1

リソース表現へのリンクの追加は、Web API コントローラー内で非常に簡単に実行できます。コントローラーのUrlプロパティ (UrlHelperクラス) を使用すると、次のように、ルート名を使用してリンクの href を構築できます。

var href = Url.Link("RouteName", new { id = 123 });

の値はhrefルート構成に基づいて計算されます。この場合は のようなものhttp://example.org/api/products/123です。href が生成されるすべての場所を更新する必要なく、ルート構成を調整できるため、これは素晴らしいことです。発行されたすべてのリンクは、新しい構成に準拠しています。

しかし、これ、または同様のルートベースの手法を使用して、テンプレート化されたhref を作成できますか? たとえば、HAL のtemplatedリンク プロパティを使用して、リソースから任意の製品へのリンクを作成するには、次のようにします。

"_links": {
  "self": {
    "href": "http://example.org/api/productfinder"
  },
  "product": {
    "href": "http://example.org/api/products/{productId}",
    "templated": true
  }  
}

(私は実際には productfinder と呼ばれるリソースを持っていません - この質問の不自然な例です)。

routeValuesパラメータをテンプレートの文字列に設定しようとしました。

var href = Url.Link("RouteName", new { id = "{productId}" });

これにより、URL エンコードされた文字列が生成されます: http://example.org/api/products/%7BproductId%7D. を使用できます.Replaceが、このアプローチは別の理由で失敗します。ルート構成にタイプの制約がある場合、たとえば{id:int}、href は null になります。

routeValuesテンプレート部分を追加できることを期待 して null を渡そうとしました。Link()null を返したのでhref、テンプレート部分だけになってしまいました。さらに、これは次のような複雑なルートでは機能しませんapi/{this}/something/{that}{?q}

だから私は立ち往生しています。ルートを使用してテンプレート化された href を生成できますか? もしそうなら、どのように?

4

1 に答える 1

2

わかりました、少し時間がかかりましたが、うまくいくものがあります。秘訣はRouteTemplate、構成のルート テーブルから を検索することです。各コントローラーには、構成への参照があります。そこからはかなり簡単でした。

への拡張クラスを作成しましたApiController。実際には、おそらくサブクラス化ApiControllerしますが、考え方は同じです。また、 をUri使用する代わりにオブジェクトを返す場合もあります.ToString()

public static class ApiControllerExtensions
{
    public static string GetTemplatedHref(this ApiController controller, string routeName, string controllerName = "")
    {
        var routeTemplate = controller.Configuration.Routes[routeName].RouteTemplate;

        var baseUri = new Uri(controller.Request.RequestUri.GetLeftPart(UriPartial.Authority));
        var templatedHref = new Uri(baseUri, routeTemplate).ToString();

        return string.IsNullOrEmpty(controllerName) ? 
            templatedHref : 
            templatedHref.Replace("{controller}", controllerName.ToLower());
    }
}

さて、コントローラーのメソッド内でテンプレート化された href が必要な場合は、次のようにできます。

var href = this.GetTemplatedHref("RouteName");

これは、ルート属性でうまく機能します。また、事前に構成されたルートでも機能します。たとえば、次のようになります。

config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

したがって、コントローラー名を指定して、次のようにテンプレート化された href を取得できます。

var href = this.GetTemplatedHref("DefaultApi", "product");

ここでも実際には、絶対/相対のオプションを追加するなど、変更と微調整を行います。しかし、ルート名を使用してテンプレートを取得するという中心的な問題は解決されました。

于 2014-09-24T21:19:56.463 に答える