如何让SimpleInjector解析viewmodel依赖?

时间:2015-06-10 02:38:17

标签: asp.net-mvc asp.net-web-api dependency-injection simple-injector

我试图在Asp.Net MVC + Web API应用程序中使用SimpleInjector 2.7.3(IoC容器)。

我尝试在同一个项目中为MVC和Web API设置它时遇到了一些问题,直到找到此链接:

http://methoddev.com/blg/let-s-talk-software/310/simple-injector-in-asp-net-mvc-webapi

按照链接的示例,这是我得到的:

我的一个Web API控制器:

public class UserController : BaseApiController
{
    private readonly IUserService service;

    public UserController(IUserService userService)
    {
        // I should point that IUserService is being injected correctly here
        this.service = userService;
    }

    public IHttpActionResult Post(CreateUserRequest request)
    {
        return Ok();
    }
}

当我尝试执行Post操作时会发生问题。 CreateUserRequest 类本身具有依赖关系。

public class CreateUserRequest : IValidatableObject
{
    private readonly IValidator<CreateUserRequest> validator;

    public CreateUserRequest(IValidator<CreateUserRequest> _validator)
    {
        // _validator is not being injected, I'm getting null here
        validator = _validator;
    }

    public string SomeProperty { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        // My validation logic here must call the validator injected
        // when the object was created.
        return null;
    }
}

我应该指出 IValidator 是来自FluentValidator包的接口。

无论如何,当 CreateUserRequest 被实例化时,验证器为空,这意味着它没有被注入。

当我创建SimpleInjector容器时,我可以看到正确注册的类型,所以我不认为这是一个问题。

我对 CreateUserRequest 类进行了以下更改:

public class CreateUserRequest : IValidatableObject
{
    private readonly CreateUserRequestValidator validator;

    // Changed here to the concrete class
    public CreateUserRequest(CreateUserRequestValidator _validator)
    {
        validator = _validator;
    }

    // ...
}

所以,我将界面更改为具体类,我仍然在那里收到空。

我唯一能想到的是,这与上述链接建议的自定义依赖项解析器有某种关系。我需要使用它来为MVC和Web API提供相同的依赖关系解析逻辑。这是代码:

public class SimpleInjectorDependencyResolver : System.Web.Mvc.IDependencyResolver,
  System.Web.Http.Dependencies.IDependencyResolver,
  System.Web.Http.Dependencies.IDependencyScope
{
    public SimpleInjectorDependencyResolver(Container container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }

        this.Container = container;
    }

    public Container Container { get; private set; }

    public object GetService(Type serviceType)
    {
        if (!serviceType.IsAbstract && typeof(IController).IsAssignableFrom(serviceType))
        {
            return this.Container.GetInstance(serviceType);
        }

        return ((IServiceProvider)this.Container).GetService(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return this.Container.GetAllInstances(serviceType);
    }

    IDependencyScope System.Web.Http.Dependencies.IDependencyResolver.BeginScope()
    {
        return this;
    }

    object IDependencyScope.GetService(Type serviceType)
    {
        return ((IServiceProvider)this.Container).GetService(serviceType);
    }

    IEnumerable<object> IDependencyScope.GetServices(Type serviceType)
    {
        return this.Container.GetAllInstances(serviceType);
    }

    void IDisposable.Dispose()
    {
    }
}

我不太了解MVC和Web API背后的许多管道(特别是自定义依赖项解析器功能),所以,我真的坚持这个。

我很感激任何有用的帮助。感谢。

- UPDATE -

除了史蒂文给出的答案之外,我想留下一个链接到遇到同样问题的人。这是一个很好的资源:

https://brettedotnet.wordpress.com/2014/07/16/web-api-and-interface-parameters/

1 个答案:

答案 0 :(得分:2)

您的视图模型对象未被Simple Injector自动连接的原因是因为MVC和Web API都不使用IDependencyResolver构建视图模型对象。所以创建一个特殊的依赖解析器不会起作用。如果要让视图模型自动连接,则必须覆盖MVC和Web API中的默认模型绑定器。

但我劝你不要这样做。在我看来,模型绑定器应该只进行数据转换,视图模型应该是普通的DTO。虽然可以使用验证属性标记视图模型,但让我们使用可能甚至触发任何数据库通信的服务的行为在我的书中是一个很大的禁忌。这可能会使开发变得非常复杂。

然而,这意味着该验证器应注入其他地方。如果不对您的体系结构进行任何更改,这基本上意味着您必须在控制器中注入该验证器:

public class UserController : BaseApiController
{
    private readonly IUserService service;
    private readonly IValidator<CreateUserRequest> validator;

    public UserController(IUserService userService,
        IValidator<CreateUserRequest> validator)
    {
        this.service = userService;
        this.validator = validator;
    }
}

显然,这可能很容易使控制器具有额外的依赖关系和逻辑,但这是因为验证是一个跨领域的问题,您可能希望远离控制器。

如果你试图解决这个问题,你最终会得到一个消息传递架构,如描述here