-->

How do I use Ninject with ActionResults while maki

2019-03-31 10:21发布

问题:

Nearly all of the Ninject examples I've seen explain how to use it with ASP.NET MVC, which will automatically inject dependencies into controllers. How would I use Ninject manually though? Let's say I have a custom ActionResult:

public class JsonResult : ActionResult
{
    [Inject] public ISerializer Serializer { get; set; }

    public JsonResult(object objectToSerialize)
    {
        // do something here
    }

    // more code that uses Serializer
}

Then in my controller, I'm using JsonResult in a method like this:

public ActionResult Get(int id)
{
    var someObject = repo.GetObject(id);
    return new JsonResult(someObject);
}

As you can see, I'm instantiating the object myself, which sidesteps Ninject's injection, and Serializer will be null. However, doing it the following way doesn't seem quite right to me:

public ActionResult Get(int id)
{
    var someObject = repo.GetObject(id);
    return IoC.Kernel.Get<JsonResult>(someObject);
}

Because now there's not only a dependency on Ninject in the controller, but I also have to expose the Ninject kernel in a static class/singleton and ensure that objects that rely on injection are only created via kernel.

Is there a way to somehow configure Ninject to inject the dependency without relying on exposing the kernel? I'd like to be able to use the new keyword if at all possible.

回答1:

Use a factory that gets the kernel injected: E.g.

public class ResultFactory : IResultFactory
{
    public ResultFactory(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public JsonResult CreateJsonResult(object obj)
    {
        var result = this.kernel.Get<JsonResult>();
        result.ObjectToSerialize = obj;
        return result;
    }
}

Inject this factory into the controller and use it to create your action results.



回答2:

I think you should turn your JsonResult inside out:

public class JsonResult : ActionResult
{
    public ISerializer Serializer { get; private set; }

    public object ObjectToSerialize { get; set; }

    public JsonResult(ISerializer serializer)
    {
        this.Serializer = serializer;
    }

    // more code that uses Serializer
}

This way you can retrieve the JsonResult with the container like this:

public ActionResult Get(int id)
{
    var result = IoC.Kernel.Get<JsonResult>();

    result.ObjectToSerialize = repo.GetObject(id);

    return result;
}

Changing the signature of the JsonResult also enables Ninject to create an instance automatically. Because of this you can let Ninject automatically inject it as dependency into your controller:

public MyController(JsonResult result)
{
    this.result = result;
}

public ActionResult Get(int id)
{
    this.result.ObjectToSerialize = repo.GetObject(id);

    return this.result;
}