Simples routes URL dans WCF Rest 4.0 sans slash
Question
J'ai un projet REST WCF 4.0 basé sur le service de WCF REST Modèle 40 (CS). Je voudrais exposer les URL simples de point de terminaison de service sans barres obliques arrière. Par exemple:
- CarService.cs
- http://www.domain.com/cars - GET renvoie une liste de toutes les voitures
- http://www.domain.com/cars/123 - GET retourne une seule voiture avec ID 123
- TruckService.cs
- http://www.domain.com/trucks - GET retourne une liste de tous les camions
- http://www.domain.com/trucks/456 - GET retourne un seul camion avec ID 456
Je regarde les URL ci-dessus que les demandes de ressources (pas de dossiers), ce qui est la raison pour laquelle je ne pense pas que des barres obliques de suivi sont ici appropriés.
Malheureusement, je ne peux pas sembler obtenir le comportement que je veux parce que je suis toujours redirigée vers / voitures / et / camions / avec un slash.
Voici comment j'ai défini la route « voitures » et méthode de service - Notez que je n'ai pas inclus des barres obliques dans une de la route ou des définitions de modèle 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();
}
Notez que MVC ne fonctionne pas de cette façon. Avec la méthode MapRoute je peux acheminer les demandes directement à http://www.domain.com/about sans redirection vers / à propos / . Comment puis-je obtenir le même comportement dans WCF REST 4.0?
La solution
Le principal problème que vous utilisez en est que le version actuelle des causes WCF REST une 307 redirect (à la « / ») lorsque vous avez une chaîne vide pour la UriTemplate dans votre WebGet attribut. Pour autant que je sache, il n'y a pas de se déplacer cela dans la version actuelle.
Cependant, il y a quelques solution « intermédiaire » à votre problème étant donné que vous voulez une solution 1) vous permet de différencier les services et 2) ont (relativement) courtes URIs.
Première solution Vous pouvez mettre dans votre fichier global.asax (par cet exemple ). Vous pouvez faire une route de service pour chaque service:
RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHostFactory(), typeof(CarService)));
RouteTable.Routes.Add(new ServiceRoute("trucks", new WebServiceHostFactory(), typeof(TruckService)));
À ce stade, vous pouvez remplir votre UriTemplate dans chaque service:
[WebGet(UriTemplate = "all")]
CarPool GetAllCars();
[WebGet(UriTemplate = "{carName}")]
Car GetCar(string carName);
Cela vous permettra de Uris:
www.domain.com/cars/all
www.domain.com/cars/123 or www.domain.com/cars/honda
De même pour les camions:
www.domain.com/trucks/all
www.domain.com/trucks/123 or www.domain.com/trucks/ford
Deuxième solution Utilisez l'hôte de service de la (c.-à-la WebServiceHost2Factory) REST Starter Kit de.
RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHost2Factory(), typeof(CarService)));
Cela ne donne pas lieu à une 307 redirect lorsque vous utilisez les URIs que vous essayez d'utiliser ci-dessus et donc, vous donne exactement ce dont vous avez besoin. Bien que je me rends compte que ça fait un peu bizarre en utilisant cette usine d'accueil de service plutôt que celui qui est livré avec 4 WCF.
Autres conseils
Vous avez besoin d'un UriTemplate, Essayez quelque chose comme ceci:
[ServiceContract()]
public interface ICarService
{
[OperationContract]
[WebGet(UriTemplate = "/Car")]
CarPool GetAllCars();
[OperationContract]
[WebGet(UriTemplate = "/Car/{carName}")]
Car GetCar(string carName);
}
Essayez de mettre cela dans le 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
}
}
J'étais face à ce problème exact et a couru à travers cet extrait dans les MS docs en ligne:
Par défaut, le routage ne gère pas les demandes de cette carte à un fichier physique existant sur le serveur Web. Par exemple, une demande de http: //server/application/Products/Beverages/Coffee.aspx est pas gérée par le routage si un fichier physique existe à Produits / Boissons / Coffee.aspx. Routage ne gère pas la demande même si elle correspond à un modèle défini, tel que {contrôleur} / {action} / {id}.
Je réalise que mon modèle de route correspond le répertoire a été mon service hébergé dans. Il semble qu'un répertoire est traité comme un fichier physique, et les modèles d'itinéraire qui correspondent à un répertoire sont ignorés aussi bien. Ainsi, suite à la documentation, je mets la propriété RouteExistingFiles « true » sur le RouteCollection. Mon service semble maintenant acheminer les demandes correctement et je l'ai été en mesure de garder la syntaxe REST que j'aime très beaucoup.
question plus ancien, mais voici comment je l'ai résolu le problème avec un service REST WCF4 (en utilisant le RouteTable dans Global.asax ajouter ServiceRoutes). IIS7 est configuré de telle sorte qu'au moment où le service est appelé j'ai un chemin relatif vide de sorte que le UriTemplate de méthode de gestion est vide comme l'exemple de voiture de Will. J'ai utilisé une règle de réécriture dans le fichier web.config du service pour ajouter un « / » si nécessaire. Il correspond toujours le chemin vérifie ensuite l'original URI ({REQUEST_URI}) pour voir si elle contient un chemin sans fuite « /".
<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 peu plus réutilisable:
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);
}
}
Essayez de changer votre code dans le Global.asax de ...
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)));