特定LifeStyle的简单注射器范围

时间:2014-08-26 12:40:53

标签: c# dependency-injection ioc-container simple-injector

有没有办法为特定的生活方式定义范围?我试图实现我想要在应用程序中持久化的我自己的作用域,但在内部我也创建了另一个作用域,然后请求GetInstance返回内部作用域实例。

我想如果我可以将我的生活方式定义为:

public class MyScopedLifestyle : ExecutionContextScopeLifestyle
{
    public MyScopedLifestyle(bool disposeInstanceWhenScopeEnds)
        : base("MyScopedLifestyle", disposeInstanceWhenScopeEnds)
    {
    }

    protected override int Length
    {
        get
        {
            return 100;
        }
    }
}

我的用法是:

var container = new Container();
container.Register<IRequestData, RequestData>(new MyScopedLifestyle());

// i had hoped I could say
//   container.BeginExecutionContextScope(MyScopedLifestyle)
// or something similar
// this is controlled by me
using (var scope1 = container.BeginExecutionContextScope())
{
    // do some stuff
    container.GetInstance<IRequestData>().RequestMarket = "en-US";

    // this is done via the webapi execution scope (using simpleinjector dependency resolver)
    using (var scope2 = container.BeginExecutionContextScope())
    {
        Assert.Equal("en-US", container.GetInstance<IRequestData>().RequestMarket); // false
    }
}

但我不确定如何在创建内部执行范围时利用我的自定义生活方式。

我真正想要发生的是,我在scope1中使用的IRequestData实例与scope2中的IRequestData实例相同。这是我用SimpleInjector可以实现的吗?

修改 我删除了这样一个事实,即我尝试按OWIN请求创建对象实例,而不是每个WebAPI请求。理想情况下,我试图创建:

container.RegisterOwinRequest<IRequestData, RequestData>();

因此,当我在管道中的任何地方解析IFoo时(无论是OWIN中间件,还是WebAPI部分,都会针对特定请求返回相同的实例)。

编辑2 为了更好的名字,我们改变了我们的IFoo / Foo / MyProperty。

1 个答案:

答案 0 :(得分:2)

您尝试使用自定义生活方式完成的任务绝对可能,但可能并不那么容易,因为您必须将该范围存储在某处(可能在CallContext中)并且需要创建一个{ {1}}方法,用于创建新范围并具有自定义BeginMyCustomScope实现,该实现在调用Scope时将自己从CallContext中删除。我认为这是太多的工作和太多的复杂性。

存在问题是因为在您想要设置Dispose属性期间,没有启动Web API请求范围。通常强制启动此范围的方法是在RequestMarket上调用GetDependencyScope方法:

HttpRequestMessage

在此之后,您可以解析message.GetDependencyScope(); 并按预期工作:

IRequestData

但是我不确定container.GetInstance<IRequestData>().RequestMarket = "en-US"; 是否在那个时间点可用,所以如果没有,我认为在评论中表达的HttpRequestMessage是一个很好的选择。< / p>

过去,在callstack之间传递数据的好方法是使用特定于线程的变量,但是当使用async / await模型时,与Web API和OWIN一样,这显然会失败。因此,执行此操作的新方法是使用DelegatingHandler。因此,您可以执行以下操作,而不是使用CallContext

DelegatingHandler

当OWIN请求开始时,你这样做:

container.RegisterInitializer<IRequestData>(data =>
    data.RequestMarket = (string)CallContext.LogicalGetData("RequestMarketKey"));