【问题标题】:Can periods be used in Asp.Net Web Api Routes?可以在 Asp.Net Web Api 路由中使用句点吗?
【发布时间】:2012-07-14 16:53:48
【问题描述】:

我正在从原始 http 处理程序中移动一个 API 项目,我在路径中使用句点:

http://server/collection/id.format

我想在 Web Api(自托管)版本中遵循相同的 URL 架构,并尝试了这个:

var c = new HttpSelfHostConfiguration(b);
c.Routes.MapHttpRoute(
    name: "DefaultApiRoute",
    routeTemplate: "{controller}/{id}.{format}",
    defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
    constraints: null
);

不幸的是,这似乎没有解决(/foo、/foo/bar 和 /foo/bar.txt 上的一致 404)。在“格式”之前使用斜线的类似模式可以正常工作:

var c = new HttpSelfHostConfiguration(b);
c.Routes.MapHttpRoute(
    name: "DefaultApiRoute",
    routeTemplate: "{controller}/{id}/{format}",
    defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
    constraints: null
);

我还没有深入研究 Web Api 的代码,在我想之前我会在这里询问这是否是 Web Api 中已知的,或者甚至是合理的限制。

更新:我忽略了“id”和“format”是字符串,这对于解决这个问题很重要。添加约束以从“id”标记中排除句点可以解决 404 问题。

【问题讨论】:

标签: c# asp.net-mvc asp.net-mvc-routing asp.net-web-api


【解决方案1】:

我能够通过执行以下操作来实现这一点: 将 web.config 中 system.webServer.handlers 中的 "*." 替换为 "*",即删除句点。

<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

【讨论】:

  • 谢谢,你是怎么发现这个的。
  • 如果不是为了这个答案,我永远不会想到去那里检查。非常感谢。
  • 若要仅为 api/* 请求启用它,只需添加&lt;add name="ExtensionlessUrlHandler-Integrated-4.0-API" path="api/*" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /&gt;。顺便说一句,名字并不重要。
  • web.config中可能还需要其他部分,即&lt;modules runAllManagedModulesForAllRequests="true" /&gt;this answer has more detail
【解决方案2】:

注意在 web.config 的 modules 属性中设置 runAllManagedModulesForAllRequests 选项

<modules runAllManagedModulesForAllRequests="true">..</modules>

否则它将无法在 IIS 中工作(可能会由非托管处理程序处理)。

【讨论】:

  • 我遇到了类似的问题,而这在我的案例中得到了解决。谢谢! +1
【解决方案3】:

我无法重现该问题。这应该有效。这是我的设置:

  1. 创建一个新的 .NET 4.0 控制台应用程序
  2. 切换到 .NET Framework 4.0 配置文件
  3. 安装Microsoft.AspNet.WebApi.SelfHost NuGet
  4. 定义一个Product

    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
  5. 对应的 API 控制器:

    public class ProductsController : ApiController
    {
        public Product Get(int id)
        {
            return new Product
            {
                Id = id,
                Name = "prd " + id
            };
        }
    }
    
  6. 还有一位主持人:

    class Program
    {
        static void Main(string[] args)
        {
            var config = new HttpSelfHostConfiguration("http://localhost:8080");
    
            config.Routes.MapHttpRoute(
                name: "DefaultApiRoute",
                routeTemplate: "{controller}/{id}.{format}",
                defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
                constraints: null
            );
    
            using (var server = new HttpSelfHostServer(config))
            {
                server.OpenAsync().Wait();
                Console.WriteLine("Press Enter to quit.");
                Console.ReadLine();
            }
        }
    }
    

现在,当您运行此控制台应用程序时,您可以导航到 http://localhost:8080/products/123.xml。当然,您可以导航到http://localhost:8080/products/123.json,您仍将获得 XML。那么问题来了:如何使用路由参数启用内容协商?

您可以执行以下操作:

    class Program
    {
        static void Main(string[] args)
        {
            var config = new HttpSelfHostConfiguration("http://localhost:8080");
            config.Formatters.XmlFormatter.AddUriPathExtensionMapping("xml", "text/html");
            config.Formatters.JsonFormatter.AddUriPathExtensionMapping("json", "application/json");

            config.Routes.MapHttpRoute(
                name: "DefaultApiRoute",
                routeTemplate: "{controller}/{id}.{ext}",
                defaults: new { id = RouteParameter.Optional, formatter = RouteParameter.Optional },
                constraints: null
            );

            using (var server = new HttpSelfHostServer(config))
            {
                server.OpenAsync().Wait();
                Console.WriteLine("Press Enter to quit.");
                Console.ReadLine();
            }
        }
    }

现在您可以使用以下网址:

http://localhost:8080/products/123.xml
http://localhost:8080/products/123.json

现在您可能想知道我们在路由定义中使用的{ext} 路由参数和AddUriPathExtensionMapping 方法之间的关系是什么,因为我们没有在任何地方指定它。好吧,猜猜看:它在 UriPathExtensionMapping 类中被硬编码为 ext 并且您无法修改它,因为它是只读的:

public class UriPathExtensionMapping
{
    public static readonly string UriPathExtensionKey;

    static UriPathExtensionMapping()
    {
        UriPathExtensionKey = "ext";
    }

    ...
}

所有这些都是为了回答你的问题:

句点可以在 Asp.Net Web Api Routes 中使用吗?

是的。

【讨论】:

  • 你的回答特别正确,但我忘了说“id”和“format”是字符串。我会更新问题,但我可以接受您的回答,然后添加我自己的另一个信息性答案吗?
  • formatter 作为默认参数名,ext 在 routetemplate 中,这不正确吗?
【解决方案4】:

我接受了 Darin 的回答(是的,句点可以在路由 url 中使用),因为它对我的示例特别正确,但对我没有帮助。这是我的错,因为我没有明确指出“id”是一个字符串,而不是一个整数。

要在字符串参数后面使用句点,路由引擎需要约束形式的提示:

var c = new HttpSelfHostConfiguration(b);
c.Routes.MapHttpRoute(
    name: "DefaultApiRoute",
    routeTemplate: "{controller}/{id}.{format}",
    defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
    constraints: new { id = "[^\\.]+" } // anything but a period
);

将约束添加到前面的标记可以正确分解和处理入站 URL。如果没有提示,“id”标记可以被解释为匹配 URL 的剩余范围。这只是通常需要约束来描绘字符串参数之间的边界的特定情况。

是的,句点可以在 Asp.Net Web API 中的 URL 路由中使用,但如果它们遵循字符串参数,请确保对路由应用正确的约束。

【讨论】:

    【解决方案5】:

    IIS 在文件下载时拦截带有句点的请求。在您的 web.config 中,您可以将 IIS 配置为忽略特定的 URL 路径,因为 webapi 将改为处理请求。如果您希望 IIS 处理文件下载以及处理 webapi 调用,您可以在 web.config 中将 ManagedDllExtension 配置添加到 system.webServer.handlers。

          <add name="ManagedDllExtension" path="collection/*.*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    

    【讨论】:

    • 这是不正确的,并且在大多数情况下不需要进行更改。如果您已将所有托管模块设置为要处理,则 IIS 不会仅仅因为路径中有句点而“拦截”请求。无论如何,那将是一件愚蠢的事情。文件名不需要有句点,目录/路由名可以。阅读 OP 自己的答案,了解此处实际发生的情况。
    猜你喜欢
    • 2014-03-13
    • 2010-11-04
    • 2013-11-10
    • 1970-01-01
    • 1970-01-01
    • 2017-06-19
    • 2023-03-20
    • 2015-09-08
    • 1970-01-01
    相关资源
    最近更新 更多