使用Unity在多个类型中注入相同的DataContext实例

时间:2009-05-22 10:15:13

标签: c# dependency-injection unity-container datacontext

假设我有IRepository接口及其实现SqlRepository,它将LINQ作为参数作为SQL DataContext的参数。假设我有IService接口及其实现服务,它需要三个IRepository,IRepository和IRepository。演示代码如下:

public interface IRepository<T> { }

public class SqlRepository<T> : IRepository<T>
{
    public SqlRepository(DataContext dc) { ... }
}

public interface IService<T> { }

public class Service<T,T1,T2,T3> : IService<T>
{
    public Service(IRepository<T1> r1, IRepository<T2>, IRepository<T3>) { ... }
}

在创建Service类以使用相同的DataContext注入所有三个存储库时是否有任何方法?

4 个答案:

答案 0 :(得分:7)

您需要做的就是确保当您使用Unity容器注册Datacontext时,请在config中使用PerResolveLifetimeManager

<type type="<namespace>.DataContext, <assembly>">
    <lifetime type="Microsoft.Practices.Unity.PerResolveLifetimeManager, Microsoft.Practices.Unity" />
</type>

或代码:

container.RegisterType<DataContext>(new PerResolveLifetimeManager());

然后,只要容器解析Service任何依赖项,同样需要DataContext的依赖项将提供完全相同的依赖项。但下一个解决Service的请求将创建一个新的DataContext

答案 1 :(得分:3)

我想我知道你想做什么。我正在同一条船上试图想出一个解决方案。

我的服务层在即将到来的请求中执行操作,它的作用取决于内容。它将它传递给一系列责任类。我希望在名为

的服务方法的生命周期内传递给所有类的相同上下文

您可以指定PerResolveLifetimeManager。到目前为止,它似乎正在处理我的测试用例:

服务类:

public interface IServiceClass
{
    void DoService();
}

class ServiceClass : IServiceClass
{
    private IHandler Handler { get; set; }

    public ServiceClass(IHandler handler)
    {
        Handler = handler;
    }

    public void DoService()
    {
        Handler.HandleRequest();
    }
}

IHandler由两个类实现,并执行Chain of Responsibility模式:

    public interface IHandler
{
    void HandleRequest();
}

class Handler : IHandler
{
    private IDataContext DataContext { get; set; }
    public Handler(IDataContext dataContext)
    {
        DataContext = dataContext;
    }

    public void HandleRequest()
    {
        DataContext.Save("From Handler 1");
    }
}

class Handler2 : IHandler
{
    private IDataContext DataContext { get; set; }
    private IHandler NextHandler { get; set; }

    public Handler2(IDataContext dataContext, IHandler handler)
    {
        DataContext = dataContext;
        NextHandler = handler;
    }

    public void HandleRequest()
    {
        if (NextHandler != null)
            NextHandler.HandleRequest();

        DataContext.Save("From Handler 2");
    }
}

正如您所看到的,两个处理程序都接受IDataContext的实例,我希望它们在两个实例中都是相同的。 Handler2还接受一个I​​Handler实例来传递控制权(它在这里做了两个演示,但实际上,只有一个人会处理请求......)

IDataContext。在构造函数中,我初始化一个Guid,并在其操作期间输出它,以便我可以看到它被调用的两次是否使用相同的实例:

public interface IDataContext
{
    void Save(string fromHandler);
}

class DataContext : IDataContext
{
    private readonly Guid _guid;

    public DataContext()
    {
        _guid = Guid.NewGuid();
    }

    public void Save(string fromHandler)
    {
        Console.Out.WriteLine("GUI: [{0}] {1}", _guid, fromHandler);
    }
}

最后,注册和致电服务:

    private IUnityContainer container;
    private void InitializeUnity()
    {
        container = new UnityContainer();
        container.RegisterType<IHandler, Handler2>("Handler2",
            new InjectionConstructor(new ResolvedParameter<IDataContext>(), new ResolvedParameter<IHandler>("Handler1")));
        container.RegisterType<IHandler, Handler>("Handler1");
        container.RegisterType<IDataContext, DataContext>(new PerResolveLifetimeManager());
        container.RegisterType<IServiceClass, ServiceClass>("MyClass", new InjectionConstructor(new ResolvedParameter<IHandler>("Handler2")));
    }

    private void CallService()
    {
        var service = container.Resolve<ServiceClass>("MyClass");
        service.DoService();

        // Resolving and calling again to simulate multiple resolves:
        service = container.Resolve<ServiceClass>("MyClass");
        service.DoService();
    }

这是我得到的输出:

GUI: [f2250055-8a5f-4f80-a1b6-bcc5574138cf] From Handler 1
GUI: [f2250055-8a5f-4f80-a1b6-bcc5574138cf] From Handler 2
GUI: [22a5c0a3-3c5c-4683-807d-bf2b43f3cd0a] From Handler 1
GUI: [22a5c0a3-3c5c-4683-807d-bf2b43f3cd0a] From Handler 2

希望这一段文字回答你的问题...如果不是抱歉,它确实激发了我需要实施的解决方案......

答案 2 :(得分:0)

如果我正确地理解你的问题(如果你使用统一性......我想你这样做是因为你已经用统一标记了它)你可以做这样的事情:

在您的存储库实现中,

[InjectionConstructor]
public SqlRepository(
    [Dependency] DataContext ctx)

但是您必须以相同的方式标记服务构造函数并使用容器来解析您的服务以及存储库。 DataContext也必须在容器中才能使其工作。

另一种方法是使用您的存储库执行类似的操作:

[InjectionMethod]
public void Initialize(
    [Dependency] DataContext ctx

这将告诉unity调用此方法,如果您在服务构造函数中使用Unity与BuildUp方法...就像这样:

unitycontainer.BuildUp<IRepository>(repository);

我想这不是你想要的,但请告诉我,如果我走在正确的轨道上,我会看看能不能帮你进一步......

干杯/ J

答案 3 :(得分:0)

您是否尝试过对Unity统一容器使用RegisterInstance()方法?这样的事情可能有用:

public static UnityContainer CreateContainer()         {             UnityContainer容器=新的UnityContainer();

        try
        {
            var section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;

            if (section != null)
            {
                section.Containers[0].Configure(container);
            }
        }
        catch (Exception ex)
        {
            TraceLogger.LogMessage("Configurarion Error for Unity Container", ex.Message, TraceEventType.Critical);
            Environment.Exit(1);
        }


        container.RegisterInstance(new DataContext());
        return container;
    }

现在,每次此容器尝试构建需要DataContext的对象时,都会传递相同的实例。您甚至可以在注册其实例之前配置DataContext。

更新: 一个选项(现在,我不知道它是否真的是一个很好的做法,但这对我有用)是为你要创建的每个对象创建一个不同的容器。类似的东西:

UnityContainer container1 = ContainerFactory.CreateContainer();
UnityContainer container2 = ContainerFactory.CreateContainer();
UnityContainer container3 = ContainerFactory.CreateContainer();
MyObject1 object1 = container1.Resolve<MyObject1>();
MyObject2 object2 = container2.Resolve<MyObject2>();
MyObject3 object3 = container3.Resolve<MyObject3>();

或更总结的方式:

MyObject1 object1 = ContainerFactory.CreateContainer().Resolve<MyObject1>();
MyObject1 object2 = ContainerFactory.CreateContainer().Resolve<MyObject2>();
MyObject1 object3 = ContainerFactory.CreateContainer().Resolve<MyObject3>();

嗯,有很多方法可以使用工厂模式创建列表。希望它有所帮助