WCF Rest 4.0中的简单URL路由,不带斜杠

时间:2010-10-19 17:22:05

标签: wcf rest slash trailing

7 个答案:

答案 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)));