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

Lee*_*Lee 18 c# asp.net-mvc asp.net-mvc-routing asp.net-web-api

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

http://server/collection/id.format
Run Code Online (Sandbox Code Playgroud)

我想在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
);
Run Code Online (Sandbox Code Playgroud)

不幸的是,这似乎没有解决(在/ foo,/ foo/bar和/foo/bar.txt上一致的404').在'format'之前使用斜杠的类似模式工作正常:

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

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

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

小智 23

我可以通过以下操作来实现这一目标:更换"*.""*"在system.webServer.handlers在web.config中,即删除时期.

<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
Run Code Online (Sandbox Code Playgroud)

  • 要仅为api/*请求启用它,只需**添加**行`<add name ="ExtensionlessUrlHandler-Integrated-4.0-API"path ="api/*"verb ="*"type ="System.Web .Handlers.TransferRequestHandler"preCondition ="integratedMode,runtimeVersionv4.0"/>`.顺便说一句,名字并不重要. (6认同)

pva*_*sek 17

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

<modules runAllManagedModulesForAllRequests="true">..</modules>
Run Code Online (Sandbox Code Playgroud)

否则它将无法在IIS中运行(可能由非托管处理程序处理).


Dar*_*rov 15

我无法重现这个问题.这应该工作.这是我的设置:

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

    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  5. 相应的API控制器:

    public class ProductsController : ApiController
    {
        public Product Get(int id)
        {
            return new Product
            {
                Id = id,
                Name = "prd " + id
            };
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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();
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

现在,当您运行此控制台应用程序时,您可以导航到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();
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

http://localhost:8080/products/123.xml
http://localhost:8080/products/123.json
Run Code Online (Sandbox Code Playgroud)

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

public class UriPathExtensionMapping
{
    public static readonly string UriPathExtensionKey;

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

    ...
}
Run Code Online (Sandbox Code Playgroud)

这一切都是为了回答你的问题:

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

是.


Lee*_*Lee 12

我接受了达林的答案(是的,句号可用于路线网址)因为它对我的例子特别正确,但对我没有帮助.这是我的错,因为没有明确指出"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
);
Run Code Online (Sandbox Code Playgroud)

将约束添加到前一个令牌可以正确分解和处理入站URL.如果没有提示,可以解释"id"标记以匹配URL的剩余范围.这只是需要约束来描述字符串参数之间的边界的特定情况.

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