diff --git a/.gitignore b/.gitignore
index b1688a6811..5f2432313f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -170,6 +170,7 @@ build/temp/
/src/Umbraco.Web.UI.NetCore/wwwroot/Media/*
/src/Umbraco.Web.UI.NetCore/wwwroot/is-cache/*
/src/Umbraco.Tests.Integration/App_Data/*
+/src/Umbraco.Tests.Integration/TEMP/*
/src/Umbraco.Web.UI.NetCore/wwwroot/Umbraco/assets/*
/src/Umbraco.Web.UI.NetCore/wwwroot/Umbraco/js/*
/src/Umbraco.Web.UI.NetCore/wwwroot/Umbraco/lib/*
diff --git a/src/Umbraco.Configuration/Legacy/GlobalSettings.cs b/src/Umbraco.Configuration/Legacy/GlobalSettings.cs
index 78036f9e42..cb3fd9cf47 100644
--- a/src/Umbraco.Configuration/Legacy/GlobalSettings.cs
+++ b/src/Umbraco.Configuration/Legacy/GlobalSettings.cs
@@ -177,7 +177,7 @@ namespace Umbraco.Core.Configuration.Legacy
/// Value of the setting to be saved.
internal static void SaveSetting(string key, string value, IIOHelper ioHelper)
{
- var fileName = ioHelper.MapPath(string.Format("{0}/web.config", ioHelper.Root));
+ var fileName = ioHelper.MapPath("~/web.config");
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single();
diff --git a/src/Umbraco.Core/AssemblyExtensions.cs b/src/Umbraco.Core/AssemblyExtensions.cs
index 0d0115ce20..19162e5934 100644
--- a/src/Umbraco.Core/AssemblyExtensions.cs
+++ b/src/Umbraco.Core/AssemblyExtensions.cs
@@ -6,6 +6,35 @@ namespace Umbraco.Core
{
public static class AssemblyExtensions
{
+ private static string _rootDir = "";
+
+ ///
+ /// Utility method that returns the path to the root of the application, by getting the path to where the assembly where this
+ /// method is included is present, then traversing until it's past the /bin directory. Ie. this makes it work
+ /// even if the assembly is in a /bin/debug or /bin/release folder
+ ///
+ ///
+ public static string GetRootDirectorySafe(this Assembly executingAssembly)
+ {
+ if (string.IsNullOrEmpty(_rootDir) == false)
+ {
+ return _rootDir;
+ }
+
+ var codeBase = executingAssembly.CodeBase;
+ var uri = new Uri(codeBase);
+ var path = uri.LocalPath;
+ var baseDirectory = Path.GetDirectoryName(path);
+ if (string.IsNullOrEmpty(baseDirectory))
+ throw new Exception("No root directory could be resolved. Please ensure that your Umbraco solution is correctly configured.");
+
+ _rootDir = baseDirectory.Contains("bin")
+ ? baseDirectory.Substring(0, baseDirectory.LastIndexOf("bin", StringComparison.OrdinalIgnoreCase) - 1)
+ : baseDirectory;
+
+ return _rootDir;
+ }
+
///
/// Returns the file used to load the assembly
///
diff --git a/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs b/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs
index 64271ebff1..80d795bb48 100644
--- a/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs
+++ b/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
public void RemoveConnectionString()
{
var key = Constants.System.UmbracoConnectionName;
- var fileName = _ioHelper.MapPath(string.Format("{0}/web.config", _ioHelper.Root));
+ var fileName = _ioHelper.MapPath("~/web.config");
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single();
@@ -58,7 +58,7 @@ namespace Umbraco.Core.Configuration
var fileSource = "web.config";
- var fileName = _ioHelper.MapPath(_ioHelper.Root + "/" + fileSource);
+ var fileName = _ioHelper.MapPath("~/" + fileSource);
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
if (xml.Root == null) throw new Exception($"Invalid {fileSource} file (no root).");
@@ -71,7 +71,7 @@ namespace Umbraco.Core.Configuration
if (configSourceAttribute != null)
{
fileSource = configSourceAttribute.Value;
- fileName = _ioHelper.MapPath(_ioHelper.Root + "/" + fileSource);
+ fileName = _ioHelper.MapPath("~/" + fileSource);
if (!File.Exists(fileName))
throw new Exception($"Invalid configSource \"{fileSource}\" (no such file).");
diff --git a/src/Umbraco.Core/IO/IIOHelper.cs b/src/Umbraco.Core/IO/IIOHelper.cs
index 3795e1905a..b6fd100133 100644
--- a/src/Umbraco.Core/IO/IIOHelper.cs
+++ b/src/Umbraco.Core/IO/IIOHelper.cs
@@ -7,8 +7,6 @@ namespace Umbraco.Core.IO
string BackOfficePath { get; }
- bool ForceNotHosted { get; set; }
-
char DirSepChar { get; }
string FindFile(string virtualPath);
string ResolveVirtualUrl(string path);
@@ -43,24 +41,6 @@ namespace Umbraco.Core.IO
bool PathStartsWith(string path, string root, char separator);
- ///
- /// Returns the path to the root of the application, by getting the path to where the assembly where this
- /// method is included is present, then traversing until it's past the /bin directory. Ie. this makes it work
- /// even if the assembly is in a /bin/debug or /bin/release folder
- ///
- ///
- string GetRootDirectorySafe();
-
- string GetRootDirectoryBinFolder();
-
- ///
- /// Allows you to overwrite RootDirectory, which would otherwise be resolved
- /// automatically upon application start.
- ///
- /// The supplied path should be the absolute path to the root of the umbraco site.
- ///
- void SetRootDirectory(string rootPath);
-
void EnsurePathExists(string path);
///
@@ -76,6 +56,7 @@ namespace Umbraco.Core.IO
///
/// This is (should be) the same as IHostingEnvironment.ApplicationVirtualPath
///
+ ///
string Root
{
get;
diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs
index 9eddea6477..b68c58e91d 100644
--- a/src/Umbraco.Core/IO/IOHelper.cs
+++ b/src/Umbraco.Core/IO/IOHelper.cs
@@ -31,13 +31,6 @@ namespace Umbraco.Core.IO
}
}
- ///
- /// Gets or sets a value forcing Umbraco to consider it is non-hosted.
- ///
- /// This should always be false, unless unit testing.
- public bool ForceNotHosted { get; set; }
-
- private static string _rootDir = "";
// static compiled regex for faster performance
//private static readonly Regex ResolveUrlPattern = new Regex("(=[\"\']?)(\\W?\\~(?:.(?![\"\']?\\s+(?:\\S+)=|[>\"\']))+.)[\"\']?", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
@@ -113,13 +106,9 @@ namespace Umbraco.Core.IO
: _hostingEnvironment.MapPath("~/" + path.TrimStart('/'));
if (result != null) return result;
-
-
}
-
-
- var root = GetRootDirectorySafe();
+ var root = Assembly.GetExecutingAssembly().GetRootDirectorySafe();
var newPath = path.TrimStart('~', '/').Replace('/', DirSepChar);
var retval = root + DirSepChar.ToString(CultureInfo.InvariantCulture) + newPath;
@@ -199,71 +188,6 @@ namespace Umbraco.Core.IO
return path[root.Length] == separator;
}
- ///
- /// Returns the path to the root of the application, by getting the path to where the assembly where this
- /// method is included is present, then traversing until it's past the /bin directory. Ie. this makes it work
- /// even if the assembly is in a /bin/debug or /bin/release folder
- ///
- ///
- public string GetRootDirectorySafe()
- {
- if (String.IsNullOrEmpty(_rootDir) == false)
- {
- return _rootDir;
- }
-
- var codeBase = Assembly.GetExecutingAssembly().CodeBase;
- var uri = new Uri(codeBase);
- var path = uri.LocalPath;
- var baseDirectory = Path.GetDirectoryName(path);
- if (String.IsNullOrEmpty(baseDirectory))
- throw new Exception("No root directory could be resolved. Please ensure that your Umbraco solution is correctly configured.");
-
- _rootDir = baseDirectory.Contains("bin")
- ? baseDirectory.Substring(0, baseDirectory.LastIndexOf("bin", StringComparison.OrdinalIgnoreCase) - 1)
- : baseDirectory;
-
- return _rootDir;
- }
-
- public string GetRootDirectoryBinFolder()
- {
- string binFolder = String.Empty;
- if (String.IsNullOrEmpty(_rootDir))
- {
- binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory.FullName;
- return binFolder;
- }
-
- binFolder = Path.Combine(GetRootDirectorySafe(), "bin");
-
- // do this all the time (no #if DEBUG) because Umbraco release
- // can be used in tests by an app (eg Deploy) being debugged
- var debugFolder = Path.Combine(binFolder, "debug");
- if (Directory.Exists(debugFolder))
- return debugFolder;
-
- var releaseFolder = Path.Combine(binFolder, "release");
- if (Directory.Exists(releaseFolder))
- return releaseFolder;
-
- if (Directory.Exists(binFolder))
- return binFolder;
-
- return _rootDir;
- }
-
- ///
- /// Allows you to overwrite RootDirectory, which would otherwise be resolved
- /// automatically upon application start.
- ///
- /// The supplied path should be the absolute path to the root of the umbraco site.
- ///
- public void SetRootDirectory(string rootPath)
- {
- _rootDir = rootPath;
- }
-
public void EnsurePathExists(string path)
{
var absolutePath = MapPath(path);
@@ -280,7 +204,7 @@ namespace Umbraco.Core.IO
{
if (path.IsFullPath())
{
- var rootDirectory = GetRootDirectorySafe();
+ var rootDirectory = MapPath("~");
var relativePath = path.ToLowerInvariant().Replace(rootDirectory.ToLowerInvariant(), string.Empty);
path = relativePath;
}
@@ -293,6 +217,10 @@ namespace Umbraco.Core.IO
///
/// Gets the root path of the application
///
+ ///
+ /// In most cases this will be an empty string which indicates the app is not running in a virtual directory.
+ /// This is NOT a physical path.
+ ///
public string Root
{
get
@@ -301,7 +229,8 @@ namespace Umbraco.Core.IO
var appPath = _hostingEnvironment.ApplicationVirtualPath;
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
- if (appPath == null || appPath == "/") appPath = string.Empty;
+ if (appPath == null || appPath == "/")
+ appPath = string.Empty;
_root = appPath;
diff --git a/src/Umbraco.Core/IO/PhysicalFileSystem.cs b/src/Umbraco.Core/IO/PhysicalFileSystem.cs
index 24284fec98..52c210ad28 100644
--- a/src/Umbraco.Core/IO/PhysicalFileSystem.cs
+++ b/src/Umbraco.Core/IO/PhysicalFileSystem.cs
@@ -59,7 +59,7 @@ namespace Umbraco.Core.IO
if (Path.IsPathRooted(rootPath) == false)
{
// but the test suite App.config cannot really "root" anything so we have to do it here
- var localRoot = _ioHelper.GetRootDirectorySafe();
+ var localRoot = _ioHelper.MapPath("~");
rootPath = Path.Combine(localRoot, rootPath);
}
diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs
index a41015c4e8..2ab56308ef 100644
--- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs
+++ b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs
@@ -69,11 +69,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions
composition.RegisterUnique(factory => CreatePackageRepository(factory, "installedPackages.config"));
composition.RegisterUnique();
composition.RegisterUnique();
- composition.RegisterUnique(factory => //factory required because we need to pass in a string path
- new PackageInstallation(
- factory.GetInstance(), factory.GetInstance(),
- factory.GetInstance(), factory.GetInstance(),
- new DirectoryInfo( factory.GetInstance().GetRootDirectorySafe())));
+ composition.RegisterUnique();
return composition;
}
diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs
index 8d5922028c..291a4a329d 100644
--- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs
+++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs
@@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
+using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Migrations.Upgrade;
@@ -24,8 +25,8 @@ namespace Umbraco.Core.Migrations.Install
private readonly IRuntimeState _runtime;
private readonly IMigrationBuilder _migrationBuilder;
private readonly IKeyValueService _keyValueService;
+ private readonly IHostingEnvironment _hostingEnvironment;
private readonly ILogger _logger;
- private readonly IIOHelper _ioHelper;
private readonly IUmbracoVersion _umbracoVersion;
private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator;
private readonly IConfigManipulator _configManipulator;
@@ -43,7 +44,7 @@ namespace Umbraco.Core.Migrations.Install
ILogger logger,
IMigrationBuilder migrationBuilder,
IKeyValueService keyValueService,
- IIOHelper ioHelper,
+ IHostingEnvironment hostingEnvironment,
IUmbracoVersion umbracoVersion,
IDbProviderFactoryCreator dbProviderFactoryCreator,
IConfigManipulator configManipulator)
@@ -55,7 +56,7 @@ namespace Umbraco.Core.Migrations.Install
_logger = logger;
_migrationBuilder = migrationBuilder;
_keyValueService = keyValueService;
- _ioHelper = ioHelper;
+ _hostingEnvironment = hostingEnvironment;
_umbracoVersion = umbracoVersion;
_dbProviderFactoryCreator = dbProviderFactoryCreator;
_configManipulator = configManipulator;
@@ -141,14 +142,14 @@ namespace Umbraco.Core.Migrations.Install
///
public void ConfigureEmbeddedDatabaseConnection()
{
- ConfigureEmbeddedDatabaseConnection(_databaseFactory, _ioHelper);
+ ConfigureEmbeddedDatabaseConnection(_databaseFactory);
}
- private void ConfigureEmbeddedDatabaseConnection(IUmbracoDatabaseFactory factory, IIOHelper ioHelper)
+ private void ConfigureEmbeddedDatabaseConnection(IUmbracoDatabaseFactory factory)
{
_configManipulator.SaveConnectionString(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe);
- var path = Path.Combine(ioHelper.GetRootDirectorySafe(), "App_Data", "Umbraco.sdf");
+ var path = Path.Combine(_hostingEnvironment.ApplicationPhysicalPath, "App_Data", "Umbraco.sdf");
if (File.Exists(path) == false)
{
// this should probably be in a "using (new SqlCeEngine)" clause but not sure
diff --git a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs
index e307802606..cf31b3ea52 100644
--- a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs
+++ b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs
@@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml.Linq;
-using Umbraco.Core.IO;
-using Umbraco.Core.Models;
+using Umbraco.Core.Hosting;
using Umbraco.Core.Models.Packaging;
-using Umbraco.Core.Services;
namespace Umbraco.Core.Packaging
{
@@ -27,18 +24,17 @@ namespace Umbraco.Core.Packaging
///
///
///
- ///
- /// The root folder of the application
- ///
+ ///
public PackageInstallation(PackageDataInstallation packageDataInstallation, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, IPackageActionRunner packageActionRunner,
- DirectoryInfo applicationRootFolder)
+ IHostingEnvironment hostingEnvironment)
{
+
_packageExtraction = new PackageExtraction();
_packageFileInstallation = packageFileInstallation ?? throw new ArgumentNullException(nameof(packageFileInstallation));
_packageDataInstallation = packageDataInstallation ?? throw new ArgumentNullException(nameof(packageDataInstallation));
_parser = parser ?? throw new ArgumentNullException(nameof(parser));
_packageActionRunner = packageActionRunner ?? throw new ArgumentNullException(nameof(packageActionRunner));
- _applicationRootFolder = applicationRootFolder ?? throw new ArgumentNullException(nameof(applicationRootFolder));
+ _applicationRootFolder = new DirectoryInfo(hostingEnvironment.ApplicationPhysicalPath);
}
public CompiledPackage ReadPackage(FileInfo packageFile)
diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
index 139e9e9b67..5d2a4b4c64 100644
--- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
+++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
@@ -269,7 +269,7 @@ namespace Umbraco.Core.Runtime
{
var path = GetApplicationRootPath();
if (string.IsNullOrWhiteSpace(path) == false)
- IOHelper.SetRootDirectory(path);
+ IOHelper.Root = path;
}
private bool AcquireMainDom(IMainDom mainDom, IApplicationShutdownRegistry applicationShutdownRegistry)
@@ -363,8 +363,14 @@ namespace Umbraco.Core.Runtime
new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache())));
}
- // by default, returns null, meaning that Umbraco should auto-detect the application root path.
- // override and return the absolute path to the Umbraco site/solution, if needed
+ ///
+ /// Returns the application path of the site/solution
+ ///
+ ///
+ ///
+ /// By default is null which means it's not running in any virtual folder. If the site is running in a virtual folder, this
+ /// can be overridden and the virtual path returned (i.e. /mysite/)
+ ///
protected virtual string GetApplicationRootPath()
=> null;
diff --git a/src/Umbraco.Tests.Common/TestHelperBase.cs b/src/Umbraco.Tests.Common/TestHelperBase.cs
index 67108833c3..b14bd5fd5d 100644
--- a/src/Umbraco.Tests.Common/TestHelperBase.cs
+++ b/src/Umbraco.Tests.Common/TestHelperBase.cs
@@ -30,6 +30,7 @@ namespace Umbraco.Tests.Common
private readonly ITypeFinder _typeFinder;
private UriUtility _uriUtility;
private IIOHelper _ioHelper;
+ private string _workingDir;
protected TestHelperBase(Assembly entryAssembly)
{
@@ -61,17 +62,20 @@ namespace Umbraco.Tests.Common
public IConfigsFactory GetConfigsFactory() => new ConfigsFactory();
///
- /// Gets the current assembly directory.
+ /// Gets the working directory of the test project.
///
- /// The assembly directory.
- public string CurrentAssemblyDirectory
+ public virtual string WorkingDirectory
{
get
{
- var codeBase = typeof(TestHelperBase).Assembly.CodeBase;
- var uri = new Uri(codeBase);
- var path = uri.LocalPath;
- return Path.GetDirectoryName(path);
+ if (_workingDir != null) return _workingDir;
+
+ var dir = Path.Combine(Assembly.GetExecutingAssembly().GetRootDirectorySafe(), "TEMP");
+
+ if (!Directory.Exists(dir))
+ Directory.CreateDirectory(dir);
+ _workingDir = dir;
+ return _workingDir;
}
}
@@ -108,16 +112,21 @@ namespace Umbraco.Tests.Common
public IWebRoutingSettings WebRoutingSettings => SettingsForTests.GenerateMockWebRoutingSettings();
///
- /// Maps the given making it rooted on . must start with ~/
+ /// Some test files are copied to the /bin (/bin/debug) on build, this is a utility to return their physical path based on a virtual path name
///
- /// The relative path.
+ ///
///
- public string MapPathForTest(string relativePath)
+ public string MapPathForTestFiles(string relativePath)
{
if (!relativePath.StartsWith("~/"))
- throw new ArgumentException("relativePath must start with '~/'", "relativePath");
+ throw new ArgumentException("relativePath must start with '~/'", nameof(relativePath));
- return relativePath.Replace("~/", CurrentAssemblyDirectory + "/");
+ var codeBase = typeof(TestHelperBase).Assembly.CodeBase;
+ var uri = new Uri(codeBase);
+ var path = uri.LocalPath;
+ var bin = Path.GetDirectoryName(path);
+
+ return relativePath.Replace("~/", bin + "/");
}
public IUmbracoVersion GetUmbracoVersion() => new UmbracoVersion(GetConfigs().Global());
diff --git a/src/Umbraco.Tests.Integration/Extensions/ApplicationBuilderExtensions.cs b/src/Umbraco.Tests.Integration/Extensions/ApplicationBuilderExtensions.cs
index a162845200..d07f4f6ee3 100644
--- a/src/Umbraco.Tests.Integration/Extensions/ApplicationBuilderExtensions.cs
+++ b/src/Umbraco.Tests.Integration/Extensions/ApplicationBuilderExtensions.cs
@@ -5,6 +5,7 @@ using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
using NUnit.Framework;
using Umbraco.Configuration.Models;
using Umbraco.Core;
@@ -22,13 +23,16 @@ namespace Umbraco.Tests.Integration.Extensions
/// Creates a LocalDb instance to use for the test
///
///
- ///
+ ///
///
///
public static IApplicationBuilder UseTestLocalDb(this IApplicationBuilder app,
- string dbFilePath,
+ IHostEnvironment hostEnvironment,
UmbracoIntegrationTest integrationTest)
{
+
+ var dbFilePath = Path.Combine(hostEnvironment.ContentRootPath, "LocalDb");
+
// get the currently set db options
var testOptions = TestOptionAttributeBase.GetTestOptions();
diff --git a/src/Umbraco.Tests.Integration/Extensions/ServiceCollectionExtensions.cs b/src/Umbraco.Tests.Integration/Extensions/ServiceCollectionExtensions.cs
index 9dde20036b..dc58d3e9e6 100644
--- a/src/Umbraco.Tests.Integration/Extensions/ServiceCollectionExtensions.cs
+++ b/src/Umbraco.Tests.Integration/Extensions/ServiceCollectionExtensions.cs
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
using Umbraco.Tests.Integration.Implementations;
namespace Umbraco.Tests.Integration.Extensions
@@ -18,6 +19,8 @@ namespace Umbraco.Tests.Integration.Extensions
services.AddSingleton(x => testHelper.GetHttpContextAccessor());
// the generic host does add IHostEnvironment but not this one because we are not actually in a web context
services.AddSingleton(x => webHostEnvironment);
+ // replace the IHostEnvironment that generic host created too
+ services.AddSingleton(x => webHostEnvironment);
}
}
}
diff --git a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs
index f10586b94b..e756ee5062 100644
--- a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs
+++ b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs
@@ -1,9 +1,11 @@
+using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using Moq;
using System.Data.Common;
+using System.IO;
using System.Net;
using Umbraco.Core;
using Umbraco.Core.Cache;
@@ -24,11 +26,12 @@ namespace Umbraco.Tests.Integration.Implementations
public class TestHelper : TestHelperBase
{
private IBackOfficeInfo _backOfficeInfo;
- private readonly IHostingEnvironment _hostingEnvironment;
+ private IHostingEnvironment _hostingEnvironment;
private readonly IApplicationShutdownRegistry _hostingLifetime;
private readonly IIpResolver _ipResolver;
private readonly IWebHostEnvironment _hostEnvironment;
private readonly IHttpContextAccessor _httpContextAccessor;
+ private string _tempWorkingDir;
public TestHelper() : base(typeof(TestHelper).Assembly)
{
@@ -37,21 +40,44 @@ namespace Umbraco.Tests.Integration.Implementations
_httpContextAccessor = Mock.Of(x => x.HttpContext == httpContext);
_ipResolver = new AspNetIpResolver(_httpContextAccessor);
- _hostEnvironment = Mock.Of(x =>
- x.ApplicationName == "UmbracoIntegrationTests"
- && x.ContentRootPath == CurrentAssemblyDirectory
- && x.WebRootPath == CurrentAssemblyDirectory); // same folder for now?
-
- _hostingEnvironment = new TestHostingEnvironment(
- SettingsForTests.GetDefaultHostingSettings(),
- _hostEnvironment,
- _httpContextAccessor);
+ var hostEnvironment = new Mock();
+ hostEnvironment.Setup(x => x.ApplicationName).Returns("UmbracoIntegrationTests");
+ hostEnvironment.Setup(x => x.ContentRootPath).Returns(() => WorkingDirectory);
+ hostEnvironment.Setup(x => x.WebRootPath).Returns(() => WorkingDirectory);
+ _hostEnvironment = hostEnvironment.Object;
_hostingLifetime = new AspNetCoreApplicationShutdownRegistry(Mock.Of());
Logger = new ProfilingLogger(new ConsoleLogger(new MessageTemplates()), Profiler);
}
+
+ public override string WorkingDirectory
+ {
+ get
+ {
+ // For Azure Devops we can only store a database in certain locations so we will need to detect if we are running
+ // on a build server and if so we'll use the %temp% path.
+
+ if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("System_DefaultWorkingDirectory")))
+ {
+ // we are using Azure Devops!
+
+ if (_tempWorkingDir != null) return _tempWorkingDir;
+
+ var temp = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoTemp");
+ Directory.CreateDirectory(temp);
+ _tempWorkingDir = temp;
+ return _tempWorkingDir;
+
+ }
+ else
+ {
+ return base.WorkingDirectory;
+ }
+ }
+ }
+
public IUmbracoBootPermissionChecker UmbracoBootPermissionChecker { get; } = new TestUmbracoBootPermissionChecker();
public AppCaches AppCaches { get; } = new AppCaches(NoAppCache.Instance, NoAppCache.Instance, new IsolatedCaches(type => NoAppCache.Instance));
@@ -77,7 +103,12 @@ namespace Umbraco.Tests.Integration.Implementations
return _backOfficeInfo;
}
- public override IHostingEnvironment GetHostingEnvironment() => _hostingEnvironment;
+ public override IHostingEnvironment GetHostingEnvironment()
+ => _hostingEnvironment ??= new TestHostingEnvironment(
+ SettingsForTests.GetDefaultHostingSettings(),
+ _hostEnvironment,
+ _httpContextAccessor);
+
public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => _hostingLifetime;
public override IIpResolver GetIpResolver() => _ipResolver;
diff --git a/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs b/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs
index 652aad8928..4a54dd2823 100644
--- a/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs
+++ b/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs
@@ -8,7 +8,8 @@ namespace Umbraco.Tests.Integration.Implementations
public class TestHostingEnvironment : AspNetCoreHostingEnvironment, Umbraco.Core.Hosting.IHostingEnvironment
{
- public TestHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor) : base(hostingSettings, webHostEnvironment, httpContextAccessor)
+ public TestHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor)
+ : base(hostingSettings, webHostEnvironment, httpContextAccessor)
{
}
diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs
index d822d687d9..b1f5805ab6 100644
--- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs
+++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs
@@ -126,7 +126,7 @@ namespace Umbraco.Tests.Integration.Testing
Services = app.ApplicationServices;
// This will create a db, install the schema and ensure the app is configured to run
- app.UseTestLocalDb(Path.Combine(testHelper.CurrentAssemblyDirectory, "LocalDb"), this);
+ app.UseTestLocalDb(Services.GetRequiredService(), this);
app.UseUmbracoCore();
}
diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/UmbracoSettingsTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/UmbracoSettingsTests.cs
index 7a82f3c070..0829de6668 100644
--- a/src/Umbraco.Tests/Configurations/UmbracoSettings/UmbracoSettingsTests.cs
+++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/UmbracoSettingsTests.cs
@@ -15,7 +15,7 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
[SetUp]
public void Init()
{
- var config = new FileInfo(TestHelper.MapPathForTest("~/Configurations/UmbracoSettings/web.config"));
+ var config = new FileInfo(TestHelper.MapPathForTestFiles("~/Configurations/UmbracoSettings/web.config"));
var fileMap = new ExeConfigurationFileMap() { ExeConfigFilename = config.FullName };
var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
diff --git a/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs b/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs
index 9bbda6dbbc..83620d35f5 100644
--- a/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs
+++ b/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs
@@ -10,14 +10,14 @@ using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Packaging
{
[TestFixture]
- class PackageExtractionTests
+ public class PackageExtractionTests
{
private const string PackageFileName = "Document_Type_Picker_1.1.umb";
private static FileInfo GetTestPackagePath(string packageName)
{
const string testPackagesDirName = "Packaging\\Packages";
- string path = Path.Combine(TestHelper.IOHelper.GetRootDirectorySafe(), testPackagesDirName, packageName);
+ string path = Path.Combine(TestHelper.IOHelper.MapPath("~"), testPackagesDirName, packageName);
return new FileInfo(path);
}
diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs
index 1630a1e969..90db389002 100644
--- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs
+++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs
@@ -7,6 +7,7 @@ using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
+using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Packaging;
@@ -25,12 +26,15 @@ namespace Umbraco.Tests.Packaging
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
public class PackageInstallationTest : TestWithDatabaseBase
{
- private Guid _testBaseFolder;
+ private DirectoryInfo _testBaseFolder;
public override void SetUp()
{
base.SetUp();
- _testBaseFolder = Guid.NewGuid();
+ var path = Path.Combine(TestHelper.WorkingDirectory, Guid.NewGuid().ToString());
+ if (!Directory.Exists(path))
+ Directory.CreateDirectory(path);
+ _testBaseFolder = new DirectoryInfo(path);
}
public override void TearDown()
@@ -38,9 +42,8 @@ namespace Umbraco.Tests.Packaging
base.TearDown();
//clear out files/folders
- var path = IOHelper.MapPath("~/" + _testBaseFolder);
- if (Directory.Exists(path))
- Directory.Delete(path, true);
+ if (_testBaseFolder.Exists)
+ _testBaseFolder.Delete(true);
}
private CompiledPackageXmlParser Parser => new CompiledPackageXmlParser(new ConflictingPackageData(ServiceContext.MacroService, ServiceContext.FileService),Factory.GetInstance());
@@ -60,7 +63,8 @@ namespace Umbraco.Tests.Packaging
PackageDataInstallation,
new PackageFileInstallation(Parser, IOHelper, ProfilingLogger),
Parser, Mock.Of(),
- applicationRootFolder: new DirectoryInfo(IOHelper.MapPath("~/" + _testBaseFolder))); //we don't want to extract package files to the real root, so extract to a test folder
+ //we don't want to extract package files to the real root, so extract to a test folder
+ Mock.Of(x => x.ApplicationPhysicalPath == _testBaseFolder.FullName));
private const string DocumentTypePickerPackage = "Document_Type_Picker_1.1.umb";
private const string HelloPackage = "Hello_1.0.0.zip";
@@ -118,10 +122,8 @@ namespace Umbraco.Tests.Packaging
public void Can_Read_Compiled_Package_Warnings()
{
//copy a file to the same path that the package will install so we can detect file conflicts
- var path = IOHelper.MapPath("~/" + _testBaseFolder);
- Console.WriteLine(path);
-
- var filePath = Path.Combine(path, "bin", "Auros.DocumentTypePicker.dll");
+
+ var filePath = Path.Combine(_testBaseFolder.FullName, "bin", "Auros.DocumentTypePicker.dll");
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
File.WriteAllText(filePath, "test");
@@ -155,7 +157,7 @@ namespace Umbraco.Tests.Packaging
Assert.AreEqual(1, result.Count);
Assert.AreEqual("bin\\Auros.DocumentTypePicker.dll", result[0]);
- Assert.IsTrue(File.Exists(Path.Combine(IOHelper.MapPath("~/" + _testBaseFolder), result[0])));
+ Assert.IsTrue(File.Exists(Path.Combine(_testBaseFolder.FullName, result[0])));
//make sure the def is updated too
Assert.AreEqual(result.Count, def.Files.Count);
diff --git a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs
index d964ab972b..885877d312 100644
--- a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs
+++ b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs
@@ -51,7 +51,7 @@ namespace Umbraco.Tests.Persistence
[Test]
public void CreateDatabase() // FIXME: move to DatabaseBuilderTest!
{
- var path = TestHelper.CurrentAssemblyDirectory;
+ var path = TestHelper.WorkingDirectory;
AppDomain.CurrentDomain.SetData("DataDirectory", path);
// delete database file
diff --git a/src/Umbraco.Tests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests/TestHelpers/TestHelper.cs
index 11393e3e6b..aab0903f1d 100644
--- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs
+++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs
@@ -82,10 +82,10 @@ namespace Umbraco.Tests.TestHelpers
public static IConfigsFactory GetConfigsFactory() => _testHelperInternal.GetConfigsFactory();
///
- /// Gets the current assembly directory.
+ /// Gets the working directory of the test project.
///
/// The assembly directory.
- public static string CurrentAssemblyDirectory => _testHelperInternal.CurrentAssemblyDirectory;
+ public static string WorkingDirectory => _testHelperInternal.WorkingDirectory;
public static IShortStringHelper ShortStringHelper => _testHelperInternal.ShortStringHelper;
public static IJsonSerializer JsonSerializer => _testHelperInternal.JsonSerializer;
@@ -102,12 +102,13 @@ namespace Umbraco.Tests.TestHelpers
public static IWebRoutingSettings WebRoutingSettings => _testHelperInternal.WebRoutingSettings;
+
///
- /// Maps the given making it rooted on . must start with ~/
+ /// Some test files are copied to the /bin (/bin/debug) on build, this is a utility to return their physical path based on a virtual path name
///
- /// The relative path.
+ ///
///
- public static string MapPathForTest(string relativePath) => _testHelperInternal.MapPathForTest(relativePath);
+ public static string MapPathForTestFiles(string relativePath) => _testHelperInternal.MapPathForTestFiles(relativePath);
public static void InitializeContentDirectories()
{
@@ -147,7 +148,7 @@ namespace Umbraco.Tests.TestHelpers
public static void CleanUmbracoSettingsConfig()
{
- var currDir = new DirectoryInfo(CurrentAssemblyDirectory);
+ var currDir = new DirectoryInfo(WorkingDirectory);
var umbracoSettingsFile = Path.Combine(currDir.Parent.Parent.FullName, "config", "umbracoSettings.config");
if (File.Exists(umbracoSettingsFile))
diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs
index 94fac6c158..e982b5c0d1 100644
--- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs
+++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs
@@ -9,6 +9,7 @@ using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Events;
+using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Packaging;
@@ -74,23 +75,21 @@ namespace Umbraco.Tests.TestHelpers
///
/// Gets a ServiceContext.
///
+ ///
///
/// A cache.
/// A logger.
- /// An Umbraco Version.
/// An io helper.
///
- ///
+ ///
/// An event messages factory.
/// Some url segment providers.
- ///
+ /// An Umbraco Version.
/// A container.
- ///
/// A ServiceContext.
/// Should be used sparingly for integration tests only - for unit tests
/// just mock the services to be passed to the ctor of the ServiceContext.
- public ServiceContext GetServiceContext(
- IScopeProvider scopeProvider, IScopeAccessor scopeAccessor,
+ public ServiceContext GetServiceContext(IScopeProvider scopeProvider, IScopeAccessor scopeAccessor,
AppCaches cache,
ILogger logger,
IIOHelper ioHelper,
@@ -98,7 +97,6 @@ namespace Umbraco.Tests.TestHelpers
IContentSettings contentSettings,
IEventMessagesFactory eventMessagesFactory,
UrlSegmentProviderCollection urlSegmentProviders,
- TypeLoader typeLoader,
IUmbracoVersion umbracoVersion,
IFactory factory = null)
{
@@ -187,7 +185,8 @@ namespace Umbraco.Tests.TestHelpers
new PackageDataInstallation(logger, fileService.Value, macroService.Value, localizationService.Value, dataTypeService.Value, entityService.Value, contentTypeService.Value, contentService.Value, propertyEditorCollection, scopeProvider, shortStringHelper, GetGlobalSettings(), localizedTextService.Value),
new PackageFileInstallation(compiledPackageXmlParser, ioHelper, new ProfilingLogger(logger, new TestProfiler())),
compiledPackageXmlParser, Mock.Of(),
- new DirectoryInfo(ioHelper.GetRootDirectorySafe())), ioHelper);
+ Mock.Of(x => x.ApplicationPhysicalPath == ioHelper.MapPath("~"))),
+ ioHelper);
});
var relationService = GetLazyService(factory, c => new RelationService(scopeProvider, logger, eventMessagesFactory, entityService.Value, GetRepo(c), GetRepo(c)));
var tagService = GetLazyService(factory, c => new TagService(scopeProvider, logger, eventMessagesFactory, GetRepo(c)));
diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs
index b4db4f551c..159baa5c79 100644
--- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs
+++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs
@@ -62,10 +62,11 @@ namespace Umbraco.Tests.TestHelpers
public override void SetUp()
{
- base.SetUp();
-
- var path = TestHelper.CurrentAssemblyDirectory;
+ // Ensure the data directory is set before continuing
+ var path = TestHelper.WorkingDirectory;
AppDomain.CurrentDomain.SetData("DataDirectory", path);
+
+ base.SetUp();
}
protected override void Compose()
@@ -167,7 +168,7 @@ namespace Umbraco.Tests.TestHelpers
if (Options.Database == UmbracoTestOptions.Database.None)
return;
- var path = TestHelper.CurrentAssemblyDirectory;
+ var path = TestHelper.WorkingDirectory;
//Get the connectionstring settings from config
var settings = ConfigurationManager.ConnectionStrings[Constants.System.UmbracoConnectionName];
@@ -337,7 +338,7 @@ namespace Umbraco.Tests.TestHelpers
private void RemoveDatabaseFile(Action onFail = null)
{
- var path = TestHelper.CurrentAssemblyDirectory;
+ var path = TestHelper.WorkingDirectory;
try
{
var filePath = string.Concat(path, "\\UmbracoNPocoTests.sdf");
diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
index f0c17adff1..880ae62e4a 100644
--- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
+++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
@@ -267,7 +267,7 @@ namespace Umbraco.Tests.Testing
profiler = Mock.Of();
break;
case UmbracoTestOptions.Logger.Serilog:
- logger = new SerilogLogger(TestHelper.CoreDebugSettings, IOHelper, TestHelper.Marchal, new FileInfo(TestHelper.MapPathForTest("~/unit-test.config")));
+ logger = new SerilogLogger(TestHelper.CoreDebugSettings, IOHelper, TestHelper.Marchal, new FileInfo(TestHelper.MapPathForTestFiles("~/unit-test.config")));
profiler = new LogProfiler(logger);
break;
case UmbracoTestOptions.Logger.Console:
diff --git a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs
index 91cb843eb1..a6c544062e 100644
--- a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs
+++ b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs
@@ -17,7 +17,8 @@ namespace Umbraco.Tests.UmbracoExamine
[OneTimeSetUp]
public void InitializeFixture()
{
- var logger = new SerilogLogger(TestHelper.CoreDebugSettings, IOHelper, TestHelper.Marchal, new FileInfo(TestHelper.MapPathForTest("~/unit-test.config")));
+
+ var logger = new SerilogLogger(TestHelper.CoreDebugSettings, IOHelper, TestHelper.Marchal, new FileInfo(TestHelper.MapPathForTestFiles("~/unit-test.config")));
_profilingLogger = new ProfilingLogger(logger, new LogProfiler(logger));
}
diff --git a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs
index 0e757bbc6d..1499c5274e 100644
--- a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs
+++ b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs
@@ -77,7 +77,7 @@ namespace Umbraco.Tests.Web.Controllers
var baseDir = IOHelper.MapPath("").TrimEnd(IOHelper.DirSepChar);
HttpContext.Current = new HttpContext(new SimpleWorkerRequest("/", baseDir, "", "", new StringWriter()));
}
- IOHelper.ForceNotHosted = true;
+
var usersController = new AuthenticationController(
new TestUserPasswordConfig(),
Factory.GetInstance(),
diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs
index 39b6d65848..42c6323d0e 100644
--- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs
+++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs
@@ -21,8 +21,8 @@ namespace Umbraco.Web.Common.AspNetCore
public AspNetCoreHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor)
{
_hostingSettings = hostingSettings ?? throw new ArgumentNullException(nameof(hostingSettings));
- _webHostEnvironment = webHostEnvironment;
- _httpContextAccessor = httpContextAccessor;
+ _webHostEnvironment = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment));
+ _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
SiteName = webHostEnvironment.ApplicationName;
ApplicationId = AppDomain.CurrentDomain.Id.ToString();
diff --git a/src/Umbraco.Web/AspNet/AspNetHostingEnvironment.cs b/src/Umbraco.Web/AspNet/AspNetHostingEnvironment.cs
index a61ad356d5..0ae177517a 100644
--- a/src/Umbraco.Web/AspNet/AspNetHostingEnvironment.cs
+++ b/src/Umbraco.Web/AspNet/AspNetHostingEnvironment.cs
@@ -1,4 +1,5 @@
using System;
+using System.Reflection;
using System.Web;
using System.Web.Hosting;
using Umbraco.Core;
@@ -18,7 +19,8 @@ namespace Umbraco.Web.Hosting
_hostingSettings = hostingSettings ?? throw new ArgumentNullException(nameof(hostingSettings));
SiteName = HostingEnvironment.SiteName;
ApplicationId = HostingEnvironment.ApplicationID;
- ApplicationPhysicalPath = HostingEnvironment.ApplicationPhysicalPath;
+ // when we are not hosted (i.e. unit test or otherwise) we'll need to get the root path from the executing assembly
+ ApplicationPhysicalPath = HostingEnvironment.ApplicationPhysicalPath ?? Assembly.GetExecutingAssembly().GetRootDirectorySafe();
ApplicationVirtualPath = HostingEnvironment.ApplicationVirtualPath;
IISVersion = HttpRuntime.IISVersion;
}