IIS 中 ASP.NET Core 应用程序内的虚拟目录

Posted

技术标签:

【中文标题】IIS 中 ASP.NET Core 应用程序内的虚拟目录【英文标题】:Virtual directory inside of ASP.NET Core app in IIS 【发布时间】: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 吗? 请。发布一个有效的答案。许多人需要知道这是如何工作的 【参考方案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) 上的服务器不支持虚拟目录,则会出现问题。

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

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

    正如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="*"

【讨论】:

以上是关于IIS 中 ASP.NET Core 应用程序内的虚拟目录的主要内容,如果未能解决你的问题,请参考以下文章

调试在 IIS 中运行的 ASP.NET Core 应用程序

Windows + IIS 环境部署Asp.Net Core App

ASP.NET Core部署系列一:发布到IIS上

Asp.Net Core子应用由于配置中重复添加模块会引起IIS错误500.19

IIS 10 上的 ASP.NET Core 404 错误

在 IIS 中托管 ASP Net Core 应用程序时无限页面加载