我正在努力从原始的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')。在'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
);
我还没有深入研究Web Api的代码,在此之前我曾想过要在这里询问这是否是Web Api中已知或甚至是合理的限制。
更新:我忽略了提到“id”和“format”是字符串,这对于解决这个问题很重要。添加约束以从“id”标记中排除句点可解决404问题。
答案 0 :(得分:22)
我能够通过以下方式实现这一目标:
在web.config中的system.webServer.handlers中用"*."
替换"*"
,即删除句点。
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
答案 1 :(得分:17)
小心在web.config中的modules属性中设置runAllManagedModulesForAllRequests选项
<modules runAllManagedModulesForAllRequests="true">..</modules>
否则它将无法在IIS中运行(可能由非托管处理程序处理)。
答案 2 :(得分:15)
我无法重现这个问题。这应该工作。这是我的设置:
Microsoft.AspNet.WebApi.SelfHost
NuGet 定义Product
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
相应的API控制器:
public class ProductsController : ApiController
{
public Product Get(int id)
{
return new Product
{
Id = id,
Name = "prd " + id
};
}
}
主持人:
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路由中使用句点吗?
是
答案 3 :(得分: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
);
将约束添加到前一个令牌可以正确分解和处理入站URL。如果没有提示,可以解释“id”标记以匹配URL的剩余范围。这只是需要约束来描述字符串参数之间的边界的特定情况。
是的,可以在Asp.Net Web API中的URL路由中使用句点,但如果它们要遵循字符串参数,请确保将正确的约束应用于路径。
答案 4 :(得分:0)
IIS以文件下载的句点拦截请求。在您的web.config中,您可以将IIS配置为忽略特定的URL路径,因为webapi将处理请求。如果希望IIS处理文件下载以及处理webapi调用,可以将webagedDllExtension配置添加到web.config中的system.webServer.handlers。
<add name="ManagedDllExtension" path="collection/*.*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />