【问题标题】:ASP.net core MVC catch all route serve static fileASP.net core MVC 捕获所有路由服务静态文件
【发布时间】:2017-02-23 11:24:12
【问题描述】:

有没有办法让 catch all 路由服务于静态文件?

看着这个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

【问题讨论】:

  • 如果您已经在路由元素中,那么您已经超越了在管道中提供静态文件的点。您可以创建一个包罗万象的控制器操作,该操作将返回文件的内容。
  • 有推荐的方法吗?
  • 据我所知没有。
  • return File("~/index.html", "text/html"); 在操作中似乎工作正常

标签: c# asp.net-core asp.net-core-mvc


【解决方案1】:

我不得不对@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");
  }
}

【讨论】:

  • 这似乎可以在本地完美运行,但是当我发布到 Azure 应用服务时,对 *.js 文件等静态文件的所有请求总是返回 index.html 文件,而不是请求的实际文件.知道为什么吗?
【解决方案2】:

ASP.NET Core 捕获 Web API 和 MVC 的所有路由配置不同

使用 Web 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" }); 
});  

【讨论】:

  • 太棒了!我使用了您的第一个解决方案,尽管我将UseStaticFiles 放在您的逻辑之前,以便首先提供静态文件,而我不需要UseDefaultFiles。更重要的是,我必须将路径设置为context.Request.Path = "/";,并在我的 HomeController 的索引操作中,服务File("~/index.html", "text/html");
【解决方案3】:

如果您已经处于路由阶段,那么您已经过了在管道中提供静态文件的阶段。您的初创公司将如下所示:

app.UseStaticFiles();

...

app.UseMvc(...);

这里的顺序很重要。因此,您的应用将首先查找静态文件,这从性能的角度来看是有意义的 - 如果您只想丢弃静态文件,则无需运行 MVC 管道。

您可以创建一个包罗万象的控制器操作,该操作将返回文件的内容。例如(窃取您评论中的代码):

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

【讨论】:

  • 您使用的是哪个File 类?不可能是System.IO.FileSystem.File。找不到合适的匹配项。
  • @Marcus 不是文件类,是控制器类的File 方法。
  • 我是个笨蛋,忘记继承Controller,所以我看不到它。谢谢!
  • 我收到No file provider has been configured to process the supplied file
【解决方案4】:

如果您不想手动指定哪些路由用于 api:

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

app.UseMvc() // suggestion: you can move all the SPA requests to for example /app/<endpoints_for_the_Spa> and let the mvc return 404 in case <endpoints_for_the_Spa> is not recognized by the backend. This way SPA will not receive index.html

// at this point the request did not hit the api nor any of the files

// return index instead of 404 and let the SPA to take care of displaying the "not found" message
app.Use(async (context, next) => {
    context.Request.Path = "/index.html";
    await next();
});
app.UseStaticFiles(); // this will return index.html

【讨论】:

  • 这在我的 asp.net-core-3.1 应用程序中也可以正常工作。我刚刚在 app.UseEndpoints 之后添加了 app.Use 和第二个 app.UseStaticFiles。
  • 感谢您的回答!当我从核心 2->3.1 转换并且我的 oidc 回调重定向以 404 结束时,这是我的 SPA 的解决方案。有了这个技巧,一切都恢复了正常!
  • 两次调用app.UseStaticFiles() 有什么意义?我不明白那部分。
  • @flipdoubt 我这是因为一旦静态管道已经运行,他就在为索引页面提供服务,所以他需要重新调用静态管道来服务索引页面。
  • @flipdoubt 正如 Maxime Morin 所说,这只是一种始终返回 index.html 的方法。
【解决方案5】:

我使用的效果很好的是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,您可以为任何不匹配的 API 路由设置默认 404 响应:

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

你最终会出现以下行为:

  • /controller => 没有扩展,所以从 HomeController.Index 提供 SPA 默认页面并让 SPA 处理路由
  • /file.txt => 检测到扩展,提供静态文件
  • /api/controller => 正确的 API 响应(使用属性路由或为 API 控制器设置另一个映射)
  • /api/non-existent-route => 404 NotFound()HomeController.ApiNotFound 返回

在许多情况下,您会希望在单独的项目中使用 API,但这是一个可行的替代方案。

【讨论】:

    【解决方案6】:

    为了从wwwroot 文件夹中提供index.html,应添加以下指令(.Net Core 2)。

    这允许提供静态文件:

    app.UseStaticFiles();
    

    这允许获取默认文件,例如index.html:

    app.UseDefaultFiles();
    

    【讨论】:

      【解决方案7】:

      在 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");
      }
      

      【讨论】:

        猜你喜欢
        • 2015-12-31
        • 2011-04-29
        • 1970-01-01
        • 2016-07-09
        • 1970-01-01
        • 2021-04-22
        • 2016-02-11
        • 2019-01-20
        • 1970-01-01
        相关资源
        最近更新 更多