wcf rest slash trailing

Rutas URL simples en WCF Rest 4.0 sin barra diagonal final



slash trailing (7)

Tengo un proyecto WCF REST 4.0 basado en la Plantilla de Servicio 40 (CS) de WCF REST. Me gustaría exponer URL de punto final de servicio simples sin barras diagonales. Por ejemplo:

  1. CarService.cs
  2. TruckService.cs

Veo las URL anteriores como solicitudes de recursos (no directorios), por lo que no creo que las barras inclinadas sean apropiadas aquí.

Desafortunadamente, parece que no puedo obtener el comportamiento que deseo porque siempre estoy redirigido a / cars / and / trucks / con una barra diagonal.

Así es como he definido la ruta y el método de servicio de los "autos". Tenga en cuenta que no he incluido ninguna barra oblicua en ninguna de las definiciones de ruta o plantilla de 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(); }

Tenga en cuenta que MVC no funciona de esta manera. Con el método MapRoute puedo enrutar las solicitudes directamente a http://www.domain.com/about sin una redirección a / about /. ¿Cómo puedo obtener el mismo comportamiento en WCF REST 4.0?


El problema principal con el que se está ejecutando es que la versión actual de WCF REST provoca un redireccionamiento 307 (a la "/") cuando tiene una cadena vacía para el UriTemplate en su atributo WebGet. Por lo que sé, no hay forma de evitar esto en la versión actual.

Sin embargo, hay un par de soluciones "intermedias" para su problema dado que desea una solución que 1) le permita diferenciar servicios y 2) tenga URI (relativamente) cortos.

Primera solución Puede poner esto en su archivo global.asax (por este ejemplo ). Puedes hacer una ruta de servicio para cada servicio:

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

En este punto, puede llenar su UriTemplate en cada servicio:

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

Esto le permitirá URI de:

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

de manera similar para camiones:

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

Segunda solución Use el host del servicio del kit de inicio REST (es decir, el WebServiceHost2Factory).

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

Esto no da como resultado un redireccionamiento 307 cuando se usan los URI que intenta usar anteriormente y, por lo tanto, le proporciona exactamente lo que necesita. Aunque me doy cuenta de que se siente un poco raro usar esa fábrica de host de servicio en lugar de la que se envía con WCF 4.


Estaba lidiando con este problema exacto y encontré este fragmento en los documentos en línea de MS:

De forma predeterminada, el enrutamiento no controla las solicitudes que se asignan a un archivo físico existente en el servidor web. Por ejemplo, una solicitud de http://server/application/Products/Beverages/Coffee.aspx no se maneja mediante enrutamiento si existe un archivo físico en Products / Beverages / Coffee.aspx. El enrutamiento no controla la solicitud, incluso si coincide con un patrón definido, como {controller} / {action} / {id}.

Me di cuenta de que mi patrón de ruta coincidía con el directorio donde estaba alojado mi servicio. Parece que un directorio se trata igual que un archivo físico, y los patrones de ruta que coinciden con un directorio también se ignoran. Así que siguiendo la documentación, establezco la propiedad RouteExistingFiles en "true" en la RouteCollection. Mi servicio ahora parece estar enrutando las solicitudes correctamente y he podido mantener la sintaxis REST que tanto amo.


Intenta cambiar tu código en el Global.asax desde ...

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

...a...

WebServiceHostFactory factory = new WebServiceHostFactory();

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


Intenta poner esto en el 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 } }


Necesitas un UriTemplate, prueba algo como esto:

[ServiceContract()] public interface ICarService { [OperationContract] [WebGet(UriTemplate = "/Car")] CarPool GetAllCars(); [OperationContract] [WebGet(UriTemplate = "/Car/{carName}")] Car GetCar(string carName); }


Pregunta anterior, pero aquí es cómo resolví el problema con un servicio REST de WCF4 (usando RouteTable en Global.asax para agregar ServiceRoutes). IIS7 se configura de manera que cuando se invoca el servicio tengo una ruta relativa vacía, por lo que la plantilla UriTemplate del método de manejo está vacía como en el ejemplo de Will''s Car. Utilicé una regla de reescritura en el archivo web.config del servicio para agregar una "/" si es necesario. Siempre coincide con la ruta y luego verifica el URI original ({REQUEST_URI}) para ver si contiene una ruta sin un "/" al final.

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


Un poco más reutilizable:

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