19

我有一个基于 WCF REST 服务模板 40(CS) 的 WCF REST 4.0 项目。我想公开没有尾部斜杠的简单服务端点 URL。例如:

  1. 汽车服务.cs
  2. 卡车服务.cs

我将上述 URL 视为资源请求(而不是目录),这就是为什么我认为尾部斜杠在这里不合适。

不幸的是,我似乎无法获得我想要的行为,因为我总是被重定向到 /cars/ 和 /trucks/并带有斜杠。

以下是我定义“汽车”路线和服务方法的方式 - 请注意,我没有在任何路线或 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,而无需重定向到 /about/。如何在 WCF REST 4.0 中获得相同的行为?

4

7 回答 7

9

您遇到的主要问题是,当您的 WebGet 属性中有 UriTemplate 的空字符串时,当前版本的 WCF REST 会导致 307 重定向(到“/”)。据我所知,在当前版本中没有解决这个问题。

但是,有几个“中间立场”解决方案可以解决您的问题,因为您需要一个 1) 允许您区分服务和 2) 具有(相对)短 URI 的解决方案。

第一个解决方案 你可以把它放在你的 global.asax 文件中(根据这个例子)。您可以为每个服务做一个服务路线:

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 附带的服务主机工厂感觉有点奇怪。

于 2010-10-20T01:13:58.530 回答
3

You need a UriTemplate, Try something like this:

 [ServiceContract()]
 public interface ICarService
 {

     [OperationContract]
     [WebGet(UriTemplate = "/Car")]
     CarPool GetAllCars();

     [OperationContract]
     [WebGet(UriTemplate = "/Car/{carName}")]
     Car GetCar(string carName);

 }
于 2010-10-19T20:14:27.413 回答
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
        }
    }
于 2012-06-01T01:07:51.343 回答
2

我正在处理这个确切的问题,并在 MS 在线文档中遇到了这个片段:

默认情况下,路由不处理映射到 Web 服务器上现有物理文件的请求。例如,如果 Products/Beverages/Coffee.aspx 中存在物理文件,则路由不会处理对http://server/application/Products/Beverages/Coffee.aspx的请求。路由不会处理请求,即使它匹配定义的模式,例如 {controller}/{action}/{id}。

我意识到我的路由模式与我的服务所在的目录匹配。似乎目录被视为与物理文件相同,并且与目录匹配的路由模式也被忽略。因此,按照文档,我在 RouteCollection 上将 RouteExistingFiles 属性设置为“true”。我的服务现在似乎可以正确地路由请求,并且我已经能够保持我非常喜欢的 REST 语法。

于 2012-01-03T15:10:18.837 回答
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);
        }
    }
于 2013-06-18T20:32:21.837 回答
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>
于 2012-05-02T15:00:32.577 回答
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)));

于 2010-11-24T19:36:36.740 回答