【问题标题】:Include a file extension in ASP.NET Core MVC routes在 ASP.NET Core MVC 路由中包含文件扩展名
【发布时间】:2021-10-28 21:52:03
【问题描述】:

我正在将旧版应用程序移植到 ASP.NET Core,并尝试保持 URL 一致。理想情况下,我需要在 URL 中包含“文件扩展名”,例如/Home/Index.ext 应该路由到对HomeControllerIndex 操作。

我从 Visual Studio 中的标准 Web 应用程序模板开始,并尝试修改默认路由:

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

/Home/Index.ext 的请求然后给出错误:

An unhandled exception occurred while processing the request.
AmbiguousMatchException: The request matched multiple endpoints. Matches:

WebApplication1.Controllers.HomeController.Index (WebApplication1)
WebApplication1.Controllers.HomeController.Privacy (WebApplication1)
WebApplication1.Controllers.HomeController.Error (WebApplication1)
Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ReportAmbiguity(CandidateState[] candidateState)

我不明白为什么它没有从该 URL 中获取操作名称来选择正确的操作。有什么方法可以更改此路由模式以使其正确匹配?

【问题讨论】:

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


    【解决方案1】:

    然后您可以像这样使用属性路由:-

    [Route("Home/Index.ext")]
    public ActionResult Index() {... }
    

    更多信息请阅读Documentation

    【讨论】:

    • 这似乎可行,但我试图避免属性路由,因为如果约定路由模式可以正常工作,每个操作都会有很多重复的属性。虽然这可能是我能做的最好的,但我仍然更喜欢基于约定的方法。
    【解决方案2】:

    您可以使用下面的 URL 重写中间件(html 扩展作为示例):

    1.自定义一个包含ReWriteRequests的类

    public class RewriteRules
    {  
        public static void ReWriteRequests(RewriteContext context)
        {
            var request = context.HttpContext.Request;
    
            if (request.Path.Value.EndsWith(".html", StringComparison.OrdinalIgnoreCase))
            {
                context.HttpContext.Request.Path = context.HttpContext.Request.Path.Value.Replace(".html", "");
    
            }
        }
    }
    

    2.Startup.cs:

    一定要在app.UseStaticFiles();之前使用URL重写中间件

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseRewriter(new RewriteOptions()
                        .Add(RewriteRules.ReWriteRequests)
                        );
    
        app.UseHttpsRedirection();
        app.UseStaticFiles();
    
        app.UseRouting();
    
        app.UseAuthentication();
        app.UseAuthorization();
            
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
            endpoints.MapRazorPages();
        });
    }
    

    参考:

    URL Rewriting Middleware in ASP.NET Core

    【讨论】:

      【解决方案3】:

      您可以使用Microsoft.AspNetCore.Routing 中的IOutboundParameterTransformer 来执行此操作。

      只需按如下方式创建一个转换器(如果您想要.ext 扩展名):

      public class AddExtensionTransformer : IOutboundParameterTransformer
      {
          public string TransformOutbound(object value)
              => value + ".ext";
      }
      

      然后你把它注册为一个约束(我用的名字addextension):

      services.Configure<RouteOptions>(options =>
      {
          options.ConstraintMap["addextension"] = typeof(AddExtensionTransformer);
      });
      

      然后在您的路由中,您只需使用addextension 作为路由约束(使用: 分隔符)。

      对于您帖子中的 default 路由,它将如下所示:

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

      现在,只要您告诉 ASP.NET Core 生成操作 URL,它也会自动生成像 /Home/Index.ext 这样的 URL。

      所以它不仅会解析它们,还会生成它们(双向工作)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-01
        • 2014-02-09
        • 2014-04-05
        • 2012-03-09
        • 2012-06-04
        • 2014-02-14
        • 1970-01-01
        • 2019-05-14
        相关资源
        最近更新 更多