5

私は MVC4 Web API プロジェクトを持っており、Mark Seemann のHyprlinkrコンポーネントを利用して、リンクされたリソースへの Uris を生成しています。(顧客 -> 住所など)。

Web API を使用した依存性注入に関する Mark のガイド (Ninject に合わせて適切に変更) には既に従いましたが、コントローラーにIResourceLinkerを注入するために何をすべきかがよくわかりません。

マークのガイドに従って、私のIHttpControllerActivator.Create作成メソッドは次のようになります。

IHttpController IHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
    var controller = (IHttpController) _kernel.GetService(controllerType);

    request.RegisterForDispose(new Release(() => _kernel.Release(controller)));

    return controller;
}

Hyperlinkr のreadme で RouteLinker作成が提案されているのは、このメソッドです。残念ながら、これを Ninject に登録する方法がわかりません。

複数のバインディングが発生するため、以下のようにバインドすることはできません。

_kernel.Bind<IResourceLinker>()
    .ToMethod(context => new RouteLinker(request))
    .InRequestScope();

私は次のように再バインドを行いました:

_kernel.Rebind<IResourceLinker>()
    .ToMethod(context => new RouteLinker(request))
    .InRequestScope();

しかし、ninject バインディング グラフを変更することは、すべてのリクエストで実行するのが悪いことである可能性があることを懸念しています。

これを達成するための最良の方法は何ですか?


Paige Cookからのリクエストに応じて更新

ここで再バインドを使用しています:

IHttpController IHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
    _kernel.Rebind<IResourceLinker>()
        .ToMethod(context => new RouteLinker(request))
        .InRequestScope();

    var controller = (IHttpController) _kernel.GetService(controllerType);

    request.RegisterForDispose(new Release(() => _kernel.Release(controller)));

    return controller;
}

IHttpControllerActivator.Createは、すべての要求で呼び出されます。残りのバインディングは標準的な方法で作成されます。つまり、標準とは、Ninject.MVC3 nuget パッケージを使用して生成されたクラスを意味します。

私のコントローラーは次のようになります。

public class CustomerController : ApiController
{
    private readonly ICustomerService _customerService;
    private readonly IResourceLinker _linker;

    public CustomerController(ICustomerService customerService, IResourceLinker linker)
    {
        _customerService = customerService;
        _linker = linker;
    }

    public CustomerModel GetCustomer(string id)
    {
        Customer customer = _customerService.GetCustomer(id);
        if (customer == null)
        {
            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
        }

        return
            new CustomerModel
                {
                    UserName       = customer.UserName,
                    Firstname      = customer.Firstname,
                    DefaultAddress = _linker.GetUri<AddressController>(c => c.Get(customer.DefaultAddressId)),
                };
    }
}
4

3 に答える 3

6

デリゲート関数を登録して、リンカーを提供します

_kernel.Bind<Func<HttpRequestMessage, IResourceLinker>>()
    .ToMethod(context => (request) => new RouteLinker(request));

デリゲートを注入する

readonly Func<HttpRequestMessage, IResourceLinker> _getResourceLinker;

public controller(Func<HttpRequestMessage, IResourceLinker> getResourceLinker) {

    _getResourceLinker = getResourceLinker;
}

アクションで使用する

public async Task<Thingy> Get() {

    var linker = _getResourceLinker(Request);
    linker.GetUri( ... )

}
于 2012-10-15T12:22:40.763 に答える
4

ApiController 派生物から RouteLinker を使用するだけでよい場合は、実際にすべての DI フープを通過する必要はありません。

次のようにコントローラー内で作成できます。

var linker = new RouteLinker(this.Request);

IMO、 RouteLinkerで DI を使用することは、RouteLinker がスタックのさらに下に必要な場合に最初に価値があります。

于 2012-10-15T20:59:55.827 に答える
2

コードサンプルを追加していただきありがとうございます。投稿した内容に基づいて、毎回メソッドで を発行_kernel.Bind<IResourceLinker>しているため、Bind/Rebind の問題が発生しています。IHttpControllerActivtor.Create

_kernel.Bind<IResourceLinker>残りのバインディングを

...標準的な方法、標準では、Ninject.MVC3 nuget パッケージを使用して生成されたクラスを意味します。

を複数回バインドする必要はありません。IResourceLinkerこれが、IHttpControllerActivator によってコントローラーが作成されるたびにバインドが起動されるため、複数のインスタンスを取得する理由です。

更新:コンストラクターの引数として の必要性を逃して申し訳ありませんHttpRequestMessage。これに関するAnthony Johnsonの回答を使用します。

于 2012-10-15T13:39:03.553 に答える