Frage

Ich habe ein WCF REST 4.0-Projekt auf der Basis der WCF REST-Service-Vorlage 40 (CS). Ich mag einfachen Service-Endpunkt-URLs belichten ohne folgende Schrägstriche. Zum Beispiel:

  1. CarService.cs
  2. TruckService.cs

sehe ich den obigen URLs als Ressourcenanforderungen (keine Verzeichnisse), weshalb ich glaube nicht, folgende Schrägstriche sind hier angebracht.

Leider kann ich nicht scheinen, um das Verhalten mag ich zu bekommen, weil ich immer zu / Autos umgeleitet bin / und / LKW / mit einem Schrägstrich.

Hier ist, wie ich habe die „Autos“ Route und Service-Methode definiert - zur Kenntnis, dass ich habe keine Schrägstriche in eines der Route oder URI Template-Definitionen enthalten:

// Global.asax.cs
RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHostFactory(), typeof(CarService)));

// CarService.cs
[WebGet(UriTemplate = "")]
public List<Car> GetCollection()
{
    return DataContext.GetAllCars();
}

Beachten Sie, dass MVC nicht auf diese Weise funktioniert. Mit der MapRoute Methode kann ich Routenanfragen direkt an http://www.domain.com/about ohne Umleitung auf / über / . Wie kann ich das gleiche Verhalten in WCF REST 4.0 bekommen?

War es hilfreich?

Lösung

The primary issue that you're running into is that the current version of WCF REST causes a 307 redirect (to the "/") when you have an empty string for the UriTemplate in your WebGet attribute. As far as I know, there is no getting around this in the current version.

However, there are a couple of "middle ground" solution to your problem given that you want a solution that 1) allows you to differentiate services, and 2) have (relatively) short URIs.

First Solution You can put this in your global.asax file (per this example). You can do a service route for each service:

RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHostFactory(), typeof(CarService)));
RouteTable.Routes.Add(new ServiceRoute("trucks", new WebServiceHostFactory(), typeof(TruckService)));

At this point you can populate your UriTemplate in each service:

[WebGet(UriTemplate = "all")]
CarPool GetAllCars();

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

This will allow you URIs of:

www.domain.com/cars/all
www.domain.com/cars/123 or www.domain.com/cars/honda

similarly for trucks:

www.domain.com/trucks/all
www.domain.com/trucks/123 or www.domain.com/trucks/ford

Second Solution Use the service host from the REST Starter Kit (i.e., the WebServiceHost2Factory).

RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHost2Factory(), typeof(CarService)));

This does not result in a 307 redirect when using the URIs that you're attempting to use above and thus, gives you exactly what you need. Though I realize that feels a little weird using that service host factory rather than the one that ships with WCF 4.

Andere Tipps

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

 }

Try putting this in the 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
        }
    }

I was dealing with this exact problem and ran across this snippet in the MS online docs:

By default, routing does not handle requests that map to an existing physical file on the Web server. For example, a request for http://server/application/Products/Beverages/Coffee.aspx is not handled by routing if a physical file exists at Products/Beverages/Coffee.aspx. Routing does not handle the request even if it matches a defined pattern, such as {controller}/{action}/{id}.

I realized that my route pattern matched the directory my service was hosted in. It appears that a directory is treated the same as a physical file, and route patterns that match a directory are ignored as well. So following the documentation, I set the RouteExistingFiles property to "true" on the RouteCollection. My service now seems to be routing the requests correctly and I've been able to keep the REST syntax that I love so very very much.

Older question but here's how I solved the problem with a WCF4 REST service (using the RouteTable in Global.asax to add ServiceRoutes). IIS7 is configured so that by the time the service is invoked I have an empty relative path so the handling method's UriTemplate is empty like Will's Car example. I used a rewrite rule in the service's web.config file to add a "/" if needed. It always matches the path then checks the original URI ({REQUEST_URI}) to see if it contains a path without a trailing "/".

    <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>

A bit more reusable:

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);
        }
    }

Try changing your code in the Global.asax from...

Routes.Add(new ServiceRoute("cars", new WebServiceHostFactory(), typeof(CarService))); RouteTable.Routes.Add(new ServiceRoute("trucks", new WebServiceHostFactory(), typeof(TruckService)));

...to...

WebServiceHostFactory factory = new WebServiceHostFactory();

Routes.Add(new ServiceRoute("cars", factory, typeof(CarService))); RouteTable.Routes.Add(new ServiceRoute("trucks", factory, typeof(TruckService)));

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top