Использование папки wwwroot (основной стиль ASP.NET) в проекте ASP.NET 4.5

Мне очень нравится подход новых веб-приложений asp.net (asp.net 5\core 1.0), в котором папка wwwroot является корневым каталогом и обслуживаются только статические файлы.

Возможно ли с помощью маршрутизации или другой конфигурации, что папка wwwroot в проекте asp.net 4.5 ведет себя аналогичным образом, так что статические файлы обслуживаются только из нее, и это "корень" веб-приложения для статических файлов?

(Отчасти я хочу спросить, что у меня есть угловое приложение, размещенное в проекте asp.net 5 в VS2015, но мне нужно перенести это в проект asp.net 4.5, но я хотел бы сохранить существующую структуру на диске)

Попытка использования OWIN

Я попытался сделать это с помощью пустого проекта веб-приложения ASP.NET 4.5 и OWIN. Таким образом, в моей структуре папок есть мое угловое приложение с основным файлом index.html в папке wwwroot в папке проекта. В корне проекта нет HTML-файлов.

Я добавил OWIN через nuget и следующий файл запуска:

[assembly: OwinStartup(typeof(MyApp.UI.Startup))]
namespace MyApp.UI
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            string root = AppDomain.CurrentDomain.BaseDirectory;
            var physicalFileSystem = new PhysicalFileSystem(Path.Combine(root, "wwwroot"));
            var options = new FileServerOptions
            {
                EnableDefaultFiles = true,
                FileSystem = physicalFileSystem
            };
            options.StaticFileOptions.FileSystem = physicalFileSystem;
            options.StaticFileOptions.ServeUnknownFileTypes = false;
            options.DefaultFilesOptions.DefaultFileNames = new[] {"index.html"};
            app.UseFileServer(options);
        }
    }
}

Хотя это не удается - источник моего файла index.html загружается при запуске, но все файлы css, js и т. Д., На которые он ссылается, не работают с 404. Еще хуже, если я добавляю gulpfile.js в корневой URL-адрес загружает мой файл gulp из корня папки проекта. Это именно то, чего я пытаюсь избежать.

Есть идеи?

3 ответа

Решение

Я считаю, что у меня есть рабочий метод для этого сейчас. Я немного погуглил и поэкспериментировал, но в итоге я придумал следующий процесс:

  1. Создайте новый проект ASP.NET 4.5 в VS2015, выбрав Пустой шаблон

  2. Добавить ссылки OWIN через nuget (Install-Package Microsoft.Owin.Host.SystemWeb а также Microsoft.Owin.StaticFiles)

  3. Добавьте файл запуска, подобный этому:

    [assembly: OwinStartup(typeof(MyApp.Startup))]
    namespace MyApp.UI
    {
        public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                string root = AppDomain.CurrentDomain.BaseDirectory;
                var physicalFileSystem = new PhysicalFileSystem(Path.Combine(root, "wwwroot"));
                var options = new FileServerOptions
                {
                    RequestPath = PathString.Empty,
                    EnableDefaultFiles = true,
                    FileSystem = physicalFileSystem
                };
                options.StaticFileOptions.FileSystem = physicalFileSystem;
                options.StaticFileOptions.ServeUnknownFileTypes = false;
                app.UseFileServer(options);
            }
        }
    }
    
  4. Добавьте следующее в файл web.config, чтобы IIS не обслуживал статические файлы, которые вам не нужны, и принудительно выполняйте все через конвейер OWIN:

    <system.webServer>
        <handlers>
          <remove name="StaticFile"/>
          <add name="Owin" verb="" path="*" type="Microsoft.Owin.Host.SystemWeb.OwinHttpHandler, Microsoft.Owin.Host.SystemWeb"/>
        </handlers>
      </system.webServer>
    

Я всегда открыт для лучших предложений о том, как это сделать, но это, по крайней мере, мне кажется.

Хотя OWIN работал для меня в моей среде разработки, запущенной в VS 2017, он не работал после развертывания в Azure. Мы также запускаем SPA и храним выходные данные webpack в ~/wwwroot/, но хотели, чтобы они загружались так, как если бы они находились в корне проекта ~ / так же, как это делает.net core webapi. Я сделал это с помощью переписывания URL, показанного ниже:

<system.webServer>
<rewrite>
  <rules>
    <rule name="wwwRootFix" stopProcessing="true">
      <match url="(.*)" />
      <conditions logicalGrouping="MatchAll">
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
        <add input="{APPL_PHYSICAL_PATH}wwwroot\{R:1}" matchType="IsFile" />
        <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
        <add input="{REQUEST_URI}" pattern="^/(wwwroot)" negate="true" />
      </conditions>
      <action type="Redirect" url="/wwwroot/{R:1}" />
    </rule>
    <rule name="React Routes" stopProcessing="true">
      <match url=".*" />
      <conditions logicalGrouping="MatchAll">
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
        <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
        <add input="{REQUEST_URI}" pattern="^/(wwwroot)" negate="true" />
      </conditions>
      <action type="Rewrite" url="/wwwroot/index.html" />
    </rule>
  </rules>
</rewrite>
</system.webServer>

Первое правило гарантирует, что искомый файл не существует в корне, не является папкой, найден по новому пути, не является папкой wwwroot и не является частью API. Если ВСЕ эти условия соблюдены, он пытается загрузить данные из wwwroot.

Второе правило проверяет, чтобы убедиться, что вы не пытаетесь загрузить API или файл, который действительно существует в корне. Если оба условия выполняются, загружается HTML-документ SPA по умолчанию (в нашем случае мы используем реагирование).

По сути, это позволяет реагирующему маршрутизатору 4 обрабатывать все остальные маршруты после того, как все остальные условия не смогли найти соответствие, и сделать так, чтобы он не выдавал ошибку 404 при попытке загрузить один из маршрутов реагирующего маршрутизатора.

Если вы хотите использовать IIS для этого, вы можете создать правило перезаписи:

<system.webServer>
    <rewrite>
      <rules>
        <rule name="RewriteUnknownToIndex" patternSyntax="ECMAScript" stopProcessing="true">
          <match url="^wwwroot/.*" negate="true" />
          <action type="Rewrite" url="/wwwroot/index.html" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>

Вы также можете добавить префикс к регулярному выражению URL, например: ^(wwwroot|api)/.*, если это веб-API, который вы хотели бы разместить в /api.

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