5

我有一个 MVC4 Web API 项目,我利用 Mark Seemann 的Hyprlinkr组件生成链接资源的 Uris。(例如客户 -> 地址)。

我已经按照 Mark 的关于使用 Web API 进行依赖注入的指南(针对 Ninject 进行适当更改)进行操作,但我不太清楚应该如何将IResourceLinker注入到我的控制器中。

按照 Mark 的指南,我的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;
}

Hyprlinkr 自述文件建议在这种方法中创建RouteLinker。不幸的是,我不确定如何使用 Ninject 注册它。

我不能像下面这样绑定,因为这会导致多个绑定:

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

我有这样的重新绑定工作:

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

但我担心更改 ninject 绑定图对于每个请求都可能是一件坏事。

实现这一目标的最佳方法是什么?


应佩奇库克的要求更新

我在这里使用重新绑定:

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

您可以像这样在 Controller 中创建它:

var linker = new RouteLinker(this.Request);

IMO,当您需要 RouteLinker 进一步降低堆栈时,首先将 DI 与 RouteLinker 一起使用变得很有价值 - 但话又说回来,我也只使用 RouteLinker 作为具体依赖项......

于 2012-10-15T20:59:55.827 回答
2

感谢您添加代码示例。根据您发布的内容,您遇到了绑定/重新绑定问题,因为您每次都_kernel.Bind<IResourceLinker>在方法中发出。IHttpControllerActivtor.Create

您需要以与_kernel.Bind<IResourceLinker>

...标准方式,标准我的意思是在使用 Ninject.MVC3 nuget 包生成的类中。

不需要IResourceLinker多次绑定 ,这就是您获得多个实例的原因,因为每次 IHttpControllerActivator 创建控制器时都会触发绑定。

更新: 抱歉,我错过了HttpRequestMessage作为构造函数参数的需要,我会选择 Anthony Johnson 对此的回答。

于 2012-10-15T13:39:03.553 回答