WCFの単純なURLルートは、トレーリングスラッシュなしで4.0休憩します
質問
WCFレストサービステンプレート40(CS)に基づいたWCF REST 4.0プロジェクトがあります。簡単なサービスエンドポイントURLを公開したいと思います それなし トレーリングスラッシュ。例えば:
- carservice.cs
- http://www.domain.com/cars - すべての車のリストを返します
- http://www.domain.com/cars/123 -ID123で1台の車を返します
- Truckservice.cs
- http://www.domain.com/trucks - すべてのトラックのリストを返します
- http://www.domain.com/trucks/456 -ID456の単一トラックを取得します
上記のURLをリソースリクエスト(ディレクトリではなく)として見ています。そのため、ここではトレーリングスラッシュが適切であるとは思わないのです。
残念ながら、私は常に /車にリダイレクトされているので、私は望む行動を得ることができないようです /および /トラック / と 後続のスラッシュ。
「車」ルートとサービスの方法を定義した方法は次のとおりです。ルートまたは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 /aboutにリダイレクトなし。 WCF REST 4.0で同じ動作を取得するにはどうすればよいですか?
解決
あなたが遭遇している主な問題は、 現在 WCF RESTのバージョンは、Webget属性にUritemplateの空の文字列がある場合、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);
これにより、次のようになります。
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
2番目のソリューションからサービスホストを使用します レストスターターキット (つまり、WebServiceHost2Factory)。
RouteTable.Routes.Add(new ServiceRoute("cars", new WebServiceHost2Factory(), typeof(CarService)));
これは、上記で使用しようとしているURIを使用している場合、307リダイレクトをもたらすことはありません。したがって、必要なものを正確に提供します。私は、WCF 4に出荷するものではなく、そのサービスホストファクトリーを使用して少し奇妙に感じていることに気付きますが。
他のヒント
Uritemplateが必要です。次のようなものを試してみてください。
[ServiceContract()]
public interface ICarService
{
[OperationContract]
[WebGet(UriTemplate = "/Car")]
CarPool GetAllCars();
[OperationContract]
[WebGet(UriTemplate = "/Car/{carName}")]
Car GetCar(string carName);
}
これを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
}
}
私はこの正確な問題に対処していて、MSオンラインドキュメントでこのスニペットに出くわしました。
デフォルトでは、ルーティングは、Webサーバー上の既存の物理ファイルにそのマップをマップするリクエストを処理しません。たとえば、のリクエスト http://server/application/products/beverages/coffee.aspx 製品/Beverages/Coffee.aspxに物理ファイルが存在する場合、ルーティングによって処理されません。ルーティングは、{controller}/{action}/{id}などの定義されたパターンと一致していても、リクエストを処理しません。
私のルートパターンが私のサービスがホストされているディレクトリと一致していることに気付きました。ディレクトリは物理ファイルと同じように扱われ、ディレクトリに一致するルートパターンも無視されているようです。そのため、ドキュメントに従って、RouteexistingFilesプロパティをRouteCollectionで「True」に設定しました。私のサービスは今ではリクエストを正しくルーティングしているようで、私はとても大好きな残りの構文を維持することができました。
古い質問ですが、WCF4 RESTサービスで問題を解決した方法は次のとおりです(global.asaxでserviceroutesを追加するためにルーテット可能なものを使用)。 IIS7は設定されているため、サービスが呼び出されるまでに空の相対パスがあるため、Willの車の例のように処理方法のUritemplateが空になります。サービスの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>
もう少し再利用可能:
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);
}
}
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)));