如何让 SimpleInjector 解析视图模型依赖项?

How to have SimpleInjector resolve viewmodel dependencies?

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

我在尝试为同一个项目的 MVC 和 Web API 设置它时遇到了一些问题,直到我发现这个 link:

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

按照 link 的示例进行操作后,我得到了以下结果:

我的一个 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 class 本身有依赖关系。

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 是 Fl​​uentValidator 包中的一个接口。

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

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

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

public class CreateUserRequest : IValidatableObject
{
    private readonly CreateUserRequestValidator validator;

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

    // ...
}

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

我唯一能想到的是,这在某种程度上与上述 link 建议的自定义依赖解析器有关。我需要使用它,以便为 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 背后的很多管道(特别是自定义依赖项解析器功能),所以,我真的被困在这一点上。

感谢您帮助我解决这个问题。谢谢。

--更新--

除了Steven给出的答案,我想给遇到同样问题的人一个link。这是一个很好的资源:

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

视图模型对象未被简单注入器自动连接的原因是 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 所述的消息传递架构。