Asp.net web api 简单注入器:依赖于http请求的实现

Asp.net web api 简单注入器:依赖于http请求的实现,asp.net-web-api,dependency-injection,inversion-of-control,simple-injector,Asp.net Web Api,Dependency Injection,Inversion Of Control,Simple Injector,我是一个简单注射器的初学者,有一个需要帮助实现的场景。我会尽量简化我需要做的事情 我有一个WebAPI,需要对用户进行身份验证,并根据用户类型选择实现 以这种结构为例 public interface ICarRepository { void SaveCar(Car car); } //Some implementation for ICarRepository public interface ICarLogic { void CreateCar(Car car); }

我是一个简单注射器的初学者,有一个需要帮助实现的场景。我会尽量简化我需要做的事情

我有一个WebAPI,需要对用户进行身份验证,并根据用户类型选择实现

以这种结构为例

public interface ICarRepository {
    void SaveCar(Car car);
}

//Some implementation for ICarRepository

public interface ICarLogic {
    void CreateCar(Car car);
}

public class CarLogicStandard: ICarLogic {
    private ICarRepository _carRepository;

    public CarLogicStandard(ICarRepository carRepository) {
        _carRepository = carRepository;
    }

    public void CreateCar(Car car) {
        car.Color = "Blue";
        _carRepository.SaveCar();
        //Other stuff...
    }
}

public class CarLogicPremium: ICarLogic {
    private ICarRepository _carRepository;

    public CarLogicPremium(ICarRepository carRepository) {
        _carRepository = carRepository;
    }

    public void CreateCar(Car car) {
        car.Color = "Red";
        _carRepository.SaveCar();
        //Other stuff 2...
    }

}
现在我有了一个控制器

public class CarController: ApiController {
    private ICarLogic _carLogic;
    public CarController(ICarLogic carLogic) {
        _carLogic = carLogic;
    }

    public void Post(somePostData) {
        //Identify the user based on post data
        //....

        Car car = somePostData.SomeCar();
        _carLogic.CreateCar(car);
    }


}
上面的代码将不起作用,因为在我的请求中,我需要标识用户。如果是高级用户,控制器应使用CarLogicPremium;如果是标准用户,控制器应使用CarLogicStandard

我可以在Global.asax上配置不需要此逻辑的存储库和其他接口。但是,由于这种情况下我需要请求来决定应该使用哪种实现,因此我建议我需要以其他方式解决此问题


有一种“简单的喷油器”方法来处理这个问题吗?还是我应该尝试另一种方法

最简单的解决方案是在中配置决策,以及容器的其余配置:

受保护的无效应用程序\u Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
var container=新容器();
container.Register();
container.Register();
container.registerWebRequest();
集装箱。登记(
() =>
HttpContext.Current!=null&&
HttpContext.Current.User!=null&&
HttpContext.Current.User.IsInRole(“高级”)
?(ICarLogic)容器。GetInstance()
:(ICarLogic)container.GetInstance()
);
//这是集成包中的扩展方法。
容器.RegisterWebApp控制器(全局配置.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver=
新的SimpleInjectorWebApidencyResolver(容器);
}
您还可以为当前用户创建一个抽象,并用高级功能装饰标准功能

公共类CarLogicPremium:ICarLogic
{
私人只读ICarLogic;
专用只读ICurrentUser currentUser;
私人只读易读存储;
公共图书馆(
伊卡洛斯,
ICurrentUser当前用户,
i沉淀(沉淀)
{
这是装饰过的;
this.currentUser=currentUser;
this.carRepository=carRepository;
}
公共汽车
{
if(currentUser.ispremiummber)
{
car.Color=“Red”;
这个。carRepository。SaveCar(car);
//其他资料2。。。
}
其他的
{
这个。装饰。创造汽车(汽车);
}
}
}
它的配置有点像这样

受保护的无效应用程序\u Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
var container=新容器();
container.Register();
container.registerWebRequest();
container.Register();
容器注册检测器(类型为(ICarLogic),类型为(CarLogicPremium));
容器.RegisterWebApp控制器(全局配置.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver=
新的SimpleInjectorWebApidencyResolver(容器);
}

但这实际上取决于随着时间的推移,您将创建多少不同的服务。如果您将不断添加新的高级功能,您应该考虑实现Try-X模式的变体。让我知道上述其中一项是否适用于您,或者您是否需要更多信息…

为什么不使用工厂来解决
ICarLogic
接口的所需实现?老实说,你不应该仅仅因为用户类型而有两种不同的实现,如果你最终添加了更多的用户类型呢?嘿,谢谢你的帮助。您会推荐什么来代替接口实现?您是对的,将存在更多的用户类型,其中一些将需要更改某些类的行为。。。我应该为每个不同的行为创建不同的界面吗?嗨,谢谢你的帮助。回答很好,但是我在这一行遇到了一个问题:(ICarLogic)container.GetInstance()“CarLogicPremium类型的注册委托引发了一个异常。无法拦截CarLogicPremium类型,因为它不是一个接口。”即使注册CarLogicPremium,您知道为什么吗?@Rafael您通常使用的是,我的建议是,在构建对象图期间,不要对运行时数据做出决策。因此,我不建议@qujck给出第一个答案,但我同意他的第二个建议:使用一个facade/proxy/decorator,通过正确的实现进行委托。@qujck是的,我在我的项目上有拦截扩展。是它导致了问题吗?@qujck是的,我对拦截进行了评论,效果很好。因为这只是一个练习的例子,如果这个问题发生在一个有意义的场景中,我将在稍后研究它。非常感谢两种解决方案!