WCF REST 4.0中的简单URL路线,而无需拖延斜线
题
我有一个基于WCF REST服务模板40(CS)的WCF REST 4.0项目。我想公开简单的服务端点URL 没有 拖延斜线。例如:
- CarService.CS
- http://www.domain.com/cars - 获得所有汽车的列表
- http://www.domain.com/cars/123 - 获得ID 123的单车返回
- 卡车服务
- http://www.domain.com/trucks - 获取所有卡车的清单
- http://www.domain.com/trucks/456 - 获得带ID 456的一辆卡车返回
我将上述URL视为资源请求(不是目录),这就是为什么我认为在这里不适合拖延的原因。
不幸的是,我似乎无法获得我想要的行为,因为我总是被重定向到 /和 /卡车 / 和 拖延斜线。
这是我定义“汽车”路线和服务方法的方式 - 请注意,我在任何路由或URI模板定义中尚未包含任何斜线:
// Global.asax.cs
RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHostFactory(), typeof(CarService)));
// CarService.cs
[WebGet(UriTemplate = "")]
public List<Car> GetCollection()
{
return DataContext.GetAllCars();
}
请注意,MVC不起作用。使用MapRoute方法,我可以将请求直接路由到 http://www.domain.com/about 没有重定向到 /大约 /。如何在WCF REST 4.0中获得相同的行为?
解决方案
您遇到的主要问题是 当前的 WCF REST的版本会导致307重定向(到“/”),当您在webget属性中为uritemplate有一个空字符串。据我所知,当前版本中没有解决这个问题。
但是,鉴于您需要解决方案1)允许您区分服务,而2)(相对)uris有一些“中间基础”解决方案。
第一个解决方案您可以将其放入您的global.asax文件中(per 这个示例)。您可以为每种服务做一个服务路线:
RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHostFactory(), typeof(CarService)));
RouteTable.Routes.Add(new ServiceRoute("trucks", new WebServiceHostFactory(), typeof(TruckService)));
此时,您可以在每种服务中填充尿液板:
[WebGet(UriTemplate = "all")]
CarPool GetAllCars();
[WebGet(UriTemplate = "{carName}")]
Car GetCar(string carName);
这将使您的uris:
www.domain.com/cars/all
www.domain.com/cars/123 or www.domain.com/cars/honda
同样适用于卡车:
www.domain.com/trucks/all
www.domain.com/trucks/123 or www.domain.com/trucks/ford
第二个解决方案使用服务主机 休息入门套件 (即,WebServiceHost2Factory)。
RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHost2Factory(), typeof(CarService)));
当使用您试图使用上面的URI时,这不会导致307重定向,从而使您完全需要。尽管我意识到使用该服务主机工厂,而不是使用WCF 4发货的工厂感到有些奇怪。
其他提示
您需要一个尿液板,尝试这样的事情:
[ServiceContract()]
public interface ICarService
{
[OperationContract]
[WebGet(UriTemplate = "/Car")]
CarPool GetAllCars();
[OperationContract]
[WebGet(UriTemplate = "/Car/{carName}")]
Car GetCar(string carName);
}
尝试将其放在global.asax.cs中
protected void Application_BeginRequest(object sender, EventArgs e)
{
string rawUrl = HttpContext.Current.Request.RawUrl.ToLower();
if (rawUrl.EndsWith("/cars"))
{
HttpContext.Current.RewritePath(rawUrl + "/"); // append trailing slash
}
}
我正在处理这个确切的问题,并在MS在线文档中遇到了这个片段:
默认情况下,路由不处理将其映射到Web服务器上现有物理文件的请求。例如,请求 http://server/application/products/beverages/coffee.aspx 如果在产品/饮料/咖啡中存在物理文件,则无法通过路由来处理。即使请求与定义的模式匹配,例如{Controller}/{action}/{ID},路由也不会处理该请求。
我意识到我的路线模式与目录匹配我的服务已托管。看来目录的处理方式与物理文件相同,并且匹配目录的路由模式也被忽略了。因此,在文档之后,我将RouteexistingFiles属性设置为“ true”。现在,我的服务似乎正确地路由了请求,并且我能够保持我非常非常喜欢的其余语法。
较旧的问题,但这是我如何通过WCF4 REST服务来解决问题(使用Global.asax中的RouteTable添加ServicerOutes)。 IIS7已配置,因此当调用服务时,我有一个空的相对路径,因此处理方法的uritemplate是空的,就像Will的汽车示例一样。我在服务的Web.config文件中使用了重写规则,以添加一个“/”。它始终与路径匹配,然后检查原始URI({request_uri}),以查看它是否包含没有尾随“/”的路径。
<rewrite>
<rules>
<!--
This rule will append a "/" after "/car" if
the client makes a request without a trailing "/".
ASP however must have a trailing "/" to find
the right handler.
-->
<rule name="FixCarPath" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{REQUEST_URI}" pattern="/car\?" />
</conditions>
<action type="Rewrite" url="{PATH_INFO}/" />
</rule>
</rules>
</rewrite>
更可重复使用:
public class Global : NinjectHttpApplication
{
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
RegisterRoutes();
}
private void RegisterRoutes()
{
RouteTable.Routes.Add(new ServiceRoute("login", new NinjectWebServiceHostFactory(), typeof(LoginService)));
RouteTable.Routes.Add(new ServiceRoute("incidents", new NinjectWebServiceHostFactory(), typeof(IncidentService)));
SetRoutePrefixes();
}
//This is a workaround for WCF forcing you to end with "/" if you dont have a urlTemplate and redirecting if you dont have
protected void Application_BeginRequest(object sender, EventArgs e)
{
string rawUrl = HttpContext.Current.Request.RawUrl.ToLower();
if (_routePrefixes.Any(rawUrl.EndsWith))
{
HttpContext.Current.RewritePath(rawUrl + "/"); // append trailing slash
}
}
private static List<string> _routePrefixes;
private static void SetRoutePrefixes()
{
_routePrefixes = new List<string>();
foreach (var route in RouteTable.Routes)
{
var r = route as Route;
var routePrefix = r.Url.Split('/').First();
_routePrefixes.Add(routePrefix);
}
}
尝试在global.asax中更改您的代码。
Routes.Add(new ServiceRoute("cars", new WebServiceHostFactory(), typeof(CarService)));
RouteTable.Routes.Add(new ServiceRoute("trucks", new WebServiceHostFactory(), typeof(TruckService)));
...至...
WebServiceHostFactory factory = new WebServiceHostFactory();
Routes.Add(new ServiceRoute("cars", factory, typeof(CarService)));
RouteTable.Routes.Add(new ServiceRoute("trucks", factory, typeof(TruckService)));