Introduce Umbraco.Compat7
This commit is contained in:
@@ -121,6 +121,7 @@ ECHO.
|
||||
ECHO Restoring NuGet packages
|
||||
ECHO Into %nuGetFolder%
|
||||
..\src\.nuget\NuGet.exe restore ..\src\Umbraco.Core\project.json -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
..\src\.nuget\NuGet.exe restore ..\src\Umbraco.Compat7\project.json -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
..\src\.nuget\NuGet.exe restore ..\src\umbraco.datalayer\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
..\src\.nuget\NuGet.exe restore ..\src\Umbraco.Web\project.json -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
..\src\.nuget\NuGet.exe restore ..\src\Umbraco.Web.UI\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
@@ -149,6 +150,7 @@ REN .\_BuildOutput\WebApp\Views\Web.config Web.config.transform
|
||||
ECHO.
|
||||
ECHO Packing the NuGet release files
|
||||
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.Core.nuspec -Version %VERSION% -Symbols -Verbosity quiet
|
||||
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.Compat7.nuspec -Version %VERSION% -Symbols -Verbosity quiet
|
||||
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.nuspec -Version %VERSION% -Verbosity quiet
|
||||
IF ERRORLEVEL 1 GOTO error
|
||||
|
||||
|
||||
@@ -264,8 +264,8 @@
|
||||
<Message Text="Compiling web project to build\$(BuildFolder)" Importance="high" />
|
||||
<!-- For UseWPP_CopyWebApplication=True see http://stackoverflow.com/questions/1983575/copywebapplication-with-web-config-transformations -->
|
||||
<!-- Build the Umbraco.Web.UI project -->
|
||||
<MSBuild Projects="..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj" Properties="WarningLevel=0;Configuration=$(BuildConfiguration);UseWPP_CopyWebApplication=True;PipelineDependsOnBuild=False;OutDir=$(SolutionBinFolderAbsolutePath);WebProjectOutputDir=$(WebAppFolderAbsolutePath);Verbosity=minimal" Targets="Clean;Rebuild;">
|
||||
</MSBuild>
|
||||
<MSBuild Projects="..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj" Properties="WarningLevel=0;Configuration=$(BuildConfiguration);UseWPP_CopyWebApplication=True;PipelineDependsOnBuild=False;OutDir=$(SolutionBinFolderAbsolutePath);WebProjectOutputDir=$(WebAppFolderAbsolutePath);Verbosity=minimal" Targets="Clean;Rebuild;" />
|
||||
<MSBuild Projects="..\src\Umbraco.Compat7\Umbraco.Compat7.csproj" Properties="WarningLevel=0;Configuration=$(BuildConfiguration);UseWPP_CopyWebApplication=True;PipelineDependsOnBuild=False;OutDir=$(SolutionBinFolderAbsolutePath);Verbosity=minimal" Targets="Clean;Rebuild;" />
|
||||
|
||||
<!-- DONE -->
|
||||
<Message Text="Finished compiling projects" Importance="high" />
|
||||
|
||||
31
build/NuSpecs/UmbracoCms.Compat7.nuspec
Normal file
31
build/NuSpecs/UmbracoCms.Compat7.nuspec
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>UmbracoCms.Compat7</id>
|
||||
<version>8.0.0</version>
|
||||
<title>Umbraco Cms Compat7</title>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
|
||||
<projectUrl>http://umbraco.com/</projectUrl>
|
||||
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>Contains resources aiming at providing a better v7-to-v8 backward compatibility.</description>
|
||||
<summary>Umbraco v7 compatibility layer for v8.</summary>
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\_BuildOutput\bin\Umbraco.Compat7.dll" target="lib\Umbraco.Compat7.dll" />
|
||||
<!--
|
||||
<file src="..\_BuildOutput\bin\Umbraco.Compat7.xml" target="lib\Umbraco.Compat7.xml" />
|
||||
-->
|
||||
|
||||
<!-- Added to be able to produce a symbols package -->
|
||||
<file src="..\_BuildOutput\bin\Umbraco.Compat7.pdb" target="lib" />
|
||||
<file src="..\..\src\Umbraco.Compat7\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Compat7" />
|
||||
</files>
|
||||
</package>
|
||||
66
src/Umbraco.Compat7/Compat7Component.cs
Normal file
66
src/Umbraco.Compat7/Compat7Component.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LightInject;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Compat7
|
||||
{
|
||||
internal class Compat7Component : UmbracoComponentBase, IUmbracoUserComponent
|
||||
{
|
||||
private List<IApplicationEventHandler> _handlers;
|
||||
private UmbracoApplicationBase _app;
|
||||
|
||||
public static event EventHandler ApplicationStarting;
|
||||
public static event EventHandler ApplicationStarted;
|
||||
|
||||
public override void Compose(ServiceContainer container)
|
||||
{
|
||||
_app = container.GetInstance<UmbracoApplicationBase>();
|
||||
var logger = container.GetInstance<ILogger>();
|
||||
|
||||
var pluginManager = container.GetInstance<PluginManager>();
|
||||
var handlerTypes = pluginManager.ResolveTypes<IApplicationEventHandler>();
|
||||
_handlers = handlerTypes.Select(Activator.CreateInstance).Cast<IApplicationEventHandler>().ToList();
|
||||
|
||||
// fixme - UmbracoApplication events
|
||||
|
||||
foreach (var handler in _handlers)
|
||||
handler.OnApplicationInitialized(_app, ApplicationContext.Current);
|
||||
|
||||
foreach (var handler in _handlers)
|
||||
handler.OnApplicationStarting(_app, ApplicationContext.Current);
|
||||
|
||||
try
|
||||
{
|
||||
ApplicationStarting?.Invoke(_app, EventArgs.Empty);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error<Compat7Component>("An error occurred in an ApplicationStarting event handler", ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Initialize(ILogger logger)
|
||||
{
|
||||
// fixme - UmbracoApplication events
|
||||
|
||||
foreach (var handler in _handlers)
|
||||
handler.OnApplicationStarted(_app, ApplicationContext.Current);
|
||||
|
||||
try
|
||||
{
|
||||
ApplicationStarted?.Invoke(_app, EventArgs.Empty);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error<Compat7Component>("An error occurred in an ApplicationStarting event handler", ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/Umbraco.Compat7/Core/ApplicationContext.cs
Normal file
33
src/Umbraco.Compat7/Core/ApplicationContext.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public class ApplicationContext : IDisposable
|
||||
{
|
||||
private ApplicationContext()
|
||||
{ }
|
||||
|
||||
public static ApplicationContext Current { get; } = new ApplicationContext();
|
||||
|
||||
public CacheHelper ApplicationCache => DependencyInjection.Current.ApplicationCache;
|
||||
|
||||
public ProfilingLogger ProfilingLogger => DependencyInjection.Current.ProfilingLogger;
|
||||
|
||||
public bool IsReady { get; } = true; // because... not accessible before we are ready
|
||||
|
||||
public bool IsConfigured => DependencyInjection.Current.RuntimeState.Level == RuntimeLevel.Run;
|
||||
|
||||
public bool IsUpgrading => DependencyInjection.Current.RuntimeState.Level == RuntimeLevel.Upgrade;
|
||||
|
||||
public DatabaseContext DatabaseContext => DependencyInjection.Current.DatabaseContext;
|
||||
|
||||
public ServiceContext Services => DependencyInjection.Current.Services;
|
||||
|
||||
public void Dispose()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
63
src/Umbraco.Compat7/Core/ApplicationEventHandler.cs
Normal file
63
src/Umbraco.Compat7/Core/ApplicationEventHandler.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public abstract class ApplicationEventHandler : IApplicationEventHandler
|
||||
{
|
||||
public void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
if (ShouldExecute(applicationContext))
|
||||
{
|
||||
ApplicationInitialized(umbracoApplication, applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
if (ShouldExecute(applicationContext))
|
||||
{
|
||||
ApplicationStarting(umbracoApplication, applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
if (ShouldExecute(applicationContext))
|
||||
{
|
||||
ApplicationStarted(umbracoApplication, applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{ }
|
||||
|
||||
protected virtual void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{ }
|
||||
|
||||
protected virtual void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{ }
|
||||
|
||||
private bool ShouldExecute(ApplicationContext applicationContext)
|
||||
{
|
||||
if (applicationContext.IsConfigured && applicationContext.DatabaseContext.IsDatabaseConfigured)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (applicationContext.IsConfigured == false && ExecuteWhenApplicationNotConfigured)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (applicationContext.DatabaseContext.IsDatabaseConfigured == false && ExecuteWhenDatabaseNotConfigured)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual bool ExecuteWhenApplicationNotConfigured => false;
|
||||
|
||||
protected virtual bool ExecuteWhenDatabaseNotConfigured => false;
|
||||
}
|
||||
}
|
||||
31
src/Umbraco.Compat7/Core/IApplicationEventHandler.cs
Normal file
31
src/Umbraco.Compat7/Core/IApplicationEventHandler.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom IApplicationStartupHandler that auto subscribes to the applications events
|
||||
/// </summary>
|
||||
public interface IApplicationEventHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// ApplicationContext is created and other static objects that require initialization have been setup
|
||||
/// </summary>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext);
|
||||
|
||||
/// <summary>
|
||||
/// All resolvers have been initialized but resolution is not frozen so they can be modified in this method
|
||||
/// </summary>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext);
|
||||
|
||||
/// <summary>
|
||||
/// Bootup is completed, this allows you to perform any other bootup logic required for the application.
|
||||
/// Resolution is frozen so now they can be used to resolve instances.
|
||||
/// </summary>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext);
|
||||
}
|
||||
}
|
||||
221
src/Umbraco.Compat7/Core/Logging/LogHelper.cs
Normal file
221
src/Umbraco.Compat7/Core/Logging/LogHelper.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Umbraco.Web;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
public static class LogHelper
|
||||
{
|
||||
#region Error
|
||||
/// <summary>
|
||||
/// Adds an error log
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="exception"></param>
|
||||
public static void Error<T>(string message, Exception exception)
|
||||
{
|
||||
Current.Logger.Error(typeof(T), message, exception);
|
||||
}
|
||||
|
||||
public static void Error(Type callingType, string message, Exception exception)
|
||||
{
|
||||
Current.Logger.Error(callingType, message, exception);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Warn
|
||||
|
||||
public static void Warn(Type callingType, string message, params Func<object>[] formatItems)
|
||||
{
|
||||
Current.Logger.Warn(callingType, message, formatItems);
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void Warn(Type callingType, string message, bool showHttpTrace, params Func<object>[] formatItems)
|
||||
{
|
||||
Mandate.ParameterNotNull(callingType, "callingType");
|
||||
Mandate.ParameterNotNullOrEmpty(message, "message");
|
||||
|
||||
if (showHttpTrace && HttpContext.Current != null)
|
||||
{
|
||||
HttpContext.Current.Trace.Warn(callingType.Name, string.Format(message, formatItems.Select(x => x.Invoke()).ToArray()));
|
||||
}
|
||||
|
||||
Current.Logger.Warn(callingType, message, formatItems);
|
||||
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void WarnWithException(Type callingType, string message, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
WarnWithException(callingType, message, false, e, formatItems);
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void WarnWithException(Type callingType, string message, bool showHttpTrace, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
Mandate.ParameterNotNull(e, "e");
|
||||
Mandate.ParameterNotNull(callingType, "callingType");
|
||||
Mandate.ParameterNotNullOrEmpty(message, "message");
|
||||
|
||||
if (showHttpTrace && HttpContext.Current != null)
|
||||
{
|
||||
HttpContext.Current.Trace.Warn(
|
||||
callingType.Name,
|
||||
string.Format(message, formatItems.Select(x => x.Invoke()).ToArray()),
|
||||
e);
|
||||
}
|
||||
|
||||
Current.Logger.Warn(callingType, e, message, formatItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a warn log
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="formatItems"></param>
|
||||
public static void Warn<T>(string message, params Func<object>[] formatItems)
|
||||
{
|
||||
Warn(typeof(T), message, formatItems);
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void Warn<T>(string message, bool showHttpTrace, params Func<object>[] formatItems)
|
||||
{
|
||||
Warn(typeof(T), message, showHttpTrace, formatItems);
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void WarnWithException<T>(string message, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
WarnWithException(typeof(T), message, e, formatItems);
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void WarnWithException<T>(string message, bool showHttpTrace, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
WarnWithException(typeof(T), message, showHttpTrace, e, formatItems);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Info
|
||||
/// <summary>
|
||||
/// Traces a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="generateMessage">The delegate to generate a message.</param>
|
||||
/// <remarks></remarks>
|
||||
public static void Info<T>(Func<string> generateMessage)
|
||||
{
|
||||
Info(typeof(T), generateMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traces if tracing is enabled.
|
||||
/// </summary>
|
||||
/// <param name="callingType"></param>
|
||||
/// <param name="generateMessage"></param>
|
||||
public static void Info(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
Current.Logger.Info(callingType, generateMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traces if tracing is enabled.
|
||||
/// </summary>
|
||||
/// <param name="type">The type for the logging namespace.</param>
|
||||
/// <param name="generateMessageFormat">The message format.</param>
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
public static void Info(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
Current.Logger.Info(type, generateMessageFormat, formatItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traces a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="generateMessageFormat">The generate message format.</param>
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
/// <remarks></remarks>
|
||||
public static void Info<T>(string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
Info(typeof(T), generateMessageFormat, formatItems);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Debug
|
||||
/// <summary>
|
||||
/// Debugs a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="generateMessage">The delegate to generate a message.</param>
|
||||
/// <remarks></remarks>
|
||||
public static void Debug<T>(Func<string> generateMessage)
|
||||
{
|
||||
Debug(typeof(T), generateMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debugs if tracing is enabled.
|
||||
/// </summary>
|
||||
/// <param name="callingType"></param>
|
||||
/// <param name="generateMessage"></param>
|
||||
public static void Debug(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
Current.Logger.Debug(callingType, generateMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debugs if tracing is enabled.
|
||||
/// </summary>
|
||||
/// <param name="type">The type for the logging namespace.</param>
|
||||
/// <param name="generateMessageFormat">The message format.</param>
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
public static void Debug(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
Current.Logger.Debug(type, generateMessageFormat, formatItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debugs a message, only generating the message if debug is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="generateMessageFormat">The generate message format.</param>
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
/// <remarks></remarks>
|
||||
public static void Debug<T>(string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
Debug(typeof(T), generateMessageFormat, formatItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debugs a message and also writes to the TraceContext specified, useful for when you would like the debug
|
||||
/// output also displayed in the Http trace output.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="generateMessageFormat"></param>
|
||||
/// <param name="showHttpTrace"></param>
|
||||
/// <param name="formatItems"></param>
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void Debug<T>(string generateMessageFormat, bool showHttpTrace, params Func<object>[] formatItems)
|
||||
{
|
||||
if (showHttpTrace && HttpContext.Current != null)
|
||||
{
|
||||
HttpContext.Current.Trace.Write(
|
||||
typeof(T).Name,
|
||||
string.Format(generateMessageFormat, formatItems.Select(x => x()).ToArray()));
|
||||
}
|
||||
Debug(typeof(T), generateMessageFormat, formatItems);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using CoreCurrent = Umbraco.Core.DependencyInjection.Current;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
public class PublishedContentModelFactoryResolver
|
||||
{
|
||||
public static PublishedContentModelFactoryResolver Current { get; set; } = new PublishedContentModelFactoryResolver();
|
||||
|
||||
public void SetFactory(IPublishedContentModelFactory factory)
|
||||
{
|
||||
CoreCurrent.Container.RegisterSingleton(_ => factory);
|
||||
}
|
||||
|
||||
public IPublishedContentModelFactory Factory => CoreCurrent.PublishedContentModelFactory;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using CoreCurrent = Umbraco.Core.DependencyInjection.Current;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
public class PropertyValueConvertersResolver
|
||||
{
|
||||
public static PropertyValueConvertersResolver Current { get; set; } = new PropertyValueConvertersResolver();
|
||||
|
||||
public IEnumerable<IPropertyValueConverter> Converters => CoreCurrent.PropertyValueConverters;
|
||||
|
||||
// fixme - should implement the basic resolver add/edit/etc methods!
|
||||
}
|
||||
}
|
||||
18
src/Umbraco.Compat7/Properties/AssemblyInfo.cs
Normal file
18
src/Umbraco.Compat7/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Umbraco.Compat7")]
|
||||
[assembly: AssemblyDescription("Umbraco v7 compatibility layer for v8.")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyProduct("Umbraco CMS")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("185e098f-5706-4b97-b404-eb974f05f633")]
|
||||
91
src/Umbraco.Compat7/Umbraco.Compat7.csproj
Normal file
91
src/Umbraco.Compat7/Umbraco.Compat7.csproj
Normal file
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{185E098F-5706-4B97-B404-EB974F05F633}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Umbraco.Compat7</RootNamespace>
|
||||
<AssemblyName>Umbraco.Compat7</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;COMPAT7</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\SolutionInfo.cs">
|
||||
<Link>Properties\SolutionInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Compat7Component.cs" />
|
||||
<Compile Include="Core\ApplicationContext.cs" />
|
||||
<Compile Include="Core\ApplicationEventHandler.cs" />
|
||||
<Compile Include="Core\IApplicationEventHandler.cs" />
|
||||
<Compile Include="Core\Logging\LogHelper.cs" />
|
||||
<Compile Include="Core\Models\PublishedContent\PublishedContentModelFactoryResolver.cs" />
|
||||
<Compile Include="Core\PropertyEditors\PropertyValueConvertersResolver.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Web\Models\IRenderModel.cs" />
|
||||
<Compile Include="Web\Models\RenderModel.cs" />
|
||||
<Compile Include="Web\Models\RenderModelOfTContent.cs" />
|
||||
<Compile Include="Web\Mvc\UmbracoTemplatePage.cs" />
|
||||
<Compile Include="Web\Mvc\UmbracoTemplatePageOfTContent.cs" />
|
||||
<Compile Include="Web\PublishedCache\FacadeServiceResolver.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="project.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj">
|
||||
<Project>{31785bc3-256c-4613-b2f5-a1b0bdded8c1}</Project>
|
||||
<Name>Umbraco.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Umbraco.Web\Umbraco.Web.csproj">
|
||||
<Project>{651e1350-91b6-44b7-bd60-7207006d7003}</Project>
|
||||
<Name>Umbraco.Web</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="notes.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
-->
|
||||
<Target Name="AfterBuild" Condition="$([System.Text.RegularExpressions.Regex]::IsMatch($(DefineConstants), '^(.*;)*COMPAT7(;.*)*$'))">
|
||||
<Copy SourceFiles="$(ProjectDir)bin\$(Configuration)\Umbraco.Compat7.dll" DestinationFolder="$(ProjectDir)..\Umbraco.Web.UI\bin" OverwriteReadOnlyFiles="true" SkipUnchangedFiles="false" />
|
||||
</Target>
|
||||
</Project>
|
||||
10
src/Umbraco.Compat7/Web/Models/IRenderModel.cs
Normal file
10
src/Umbraco.Compat7/Web/Models/IRenderModel.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
public interface IRenderModel
|
||||
{
|
||||
IPublishedContent Content { get; }
|
||||
}
|
||||
}
|
||||
39
src/Umbraco.Compat7/Web/Models/RenderModel.cs
Normal file
39
src/Umbraco.Compat7/Web/Models/RenderModel.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
public class RenderModel : IRenderModel
|
||||
{
|
||||
public RenderModel(IPublishedContent content, CultureInfo culture)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException(nameof(content));
|
||||
if (culture == null) throw new ArgumentNullException(nameof(culture));
|
||||
Content = content;
|
||||
CurrentCulture = culture;
|
||||
}
|
||||
|
||||
public RenderModel(IPublishedContent content)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException(nameof(content));
|
||||
if (UmbracoContext.Current == null)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot construct a RenderModel without specifying a CultureInfo when no UmbracoContext has been initialized");
|
||||
}
|
||||
Content = content;
|
||||
CurrentCulture = UmbracoContext.Current.PublishedContentRequest.Culture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current IPublishedContent object
|
||||
/// </summary>
|
||||
public IPublishedContent Content { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Culture assigned to the page being rendered
|
||||
/// </summary>
|
||||
public CultureInfo CurrentCulture { get; private set; }
|
||||
}
|
||||
}
|
||||
24
src/Umbraco.Compat7/Web/Models/RenderModelOfTContent.cs
Normal file
24
src/Umbraco.Compat7/Web/Models/RenderModelOfTContent.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Globalization;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
public class RenderModel<TContent> : RenderModel
|
||||
where TContent : IPublishedContent
|
||||
{
|
||||
public RenderModel(TContent content, CultureInfo culture)
|
||||
: base(content, culture)
|
||||
{
|
||||
Content = content;
|
||||
}
|
||||
|
||||
public RenderModel(TContent content)
|
||||
: base(content)
|
||||
{
|
||||
Content = content;
|
||||
}
|
||||
|
||||
public new TContent Content { get; private set; }
|
||||
}
|
||||
}
|
||||
29
src/Umbraco.Compat7/Web/Mvc/UmbracoTemplatePage.cs
Normal file
29
src/Umbraco.Compat7/Web/Mvc/UmbracoTemplatePage.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Umbraco.Web.Models;
|
||||
//using Umbraco.Core.Dynamics;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Web.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// The View that front-end templates inherit from
|
||||
/// </summary>
|
||||
public abstract class UmbracoTemplatePage : UmbracoViewPage<RenderModel>
|
||||
{
|
||||
private object _currentPage;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the content as a dynamic object
|
||||
/// </summary>
|
||||
public dynamic CurrentPage
|
||||
{
|
||||
get
|
||||
{
|
||||
// it's invalid to create a DynamicPublishedContent around a null content anyway
|
||||
// fixme - should we return null or DynamicNull.Null?
|
||||
if (Model == null || Model.Content == null) return null;
|
||||
//return _currentPage ?? (_currentPage = Model.Content.AsDynamic());
|
||||
return _currentPage ?? (_currentPage = Model.Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/Umbraco.Compat7/Web/Mvc/UmbracoTemplatePageOfTContent.cs
Normal file
28
src/Umbraco.Compat7/Web/Mvc/UmbracoTemplatePageOfTContent.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Web.Models;
|
||||
//using Umbraco.Core.Dynamics;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Web.Mvc
|
||||
{
|
||||
public abstract class UmbracoTemplatePage<TContent> : UmbracoViewPage<RenderModel<TContent>>
|
||||
where TContent : IPublishedContent
|
||||
{
|
||||
private object _currentPage;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the content as a dynamic object
|
||||
/// </summary>
|
||||
public dynamic CurrentPage
|
||||
{
|
||||
get
|
||||
{
|
||||
// it's invalid to create a DynamicPublishedContent around a null content anyway
|
||||
// fixme - should we return null or DynamicNull.Null?
|
||||
if (Model == null || Model.Content == null) return null;
|
||||
//return _currentPage ?? (_currentPage = Model.Content.AsDynamic());
|
||||
return _currentPage ?? (_currentPage = Model.Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using WebCurrent = Umbraco.Web.Current;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Web.PublishedCache
|
||||
{
|
||||
public class FacadeServiceResolver
|
||||
{
|
||||
public static FacadeServiceResolver Current { get; set; } = new FacadeServiceResolver();
|
||||
|
||||
public IFacadeService Service => WebCurrent.FacadeService;
|
||||
}
|
||||
}
|
||||
11
src/Umbraco.Compat7/app.config
Normal file
11
src/Umbraco.Compat7/app.config
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="HtmlAgilityPack" publicKeyToken="bd319b19eaf3b43a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.4.9.5" newVersion="1.4.9.5" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
36
src/Umbraco.Compat7/notes.txt
Normal file
36
src/Umbraco.Compat7/notes.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
|
||||
** Umbraco.Compat7
|
||||
|
||||
The purpose of Umbraco.Compat7 is to help support v7 sites in v8, by providing
|
||||
an implementation of most of the important interfaces and services that have
|
||||
been removed in v8.
|
||||
|
||||
This includes:
|
||||
|
||||
- ApplicationContext
|
||||
compat: full
|
||||
status: done
|
||||
|
||||
- IApplicationEventHandler
|
||||
compat: UmbracoApplicationBase ApplicationStarting & ApplicationStarted events
|
||||
are gone. Use corresponding Compat7Component events instead, should be mostly
|
||||
the same.
|
||||
status: to be tested
|
||||
|
||||
- Resolvers
|
||||
status: to be implemented - all of them - bah
|
||||
|
||||
- RenderModel, UmbracoTemplatePage
|
||||
compat: will NOT support dynamics, so CurrentPage will prob not work
|
||||
status: need to test RendeModel, not sure it works at all
|
||||
|
||||
What else?
|
||||
|
||||
- IPublishedContent GetPropertyValue extension methods
|
||||
- ?
|
||||
|
||||
** Building
|
||||
|
||||
By default, Umbraco.Compat7 is built but not copied / nothing.
|
||||
Eventually it should become an extra NuGet package.
|
||||
12
src/Umbraco.Compat7/project.json
Normal file
12
src/Umbraco.Compat7/project.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"LightInject": "4.1.1"
|
||||
},
|
||||
"frameworks": {
|
||||
"net461": { }
|
||||
},
|
||||
"runtimes": {
|
||||
"win": { },
|
||||
"win-anycpu": { }
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ namespace Umbraco.Core
|
||||
/// should be possible to use this runtime in console apps.</remarks>
|
||||
public class CoreRuntime : IRuntime
|
||||
{
|
||||
private readonly UmbracoApplicationBase _app;
|
||||
private BootLoader _bootLoader;
|
||||
private RuntimeState _state;
|
||||
|
||||
@@ -38,14 +39,16 @@ namespace Umbraco.Core
|
||||
public CoreRuntime(UmbracoApplicationBase umbracoApplication)
|
||||
{
|
||||
if (umbracoApplication == null) throw new ArgumentNullException(nameof(umbracoApplication));
|
||||
_app = umbracoApplication;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void Boot(ServiceContainer container)
|
||||
{
|
||||
// some components may want to initialize with the UmbracoApplicationBase
|
||||
// well, they should not - let's not do this
|
||||
//container.RegisterInstance(_app);
|
||||
// well, they should not - we should not do this - however, Compat7 wants
|
||||
// it, so let's do it, but we should remove this eventually.
|
||||
container.RegisterInstance(_app);
|
||||
|
||||
Compose(container);
|
||||
|
||||
|
||||
@@ -44,4 +44,7 @@ using System.Security.Permissions;
|
||||
[assembly: InternalsVisibleTo("umbraco.providers")]
|
||||
|
||||
//allow this to be mocked in our unit tests
|
||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
||||
|
||||
// v8
|
||||
[assembly: InternalsVisibleTo("Umbraco.Compat7")]
|
||||
@@ -31,4 +31,7 @@ using System.Security;
|
||||
[assembly: InternalsVisibleTo("Umbraco.VisualStudio")]
|
||||
[assembly: InternalsVisibleTo("Umbraco.ModelsBuilder")]
|
||||
[assembly: InternalsVisibleTo("Umbraco.ModelsBuilder.AspNet")]
|
||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
||||
|
||||
// v8
|
||||
[assembly: InternalsVisibleTo("Umbraco.Compat7")]
|
||||
@@ -1,6 +1,6 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25123.0
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Web.UI", "Umbraco.Web.UI\Umbraco.Web.UI.csproj", "{4C4C194C-B5E4-4991-8F87-4373E24CC19F}"
|
||||
EndProject
|
||||
@@ -32,6 +32,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B5BD12C1
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuSpecs", "NuSpecs", "{227C3B55-80E5-4E7E-A802-BE16C5128B9D}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\build\NuSpecs\UmbracoCms.Compat7.nuspec = ..\build\NuSpecs\UmbracoCms.Compat7.nuspec
|
||||
..\build\NuSpecs\UmbracoCms.Core.nuspec = ..\build\NuSpecs\UmbracoCms.Core.nuspec
|
||||
..\build\NuSpecs\UmbracoCms.nuspec = ..\build\NuSpecs\UmbracoCms.nuspec
|
||||
EndProjectSection
|
||||
@@ -104,6 +105,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{5B03EF4E
|
||||
..\build\NuSpecs\build\UmbracoCms.targets = ..\build\NuSpecs\build\UmbracoCms.targets
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Compat7", "Umbraco.Compat7\Umbraco.Compat7.csproj", "{185E098F-5706-4B97-B404-EB974F05F633}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -148,6 +151,10 @@ Global
|
||||
{07FBC26B-2927-4A22-8D96-D644C667FECC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{07FBC26B-2927-4A22-8D96-D644C667FECC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{07FBC26B-2927-4A22-8D96-D644C667FECC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{185E098F-5706-4B97-B404-EB974F05F633}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{185E098F-5706-4B97-B404-EB974F05F633}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{185E098F-5706-4B97-B404-EB974F05F633}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{185E098F-5706-4B97-B404-EB974F05F633}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
Reference in New Issue
Block a user