我有指向IIS中某些文件服务器的虚拟目录。我了解到ASP.NET核心无法“看到”IIS中的虚拟目录,因为它运行在Kestral上。
我被告知解决方法是使用app.usefileserver:

app.UseFileServer(new FileServerOptions
{
    FileProvider = new PhysicalFileProvider(@"\\server\path"),
    RequestPath = new PathString("/MyPath"),
    EnableDirectoryBrowsing = true
});

我设置了它,当我在浏览器地址栏中键入/mypath时它就可以工作了。
但是,我希望在控制器中能够获得物理路径。
类似于:
//Server.Map path no longer exists in ASP.NET Core...
var filePath = Server.MapPath("/MyPath");
var fileName = "MyFile.txt";
System.IO.File.OpenRead(Path.Combine(filePath , fileName));

是否可以通过在app.usefileserver中提供设置的requestpath来获取物理路径?

最佳答案

这个问题的核心是访问控制器中正确的ifileprovider(指向目录的物理路径)。
可以通过在自定义服务中配置这些路径来实现此目的,以便可以在任何位置访问它们:
在configure()方法中设置usefileserver
在你的控制器里等
我有一些代码来演示如何进行此操作:
服务和便利方法
首先,创建一个自定义服务,它将保存可以由usefileserver()或控制器访问的文件服务器选项。我选择了它们的列表,这样您就可以添加多个路径。

public interface IFileServerProvider
{
    /// <summary>
    /// Contains a list of FileServer options, a combination of virtual + physical paths we can access at any time
    /// </summary>
    IList<FileServerOptions> FileServerOptionsCollection { get; }

    /// <summary>
    /// Gets the IFileProvider to access a physical location by using its virtual path
    /// </summary>
    IFileProvider GetProvider(string virtualPath);
}

/// <summary>
/// Implements IFileServerProvider in a very simple way, for demonstration only
/// </summary>
public class FileServerProvider : IFileServerProvider
{
    public FileServerProvider(IList<FileServerOptions> fileServerOptions)
    {
        FileServerOptionsCollection = fileServerOptions;
    }

    public IList<FileServerOptions> FileServerOptionsCollection { get; }

    public IFileProvider GetProvider(string virtualPath)
    {
        var options = FileServerOptionsCollection.FirstOrDefault(e => e.RequestPath == virtualPath);
        if (options != null)
            return options.FileProvider;

        throw new FileNotFoundException($"virtual path {virtualPath} is not registered in the fileserver provider");
    }
}

然后,为了方便起见,您还可以添加一个扩展方法,该方法将调用usefileserver中间件,其中包含上面服务中的选项:
/// <summary>
/// Wrapper for UseFileServer to easily use the FileServerOptions registered in the IFileServerProvider
/// </summary>
public static class FileServerProviderExtensions
{
    public static IApplicationBuilder UseFileServerProvider(this IApplicationBuilder application, IFileServerProvider fileServerprovider)
    {
        foreach (var option in fileServerprovider.FileServerOptionsCollection)
        {
            application.UseFileServer(option);
        }
        return application;
    }
}

启动方法
现在,您只需要用您选择的路径(1)注册ifileserverprovider并将其交给便利方法来实际使用它们(2)。
(1)首先,将具有所选路径的IFileServerProvider注册为单例服务:
public void ConfigureServices(IServiceCollection services)
{
    //Add our IFileServerProvider implementation as a singleton
    services.AddSingleton<IFileServerProvider>(new FileServerProvider(
        new List<FileServerOptions>
        {
            new FileServerOptions
            {
                FileProvider = new PhysicalFileProvider(@"D:\\somepath"),
                RequestPath = new PathString("/OtherPath"),
                EnableDirectoryBrowsing = true
            },
            new FileServerOptions
            {
                FileProvider = new PhysicalFileProvider(@"\\server\path"),
                RequestPath = new PathString("/MyPath"),
                EnableDirectoryBrowsing = true
            }
        }));

    // Add framework services.
    services.AddMvc();
}

(2)然后通过调用前面创建的扩展方法在usefileserver中实际使用它们。注意configure方法中的额外参数IFileServerProvider fileServerprovider
// Note: accessing the IFileServerProvider implemantion here by adding it
// in the arguments list!
public void Configure(IApplicationBuilder app, IFileServerProvider fileServerprovider)
{
    //call convenience method which adds our FileServerOptions from
    // the IFileServerProvider service
    app.UseFileServerProvider(fileServerprovider);

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

用法
现在,当您浏览到路径/mypath或/otherpath时,应该会得到一个与前面一样的目录列表。
但是,由于服务中的所有内容都是整洁的,因此现在更容易在控制器中以编程方式访问这些路径:
public class HomeController : Controller
{
    private IFileServerProvider _fileServerProvider;

    public HomeController(IFileServerProvider fileServerProvider)
    {
        _fileServerProvider = fileServerProvider;
    }

    public IActionResult Index()
    {
        var fileProvider = _fileServerProvider.GetProvider("/MyPath");
        var fileInfo = fileProvider.GetFileInfo("MyFile.txt");
        using (var stream = System.IO.File.OpenRead(fileInfo.PhysicalPath))
        {
            string contents = new StreamReader(stream).ReadToEnd();
        }
        return View();
    }
}

这段代码也许可以用更抽象、名称更恰当的版本编写,但它演示了解决问题的有效方法。

08-28 10:47