Skip to content

Commit

Permalink
Add VirtualPathProvider infrastructure (#490)
Browse files Browse the repository at this point in the history
This enables usage of these types, but does not hook it up to a ASP.NET Core related concept. For now, that is left to the user if they need the API.
  • Loading branch information
twsouthwick authored Mar 27, 2024
1 parent cc26216 commit 6af1a41
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,42 @@ public static partial class HostingEnvironment
public static string ApplicationID { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public static bool IsHosted { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public static string SiteName { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public static System.Web.Hosting.VirtualPathProvider VirtualPathProvider { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public static void RegisterVirtualPathProvider(System.Web.Hosting.VirtualPathProvider provider) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");}
}
public abstract partial class VirtualDirectory : System.Web.Hosting.VirtualFileBase
{
protected VirtualDirectory(string virtualPath) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");}
public abstract System.Collections.IEnumerable Children { get; }
public abstract System.Collections.IEnumerable Directories { get; }
public abstract System.Collections.IEnumerable Files { get; }
public override bool IsDirectory { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
}
public abstract partial class VirtualFile : System.Web.Hosting.VirtualFileBase
{
protected VirtualFile(string virtualPath) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");}
public override bool IsDirectory { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public abstract System.IO.Stream Open();
}
public abstract partial class VirtualFileBase
{
internal VirtualFileBase() { }
public abstract bool IsDirectory { get; }
public virtual string Name { get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public string VirtualPath { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
}
public abstract partial class VirtualPathProvider
{
protected VirtualPathProvider() { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");}
protected internal System.Web.Hosting.VirtualPathProvider Previous { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");} }
public virtual string CombineVirtualPaths(string basePath, string relativePath) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");}
public virtual bool DirectoryExists(string virtualDir) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");}
public virtual bool FileExists(string virtualPath) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");}
public virtual System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, System.DateTime utcStart) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");}
public virtual System.Web.Hosting.VirtualDirectory GetDirectory(string virtualDir) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");}
public virtual System.Web.Hosting.VirtualFile GetFile(string virtualPath) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");}
public virtual string GetFileHash(string virtualPath, System.Collections.IEnumerable virtualPathDependencies) { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");}
protected virtual void Initialize() { throw new System.PlatformNotSupportedException("Only supported when running on ASP.NET Core or System.Web");}
}
}
namespace System.Web.Security
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@
[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Web.Caching.CacheItemUpdateReason))]
[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Web.Configuration.HttpCapabilitiesBase))]
[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Web.Hosting.HostingEnvironment))]
[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Web.Hosting.VirtualDirectory))]
[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Web.Hosting.VirtualFile))]
[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Web.Hosting.VirtualFileBase))]
[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Web.Hosting.VirtualPathProvider))]
[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Web.Security.MachineKey))]
[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Web.SessionState.HttpSessionState))]
[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Web.SessionState.SessionStateBehavior))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,13 @@ public static class HostingEnvironment
public static bool IsHosted => HostingEnvironmentAccessor.TryGet(out var current) && current.Options.IsHosted;

public static string SiteName => HostingEnvironmentAccessor.Current.Options.SiteName;

public static VirtualPathProvider? VirtualPathProvider => HostingEnvironmentAccessor.Current.Options.VirtualPathProvider;

public static void RegisterVirtualPathProvider(VirtualPathProvider provider)
{
ArgumentNullException.ThrowIfNull(provider);

HostingEnvironmentAccessor.Current.Options.VirtualPathProvider = provider;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;

namespace System.Web.Hosting;

public abstract class VirtualDirectory : VirtualFileBase
{
protected VirtualDirectory(string virtualPath)
: base(VirtualPathUtility.AppendTrailingSlash(virtualPath))
{
}

public override bool IsDirectory => true;

/// <summary>
/// Returns an object that enumerates all the children VirtualDirectory's of this directory.
/// </summary>
public abstract IEnumerable Directories { get; }

/// <summary>
///Returns an object that enumerates all the children VirtualFile's of this directory.
/// </summary>
public abstract IEnumerable Files { get; }

/// <summary>
/// Returns an object that enumerates all the children VirtualDirectory's and VirtualFiles of this directory.
/// </summary>
public abstract IEnumerable Children { get; }
}
18 changes: 18 additions & 0 deletions src/Microsoft.AspNetCore.SystemWebAdapters/Hosting/VirtualFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;

namespace System.Web.Hosting;

public abstract class VirtualFile : VirtualFileBase
{
protected VirtualFile(string virtualPath)
: base(virtualPath)
{
}

public override bool IsDirectory => false;

public abstract Stream Open();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Web.Hosting;

public abstract class VirtualFileBase
{
private protected VirtualFileBase(string virtualPath)
{
VirtualPath = virtualPath;
}

public virtual string Name => VirtualPathUtility.GetFileName(VirtualPath);

public string VirtualPath { get; }

public abstract bool IsDirectory { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;
using System.Web.Caching;
using System.Web.Util;

namespace System.Web.Hosting;

public abstract class VirtualPathProvider
{
internal virtual void Initialize(VirtualPathProvider? previous)
{
Previous = previous;
Initialize();
}

protected virtual void Initialize()
{
}

protected internal VirtualPathProvider? Previous { get; private set; }

public virtual string? GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
=> Previous?.GetFileHash(virtualPath, virtualPathDependencies);

public virtual CacheDependency? GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
=> Previous?.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);

public virtual bool FileExists(string virtualPath) => Previous != null && Previous.FileExists(virtualPath);

public virtual bool DirectoryExists(string virtualDir) => Previous != null && Previous.DirectoryExists(virtualDir);

public virtual VirtualFile? GetFile(string virtualPath) => Previous?.GetFile(virtualPath);

internal VirtualFile? GetFileWithCheck(string virtualPath)
{
var virtualFile = GetFile(virtualPath);

if (virtualFile == null)
{
return null;
}

// Make sure the VirtualFile's path is the same as what was passed to GetFile
if (!string.Equals(virtualPath, virtualFile.VirtualPath, StringComparison.OrdinalIgnoreCase))
{
throw new HttpException($"Bad virtual path {virtualFile} in VirtuaPathBase");
}

return virtualFile;
}

public virtual VirtualDirectory? GetDirectory(string virtualDir) => Previous?.GetDirectory(virtualDir);

public virtual string CombineVirtualPaths(string basePath, string relativePath)
{
if (string.IsNullOrEmpty(basePath))
{
throw new ArgumentException($"'{nameof(basePath)}' cannot be null or empty.", nameof(basePath));
}

var baseDir = UrlPath.GetDirectory(basePath);

// By default, just combine them normally
return VirtualPathUtility.Combine(baseDir, relativePath);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
#if NETCOREAPP

using System;
using System.Web.Hosting;

namespace Microsoft.AspNetCore.SystemWebAdapters;

public class SystemWebAdaptersOptions
{
private VirtualPathProvider? _virtualPathProvider;

public string ApplicationID { get; set; } = string.Empty;

public bool IsHosted { get; set; }
Expand All @@ -18,6 +21,20 @@ public class SystemWebAdaptersOptions
public string AppDomainAppVirtualPath { get; set; } = "/";

public string AppDomainAppPath { get; set; } = AppContext.BaseDirectory;

/// <summary>
/// Gets or sets the value used by <see cref="HostingEnvironment.VirtualPathProvider"/>.
/// </summary>
public VirtualPathProvider? VirtualPathProvider
{
get => _virtualPathProvider;
set
{
value?.Initialize(_virtualPathProvider);

_virtualPathProvider = value;
}
}
}

#endif
30 changes: 30 additions & 0 deletions src/Microsoft.AspNetCore.SystemWebAdapters/Utilities/UrlPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,35 @@ private static bool HasScheme(string virtualPath)
return indexOfSlash == -1 || indexOfColon < indexOfSlash;
}

internal static string GetDirectory(string path)
{
if (string.IsNullOrEmpty(path))
{
throw new ArgumentException("Path must not be empty", nameof(path));
}

if (path[0] != '/' && path[0] != AppRelativeCharacter)
{
throw new ArgumentException($"Path {path} must be rooted");
}

// If it's just "~" or "/", return it unchanged
if (path.Length == 1)
{
return path;
}

int slashIndex = path.LastIndexOf('/');

// This could happen if the input looks like "~abc"
if (slashIndex < 0)
{
throw new ArgumentException($"Path {path} must be rooted");
}

return path[..(slashIndex + 1)];
}

private static bool IsDirectorySeparatorChar(char ch) => ch == '\\' || ch == '/';

// e.g \\server\share\foo or //server/share/foo
Expand Down Expand Up @@ -532,6 +561,7 @@ internal string MakeRelative(string fromPath, string toPath)
return relativePath + queryString + toUri.Fragment;
}

[return: NotNullIfNotNull(nameof(virtualPath))]
internal static string? GetFileName(string virtualPath)
{
if (virtualPath is not null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public static class VirtualPathUtility
/// <param name="virtualPath">The virtual path. </param>
/// <exception cref="ArgumentException">
/// <paramref name="virtualPath" /> contains one or more characters that are not valid, as defined in <see cref="IO.Path.InvalidPathChars" />. </exception>

[return: NotNullIfNotNull(nameof(virtualPath))]
public static string? GetFileName(string virtualPath) => VirtualPathUtilityImpl.GetFileName(virtualPath);

/// <summary>Returns a Boolean value indicating whether the specified virtual path is absolute; that is, it starts with a literal slash mark (/).</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ public string Combine(string basePath, string relativePath)
return UrlPath.GetExtension(virtualPath);
}

[return: NotNullIfNotNull(nameof(virtualPath))]
public static string? GetFileName(string virtualPath)
{
if (string.IsNullOrEmpty(virtualPath))
Expand Down

0 comments on commit 6af1a41

Please sign in to comment.