Ядро ASP.net MVC ловит весь маршрут обслуживает статический файл

Есть ли способ сделать перехват всех маршрутов статическим файлом?

Глядя на это http://blog.nbellocam.me/2016/03/21/routing-angular-2-asp-net-core/

Я в основном хочу что-то вроде этого:

        app.UseMvc(routes =>
        {
            routes.MapRoute("default", "{controller}/{action=Index}");

            routes.MapRoute("spa", "{*url}"); // This should serve SPA index.html
        });

Таким образом, любой маршрут, который не соответствует контроллеру MVC, будет обслуживаться wwwroot/index.html

8 ответов

Решение

Если вы уже находитесь в стадии маршрутизации, вы прошли точку, когда статические файлы подаются в конвейер. Ваш стартап будет выглядеть примерно так:

app.UseStaticFiles();

...

app.UseMvc(...);

Порядок здесь важен. Таким образом, ваше приложение будет сначала искать статические файлы, что имеет смысл с точки зрения производительности - не нужно запускать конвейер MVC, если вы просто хотите выбросить статический файл.

Вы можете создать универсальное действие контроллера, которое будет возвращать содержимое файла. Например (кража кода в вашем комментарии):

public IActionResult Spa()
{
    return File("~/index.html", "text/html");
}

Я должен был сделать некоторые дополнения к ответу @DavidG. Вот что я закончил

Startup.cs

app.UseStaticFiles();

app.UseMvc(routes =>
{
   routes.MapRoute("default", "{controller}/{action}");

   routes.MapRoute("Spa", "{*url}", defaults: new { controller = "Home", action = "Spa" });
});

HomeController.cs

public class HomeController : Controller
{
  public IActionResult Spa()
  {
      return File("~/index.html", "text/html");
  }
}

ASP.NET Core перехватывает все маршруты, для Web API и MVC настроены по-разному

С веб-API (if you're using prefix "api" for all server-side controllers eg. Route("api/[controller"]):

app.Use(async (context, next) => 
{ 
    await next(); 
    var path = context.Request.Path.Value;

    if (!path.StartsWith("/api") && !Path.HasExtension(path)) 
    { 
        context.Request.Path = "/index.html"; 
        await next(); 
    } 
});            

app.UseStaticFiles();
app.UseDefaultFiles();

app.UseMvc();

С MVC (dotnet add package Microsoft.AspNetCore.SpaServices -Version x.y.z):

app.UseStaticFiles();
app.UseDefaultFiles();

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

    routes.MapSpaFallbackRoute("spa", new { controller = "Home", action = "Index" }); 
});  

Если вы не хотите вручную указывать, какие маршруты для API:

app.UseDefaultFiles();
app.UseStaticFiles();

app.UseMvc()

//return index instead of 404

app.Use(async (context, next) => {
    context.Request.Path = "/index.html";
    await next();
});

app.UseStaticFiles();

То, что я использую это работает хорошо Microsoft.AspNetCore.Builder.SpaRouteExtensions.MapSpaFallbackRoute:

app.UseMvc(routes =>
{
    // Default route for SPA components, excluding paths which appear to be static files (have an extension)
    routes.MapSpaFallbackRoute(
        "spaFallback",
        new { controller = "Home", action = "Index" });
});

HomeController.Index имеет эквивалент вашего index.html, Возможно, вы также можете перенаправить на статическую страницу.

Немного не по теме, но если у вас также есть API в том же проекте под api В папке вы можете установить ответ 404 по умолчанию для любых маршрутов API, которые не совпадают:

routes.MapRoute(
    "apiDefault",
    "api/{*url}",
    new { controller = "Home", action = "ApiNotFound" });

В результате вы получите следующее поведение:

  • /controller => Без расширения, так что обслуживайте страницу SPA по умолчанию с HomeController.Index и пусть SPA управляет маршрутизацией
  • /file.txt => Расширение обнаружено, подать статический файл
  • /api/controller => правильный ответ API (используйте маршрутизацию атрибутов или настройте другую карту для контроллеров API)
  • /api/non-existent-route => 404 NotFound() вернулся из HomeController.ApiNotFound

Во многих случаях вам понадобится API в отдельном проекте, но это жизнеспособная альтернатива.

Для того, чтобы служить index.html от wwwroot В папку должны быть добавлены следующие директивы (.Net Core 2).

Это позволяет обслуживать статические файлы:

app.UseStaticFiles();

Это позволяет получить файлы по умолчанию, например, index.html:

app.UseDefaultFiles();

В ASP.NET Core 3.1 я использовал следующее:

Startup.cs

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRouting();

    app.UseCors();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });

    app.UseDefaultFiles();
    app.UseStaticFiles();
}

MyController.cs

[HttpGet("{anything}")]
public IActionResult GetSPA()
{
    return File("~/index.html", "text/html");
}

В .NET Core 6 добавьтеapp.MapFallbackToFile("index.html");в вашейProgram.csфайл.

Вот пример кода из шаблона проекта ASP.NET Core с React:

      app.MapControllerRoute(
    name: "default",
    pattern: "{controller}/{action=Index}/{id?}");

app.MapFallbackToFile("index.html");  

app.Run();
Другие вопросы по тегам