【问题标题】:How to have SimpleInjector resolve viewmodel dependencies?如何让 SimpleInjector 解决视图模型依赖项?
【发布时间】:2015-06-10 02:38:16
【问题描述】:

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

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

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

我对 CreateUserRequest 类做了以下更改:

public class CreateUserRequest : IValidatableObject
{
    private readonly CreateUserRequestValidator validator;

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

    // ...
}

所以,我将接口更改为具体类,但我仍然在那里收到 null。

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

感谢任何帮助解决这个问题。谢谢。

--更新--

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

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

【问题讨论】:

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


【解决方案1】:

您的视图模型对象没有被 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 描述的那样。

【讨论】:

  • 这确实是我的问题的答案。正因为如此,学习了很多 web api 的管道和可扩展性。感谢您对架构的关注。我将修改我的课程。谢谢。
猜你喜欢
  • 2014-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-18
  • 1970-01-01
  • 2018-08-25
  • 1970-01-01
  • 2015-07-16
相关资源
最近更新 更多