答案 0 :(得分:9)
您遇到的主要问题是,当您的WebGet中的UriTemplate为空字符串时,WCF REST的当前版本会导致307重定向(到“/”)属性。据我所知,目前的版本没有解决这个问题。
然而,鉴于你想要一个1)允许你区分服务的解决方案,以及2)有(相对)短的URI,你的问题有一些“中间立场”的解决方案。
第一个解决方案 您可以将它放在global.asax文件中(按this example)。您可以为每项服务执行服务路线:
RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHostFactory(), typeof(CarService)));
RouteTable.Routes.Add(new ServiceRoute("trucks", new WebServiceHostFactory(), typeof(TruckService)));
此时,您可以在每项服务中填充您的UriTemplate:
[WebGet(UriTemplate = "all")]
CarPool GetAllCars();
[WebGet(UriTemplate = "{carName}")]
Car GetCar(string carName);
这将允许你的URI:
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
第二个解决方案 使用REST Starter Kit中的服务主机(即WebServiceHost2Factory)。
RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHost2Factory(), typeof(CarService)));
使用您尝试在上面使用的URI时,这不会导致307重定向,从而为您提供所需的确切内容。虽然我意识到使用该服务主机工厂而不是WCF 4附带的工厂感觉有点奇怪。
答案 1 :(得分:3)
你需要一个UriTemplate,尝试这样的事情:
[ServiceContract()]
public interface ICarService
{
[OperationContract]
[WebGet(UriTemplate = "/Car")]
CarPool GetAllCars();
[OperationContract]
[WebGet(UriTemplate = "/Car/{carName}")]
Car GetCar(string carName);
}
答案 2 :(得分:3)
尝试将其放入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
}
}
答案 3 :(得分:2)
我正在处理这个确切的问题并在MS在线文档中遇到了这个片段:
默认情况下,路由不处理映射到Web服务器上现有物理文件的请求。例如,如果Products / Beverages / Coffee.aspx中存在物理文件,则不会通过路由处理http://server/application/Products/Beverages/Coffee.aspx的请求。路由不处理请求,即使它与定义的模式匹配,例如{controller} / {action} / {id}。
我意识到我的路由模式与托管我的服务的目录相匹配。看起来目录被视为与物理文件相同,并且也会忽略与目录匹配的路由模式。因此,根据文档,我在RouteCollection上将RouteExistingFiles属性设置为“true”。我的服务现在似乎正确地路由请求,我已经能够非常非常地保留我喜欢的REST语法。
答案 4 :(得分:2)
较早的问题,但这里是我如何使用WCF4 REST服务解决问题(使用Global.asax中的RouteTable添加ServiceRoutes)。配置IIS7,以便在调用服务时我有一个空的相对路径,因此处理方法的UriTemplate是空的,就像Will的Car示例一样。我在服务的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>
答案 5 :(得分:2)
更可重复使用:
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);
}
}
答案 6 :(得分:1)
尝试从...
更改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)));