【问题标题】:Virtual directory inside of ASP.NET Core app in IISIIS 中 ASP.NET Core 应用程序内的虚拟目录
【发布时间】:2016-03-16 08:17:17
【问题描述】:

我们有一个使用 ASP.NET Core 1.0 RC1 并托管在 IIS 上的应用程序。它工作正常。现在我们有了静态内容,可以在文件共享中使用,并且应该可以从应用程序访问。

在 ASP.NET 5 之前,我们在 IIS 中添加了一个虚拟目录,可以轻松访问共享内容。对于我们托管的 ASP.NET 5 应用程序,不幸的是,这似乎不起作用。尝试访问静态内容时,我们只会收到 404 回复。

我们的应用程序正在使用app.UseIISPlatformHandler()app.UseStaticFiles(),但这不起作用。我们发现我们可以使用 app.UseFileServer() 和自定义 FileServerOptions 来获得所需的行为,但我们很好奇是否也可以使用在 IIS 中添加虚拟目录的正常“旧”方式。

【问题讨论】:

  • 您是否尝试在指向网络共享的 wwwroot 文件夹中创建符号链接?
  • @Matthias - 你找到方法了吗?我的情况完全一样...
  • 是:使用带有app.UseFileServer() 的文件服务器中间件。这就是使用 ASP.NET Core 的方式,因为 IIS 虚拟目录和虚拟应用程序由于 AspNetCoreModule 而无法工作。
  • 出于完全相同的原因,我也对此感兴趣。能否请您自行回答您的问题,详细说明您所做的事情以及您提供的 FileServerOptions 吗?
  • 请。发布一个有效的答案。许多人需要知道这是如何工作的

标签: iis asp.net-core virtual-directory


【解决方案1】:

我发现了一个我认为一定是 OP 写的博客。

结果是根本不使用 IIS 中的虚拟目录,而是将 Startup.cs 中的路径映射到物理服务器目录。我希望OP不介意我粘贴了下面的博客,但是当我今天第一次遇到这个问题时它对我有所帮助。

来源:https://www.jauernig-it.de/asp-net-coreiis-serving-content-from-a-file-share/

在某些情况下,当您想通过应用程序提供静态内容时,这不是应用程序的一部分,例如因为它存在于公共文件共享中。由业务部门管理的网站内容可能就是这样的用例。在 Core 之前的 ASP.NET 中,这在 IIS 中没有问题:只需在 IIS 网站中创建一个虚拟目录并将其指向文件共享。

不幸的是,对于 ASP.NET Core,这种方法不再适用。如果您在 IIS 中将虚拟目录添加到 ASP.NET Core 应用程序,则无法识别该目录并返回 404。这是因为 DNX/Kestrel 在 IIS 下运行(使用 HttpPlatformHandler 模块)并且 IIS 仅代理请求。 Kestrel 对 IIS 中的虚拟目录一无所知。而且因为 ASP.NET Core 应用程序独立于 IIS,也可以在没有 IIS 的情况下运行(例如,独立运行 Kestrel),这应该被认为是一件好事。

但是现在我们需要另一种解决方案来解决我们的问题……幸运的是,ASP.NET Core 为我们提供了一个编程接口,可以从任何地方提供文件。只需将以下代码添加到您的 Startup.cs Configure() 方法中:

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

这实质上是将文件服务器添加到物理服务器路径,然后在某个请求路径上可用,在这种情况下,目录浏览被禁用。您还可以使用 new PhysicalFileProvider(env.WebRootPath + "\path") 从相对于您的应用程序的路径提供服务(假设 env 的类型为 IHostingEnvironment 作为 Configure() 的参数)。瞧,就是这样。无需在 IIS 中添加“虚拟目录”,这些东西已被弃用,已成为过去。对我来说,这是一件好事,因为我们变得更加独立于整个 IIS……

【讨论】:

  • 这对我有用。需要使用 Microsoft.Extensions.FileProviders;
  • 辉煌。第一次工作。
  • 正是我需要的。
  • 这应该是公认的答案。简直就是完美。
  • 有没有办法先获取当前默认的 PhysicalFileProvider 或默认的 FileServerOptions,这样我就可以通过它并且只调整 RequestPath 而不会影响其他任何东西?
【解决方案2】:

我今天遇到了这个问题,终于设法解决了。诀窍(对我来说,可能不适合所有人)是确保 aspNetCore 处理程序在子应用程序中被禁用并在主(ASP.NET Core)应用程序中启用。

我的 ASP.NET Core 应用有一个基本的 Web.config

<configuration>
  <system.webServer>
    <handlers>
        <add name="aspNetCore" path="*" verb="*" type="" modules="AspNetCoreModule" scriptProcessor="" resourceType="Unspecified" requireAccess="Script" allowPathInfo="false" preCondition="" responseBufferLimit="4194304" />
    </handlers>
    <aspNetCore processPath="dotnet" arguments=".\bin\Debug\netcoreapp2.0\myapp.dll" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" />
  </system.webServer>
</configuration>

并且在 IIS 中作为子应用程序添加的应用程序具有

<configuration>
  <!-- removed -->
  <system.webServer>
      <handlers>
          <remove name="aspNetCore" />
       </handlers>
  </system.webServer>
</configuration>

【讨论】:

  • 有趣的是,可以在 web.config 中将其关闭。这就是你不在 IIS 上时在 nginx 配置文件中所做的事情。
  • 此解决方案需要更多功劳。在某种发布管理软件下的任何东西中都非常简单且容易实现。
  • 我对此表示赞同,因为它完全解决了我的问题。我在 IIS Express 的根站点上运行 dotnet core 2 Web 应用程序,需要设置一个虚拟应用程序文件夹以指向旧版 .net 4.5 应用程序。当我第一次尝试时,请求只会挂在重定向上,我不知道为什么(没有 404 它只是死了)。将上述处理程序删除添加到我的旧应用程序的 Web.config 立即解决了问题!非常感谢这行得通,否则我会陷入困境。
  • 非常感谢,我正在使用 smarterasp.net 共享主机基本计划。在 root 上部署了 asp.net core 2.0 应用程序。并在虚拟目录下部署了 MVC5 rdlc 报告应用程序,因为.net core 仍然不支持 rdlc。我只是从我的 MVC5 网络配置中删除了 aspNetCore 设置
  • 此解决方案还可以在使用 asp.net 核心时修复 Plesk Web Statistics。因为可以通过 domain.tld/plesk-stat/webstat 访问的 Plesk Web Statistics 也是一个虚拟目录,所以将此 web.config 放在 C:\Inetpub\vhosts\domain.tld\.plesk\statistics\domain.tld\跨度>
【解决方案3】:

我知道这是一个 1.8 年的问题,但如果有人需要解决同样的问题,请尝试使用这个:

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseStaticFiles(new StaticFileOptions()
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), @"wwwroot", "images")),
        RequestPath = new PathString("/MyImages")
    });
}

完全可以将 PhysicalFileProvider 的参数更改为任何本地或共享文件夹,并以此提供文件。

SECURITY 不建议这样做。但是,对于研究建议,它是可以接受的。

静态文件模块不提供 授权检查。它提供的任何文件,包括那些在 wwwroot 是公开的。提供文件基于 授权:将它们存储在 wwwroot 和任何目录之外 可访问静态文件中间件并通过 控制器操作,返回授权所在的 FileResult 已申请。

在 Microsoft 的 Asp.Net 文档中,我们可以找到更完整的信息来帮助解决此问题。

查看此链接:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/static-files

【讨论】:

    【解决方案4】:

    不直接。

    您看,问题是,当您有一个 .NET-Core 应用程序时,该应用程序在 Kestrell 中运行,而不是 IIS(对于 .NET Core

    现在,为了在 IIS 中托管您的 .NET-Core 应用程序,AspNetCoreModule 在 127.0.0.1 端口 X 上使用 Kestrell 启动您的 .NET-Core 应用程序,然后反向代理来自 iis-domain+virtual 目录的流量到 127.0.0.1 上的端口 X(它可能使用 TCP 以外的其他东西)。

    问题 1 是,Kestrell 的功能非常有限,这意味着没有虚拟目录。
    问题 2 是,与 nginx 不同,IIS 并没有真正正确地进行反向代理,或者我们应该说“完全”。

    IIS 可以将 domainxy:80 转发到 127.0.0.1:random 好吧。 但它没有正确执行的是将 domainxy:80/foo 重写为 127.0.0.1:random (图像、标题、json-ajax-results、url、return-url、cookie 等,反之亦然)。 相反,它将 domain:80/foo 重写为 127.0.0.1:random/foo,如果 127.0.0.1:random (Kestrell) 上的服务器不支持虚拟目录,则会出现问题。

    因此,如果您想在虚拟目录中运行您的应用程序,您有两个选择(都涉及修改“您的”应用程序 - 如果可以的话):

    1. 如果您的应用程序仅部署一次,请将所有内容放入目录“foo”(包括 MVC 控制器路由)。

    2. 正如https://github.com/aspnet/Hosting/issues/416#issuecomment-149046552 中的建议,您可以让应用程序框架为您模拟该文件夹,有点像在 RoR 中:

        public void Configure(IApplicationBuilder app, 
                              IHostingEnvironment env,
                              ILoggerFactory loggerFactory)
        {
            string virtual_directory = "/Virt_DIR";
            // virtual_directory = "/";
    
            if (virtual_directory.EndsWith("/"))
                virtual_directory = virtual_directory.Substring(0, virtual_directory.Length - 1);
    
            if (string.IsNullOrWhiteSpace(virtual_directory))
                Configure1(app, env, loggerFactory); // Don't map if you don't have to 
                // (wonder what the framework does or does not  do for that case)
            else 
                app.Map(virtual_directory, delegate(IApplicationBuilder mappedApp) 
                    {
                        Configure1(mappedApp, env, loggerFactory);
                    }
                );
        }
        
        // Configure is called after ConfigureServices is called.
        public void Configure1(IApplicationBuilder app, 
                               IHostingEnvironment env, 
                               ILoggerFactory loggerFactory)
        {
             //  [...]  (here comes what used to be in your old Configure method)
        }
    
    

    您必须在某处配置虚拟目录的名称。 当您在 JavaScript/ajax-requests 中有/返回 URL 时要小心,它们不会被自动映射。您必须自己执行此操作,但以前使用旧 ASP.NET 也是如此。

    真的,就像 RoR:

    映射 Rails.application.config.relative_url_root || “/”做
    运行 RedmineApp::Application
    结束

    关于应用程序中的虚拟目录: 不,这不是那么简单。
    IIS 是一个完整的网络服务器,它将提供映射目录的内容,就像它在那里一样(如果它可以读取内容)。

    如果您将整个父目录转发给 Kestrell,则 IIS 无法为子目录提供服务,而您的应用程序将不得不这样做。这意味着您必须为该特定目录设置一个静态文件服务器,并告诉它文件在哪里,就像您所做的那样。

    您可以做的是告诉 IIS 不要代理该特定虚拟子目录(就像您可以在 nginx 中定义静态文件位置一样 - 除非 IIS 可能不支持该功能)。

    但是,您可以在应用程序目录中创建指向网络文件夹的符号链接(或挂载/连接),前提是 Windows 能够这样做(mklink)。然后 .NET Core 应该能够静态地为它服务。但实际上,这听起来像是一个 hack。

    如果你不能配置 IIS,你真的应该使用 app.UseFileServer() 并定义文档在数据库中的位置。这样您就可以稍后删除并重新插入应用程序。

    【讨论】:

      【解决方案5】:

      .Net Core 对 IIS 虚拟目录的支持非常有限。 作为一种解决方法,您可以使用Microsoft.Web.Administration 来获取站点(“默认网站”)虚拟目录的列表。 将Path 替换为PhysicalPath 以定位资源

      创建一个 .NetStandard lib 项目 (>= 1.6.0),并使用 this 示例

      【讨论】:

        【解决方案6】:

        我的解决方案是在 web.config 文件上使用 path="/" 而不是 path="*"

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-23
          • 1970-01-01
          • 2010-12-28
          • 2012-03-07
          相关资源
          最近更新 更多