Виртуальный каталог внутри приложения ASP.NET Core в IIS

У нас есть приложение, использующее ASP.NET Core 1.0 RC1 и размещенное на IIS. Работает нормально. Теперь у нас есть статический контент, который доступен в общей папке и должен быть доступен из приложения.

До ASP.NET 5 мы добавляли виртуальный каталог в IIS и могли легко получать доступ к общему контенту. С нашим размещенным приложением ASP.NET 5 это, к сожалению, не работает. Мы просто получаем 404 назад при попытке доступа к статическому контенту.

Наше приложение использует app.UseIISPlatformHandler() а также app.UseStaticFiles(), но это не работает. Мы обнаружили, что мы могли бы использовать app.UseFileServer() с обычаем FileServerOptions чтобы получить желаемое поведение, но нам любопытно, возможно ли это и с обычным "старым" способом добавления виртуального каталога в IIS.

6 ответов

Я нашел блог, который, я думаю, был написан ОП.

В результате мы вовсе не используем виртуальный каталог в IIS, а сопоставляем ваш путь в Startup.cs с каталогом физического сервера. Я надеюсь, что OP не возражает, что я вставил ниже блог, но он помог мне, когда я впервые столкнулся с этой проблемой сегодня.

Источник: https://www.jauernig-it.de/asp-net-coreiis-serving-content-from-a-file-share/

Существуют ситуации, когда вы хотите предоставить статическое содержимое вашему приложению, которое не является его частью, например, потому что оно существует в общем файловом ресурсе. Контент веб-сайта, который управляется бизнес-подразделением, может быть таким примером использования. В ASP.NET до Core это не было проблемой в IIS: просто создайте виртуальный каталог на своем веб-сайте IIS и укажите его для общего файлового ресурса.

К сожалению, в ASP.NET Core этот подход больше не работает. Если вы добавляете виртуальный каталог в приложение ASP.NET Core в IIS, он не распознается и возвращается 404. Это из-за DNX/Kestrel, который работает под IIS (используя модуль HttpPlatformHandler) и к которому IIS только передает запросы. Kestrel ничего не знает о виртуальных каталогах из IIS. А поскольку основные приложения ASP.NET не зависят от IIS и могут также запускаться без него (например, запуск автономного Kestrel), это следует рассматривать как хорошую вещь.

Но теперь нам нужно другое решение для нашей проблемы… к счастью, ASP.NET Core предоставляет нам программный интерфейс для обслуживания файлов из любого места. Просто добавьте следующий код в ваш метод Startup.cs Configure():

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

По сути, это добавление файлового сервера к физическому пути к серверу, который затем доступен по определенному пути запроса, в данном случае с отключенным просмотром каталога. Вы также можете обслуживать по пути относительно вашего приложения, используя новый PhysicalFileProvider(env.WebRootPath + "\path") (данный env имеет тип IHostingEnvironment в качестве параметра Configure()). Вуаля, вот и все. Нет необходимости добавлять "виртуальный каталог" в IIS, этот материал устарел и ушел в прошлое. Для меня это хорошая вещь, потому что мы становимся более независимыми от всего IIS...

Я столкнулся с этой проблемой сегодня, и, наконец, удалось ее исправить. Хитрость (для меня, вероятно, не для всех) заключается в 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>

Не напрямую.

Видите ли, проблема в том, что когда у вас есть приложение.NET-Core, оно запускается в Kestrell, а не в IIS.

Теперь, чтобы разместить ваше приложение.NET-Core в IIS, AspNetCoreModule запускает ваше приложение.NET-Core с Kestrell на порту X 127.0.0.1, а затем перенаправляет трафик с вашего виртуального каталога iis-domain+ на порт X на 127.0.0.1 (он может использовать что-то еще, кроме TCP).

Проблема 1 в том, что Kestrell имеет довольно ограниченную функциональность, то есть не имеет виртуальных каталогов.
Проблема 2 в том, что IIS, в отличие от nginx, на самом деле не выполняет обратное проксирование должным образом, или мы должны сказать "полностью".

IIS может пересылать domainxy:80 на 127.0.0.1:random в порядке. Но что он не делает должным образом, так это переписывает domainxy:80/foo в 127.0.0.1:random (images, header, json-ajax-results, urls, return-url, cookies и т. Д. И наоборот). Вместо этого он переписывает домен: 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, вы можете настроить каркас приложения для имитации этой папки, как в 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)

Вам нужно будет где-то настроить имя виртуального каталога. Осторожно, когда у вас есть / возвращаются URL в JavaScript/ajax-запросах, они не будут автоматически отображаться. Вы должны сделать это сами, но так было и со старым ASP.NET.

Действительно, как RoR:

карта Rails.application.config.relative_url_root || "/" делать
запустить RedmineApp::Application
конец

Что касается виртуального каталога в приложении: нет, это не так просто.
IIS - это полноценный веб-сервер, который будет обслуживать содержимое этого сопоставленного каталога так, как он был там (если он может читать содержимое).

Если вы перенаправите весь родительский каталог в Kestrell, то IIS не сможет обслуживать подкаталог, и ваше приложение должно будет это сделать. Это означает, что вам нужно настроить статический файловый сервер для этого конкретного каталога и сообщить ему, где находятся файлы, как вы это сделали.

То, что вы могли бы сделать, это сказать IIS не использовать прокси для этого конкретного виртуального подкаталога (точно так же, как вы можете определить местоположение статического файла в nginx - за исключением того, что IIS, вероятно, не поддерживает эту функцию).

Однако вы можете создать символическую ссылку в каталоге вашего приложения, которая идет в сетевую папку, если Windows способна на это (mklink). Тогда.NET Core сможет обслуживать его статически. Но на самом деле, это звучит как взломать.

Если вы не можете настроить IIS, вам действительно следует использовать app.UseFileServer() и определить местоположение документа в базе данных. Таким образом, вы можете просто удалить и повторно вставить приложение позже.

Я знаю его с 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 для любой локальной или общей папки, и с этим подать файл.

Делать это таким образом не рекомендуется. Но для изучения предложите, это приемлемо.

Модуль статического файла не обеспечивает проверки авторизации. Любые файлы, обслуживаемые им, в том числе под wwwroot, являются общедоступными. Чтобы обслуживать файлы на основе авторизации: храните их вне wwwroot и любого каталога, доступного для промежуточного программного обеспечения статических файлов, и обслуживайте их с помощью действия контроллера, возвращая FileResult, где применяется авторизация.

В документации Microsoft Asp.Net мы можем найти более полную информацию, чтобы помочь с этой проблемой.

Проверьте эту ссылку: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/static-files

.Net Core имеет очень ограниченную поддержку виртуальных каталогов IIS. В качестве обходного пути вы можете использовать Microsoft.Web.Administration для получения списка виртуальных каталогов сайта («веб-сайта по умолчанию»). Замените Path на PhysicalPath , чтобы найти ресурсы.

Создайте проект библиотеки .NetStandard (>= 1.6.0) и используйте этот пример .

Мое решение использовало path="/" вместо path="*" на web.config файл

Другие вопросы по тегам