【问题标题】:unity resolve instance at web api controllerweb api控制器上的统一解析实例
【发布时间】:2019-02-07 17:32:55
【问题描述】:

有没有办法在控制器级别解析类的实例?我想覆盖之前由 unity 创建的实例,并通过控制器分配这个新值。

问题是我不确定如何访问网络应用控制器中的统一容器。

这是我的代码:

存储库:

public class UserRepository: IUserRepository
{
    private UserInformation _userInfo; 
    public UserRepository(string headerValue)
    {       
        _userInfo = LoadUserData(headerValue);
    }

    public UserInformation GetUserInfo()
    {       
        return _userInfo;
    }
}

public class UserInformation
{
      public string FirstName;
      public string LastName;
}

统一配置:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        //Some code omitted
        config.DependencyResolver = new UnityDependencyResolver(UnityConfig.RegisterComponents());            
    }
}

public static class UnityConfig
{
    public static UnityContainer RegisterComponents()
    {
        //Unity Configuration
        var container = new UnityContainer();

        container.RegisterType<IUserRepository, UserRepository>(new InjectionConstructor("DummyHeaderValue"));          
        return container;
    }
}

控制器:

public class CustomerController : ApiController
{   
    public CustomerController()
    {
        //Something like this
        container.Resolve<UserRepository>(new InjectionConstructor(Request.GetHeader("RealHeaderValueFromHttpRequest")));
    }   
}

那么我应该能够在整个应用程序中使用更新后的UserRepository 实例。

关于如何实现这一点的任何想法?

编辑: 正如@Nkosi 所指出的,我无权访问控制器构造函数中的请求。所以让我重新表述一下我的问题:

如何使用包含当前用户详细信息的 UserInformation 对象初始化 UserRepository?我想这样做的原因是,在我的整个应用程序中,我想要用户详细信息,并且我不想从每个方法中传递用户 ID

类似这样:从整个应用程序中的任何方法

UserInformation obj = _userRepository().GetUserInfo();

【问题讨论】:

  • 当您应该使用显式依赖原则并将依赖注入构造函数时,您正在使用服务定位器模式。 public CustomerController(IUserRepository repository) { ... }
  • 另请注意,在控制器的构造函数中访问时,请求尚不可用。您将需要重新考虑存储库和控制器的设计。
  • 我的主要目标是使用统一的 Http 请求标头中的值初始化 UserRepository 构造函数。有什么想法吗?
  • 我明白你想做什么。我要告诉你的是,在初始化存储库时,你将无法访问构造函数中的请求。

标签: c# asp.net-web-api dependency-injection unity-container


【解决方案1】:

创建一个抽象来访问请求

public interface IHeaderService {
    string RealHeaderValueFromHttpRequest();
}

它的实现将有权访问上下文并请求获得所需的功能

public class HeaderService : IHeaderService {
    public string RealHeaderValueFromHttpRequest() {
        return HttpContext.Current.Request.Headers["RealHeaderValueFromHttpRequest"];
    }
}

该服务现在将被显式注入到依赖存储库中

public class UserRepository: IUserRepository {
    private readonly IHeaderService headerService;

    public UserRepository(IHeaderService headerService) { 
        this.headerService = headerService;
    }

    public UserInformation GetUserInfo() {
        var headerValue = headerService.RealHeaderValueFromHttpRequest();
        var _userInfo = LoadUserData(headerValue);
        return _userInfo;
    }

    //...
}

该存储库也将被显式注入到依赖的控制器中。

public class CustomerController : ApiController {
    private readonly IUserRepository repositoty;

    public CustomerController(IUserRepository repositoty) {
        this.repository = repository;        
    }

    public IHttpActionResult SomeAction() {
        //NOTE: Only access user info in a controller action
        var userInfo = repository.GetUserInfo();

        //... use user info.
    }

    //...
}

现在剩下的就是确保所有抽象及其实现都注册到依赖容器中

public static class UnityConfig {
    public static UnityContainer RegisterComponents() {
        //Unity Configuration
        var container = new UnityContainer();

        container.RegisterType<IUserRepository, UserRepository>();
        container.RegisterType<IHeaderService, HeaderService>();

        return container;
    }
}

【讨论】:

  • 看起来不错!我会尽力让你知道。虽然我有一个问题,有什么办法可以使用HttpRequestMessage 而不是HttpContext.Current.Request。就好像我使用前一个一样,我将无法通过集成测试端到端测试我的代码(我正在使用 OWIN 自托管进行集成测试)。
  • @Shaggy 我只是用它作为一个简单的例子。您应该能够使用 Owin 提取当前的 HttpRequestMessage。
  • @Shaggy 在测试时也可以模拟服务抽象而不是使用耦合实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-09
  • 1970-01-01
  • 1970-01-01
  • 2014-07-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多