为了账号安全,请及时绑定邮箱和手机立即绑定

您可以使用带有标记界面的 Autofac 的 Owned 吗?

您可以使用带有标记界面的 Autofac 的 Owned 吗?

C#
ibeautiful 2023-07-09 17:51:09
我想使用 Autofac 为给定工作单元创建一个或多个 WCF 通道的新实例。我想使用命令模式来表示工作单元,即给定的命令类注入它需要的通道并实现一系列相关操作。我尝试了以下方法:interface IUnitOfWork{}class FooCall : IUnitOfWork{    readonly BarChannel _channel;    public FooCall(BarChannel channel)    {        Console.WriteLine($"FooCall({new {channel}})");        _channel = channel;    }    public string Foo()    {        return "FOO";    }}class BarChannel{    public BarChannel()    {        Console.WriteLine("BarChannel()");    }}class FooService{    Func<Owned<FooCall>> _helperFn;    public FooService(Func<Owned<FooCall>> helperFn)    {        _helperFn = helperFn;    }    public void CallFoo()    {        using (var helper = _helperFn())        {            Console.WriteLine($"CallFoo(), helper={helper}");            helper.Value.Foo();        }    }}class Program{    static void Main(string[] args)    {        var builder = new ContainerBuilder();        builder.RegisterType<BarChannel>().InstancePerOwned<IUnitOfWork>();        builder.RegisterType<FooCall>().AsImplementedInterfaces().AsSelf();        builder.RegisterType<FooService>();        using (var scope = builder.Build().BeginLifetimeScope())        {            Console.WriteLine("call 1");            scope.Resolve<FooService>().CallFoo();            Console.WriteLine("call 2");            scope.Resolve<FooService>().CallFoo();        }    }}简而言之:服务方法创建一个拥有的工作单元;工作单元被注入了它调用的每个拥有的通道。代码示例应显示正在创建的两个通道实例。除了似乎为拥有的依赖项创建的生命周期范围仅标记为解析依赖项的类型 - 即 as FooCall,而不是 as IUnitOfWork。如果我注册BarChannel为InstancePerOwned<FooCall>,则代码有效;按原样注册为InstancePerOwned<IUnitOfWork>,它无法解析FooService,因为它找不到匹配的生命周期范围。我是否遗漏了某些东西,或者是我想要使用 Autofac 无法实现的功能?我宁愿不必将所有 WCF 通道注册为每个命令类的每个拥有的实例,这似乎会变得非常冗长。另一种解决方法是使用每个依赖实例并直接解析 Func,但这不会让我说在重用通道及其之间的依赖关系的同时组成工作单元。
查看完整描述

1 回答

?
慕工程0101907

TA贡献1887条经验 获得超5个赞

问题是,这InstancePerOwned<T>实际上只是 的一个特殊情况InstancePerMatchingLifetimeScope(params object[] lifetimeScopeTag),其中范围被标记为typeof(T). 就目前情况而言,在尝试解析时,此处提供的标记与附加到范围的标记之间需要存在直接链接,该链接始终设置为该特定Owned<>依赖项内的任何内容的类型。此时没有额外的逻辑来暗示类型之间的关系,它只是标签上的直接匹配。


但是,InstancePerMatchingLifetimeScope确实允许指定多个标签,因此可以执行以下操作:


builder.RegisterType<BarChannel>()

    .InstancePerMatchingLifetimeScope(new TypedService(typeof(FooCall)),new TypedService(typeof(AnotherUnitOfWork))); 

为了更简洁地包装它,您可以使用:


private static IEnumerable<Type> GetTypesImplementingInterface<TInterface>()

{

    return AppDomain.CurrentDomain.GetAssemblies()

        .SelectMany(s => s.GetTypes())

        .Where(p => typeof(TInterface).IsAssignableFrom(p));

}

然后是一个新的扩展方法:


public static class AutofacRegistrationBuilderExtensions

{

    public static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> InstancePerOwned<TLimit, TActivatorData, TRegistrationStyle>(

        this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> builder, IEnumerable<Type> serviceTypes)

    {

        return builder.InstancePerMatchingLifetimeScope(serviceTypes.Select(s => new TypedService(s)).ToArray());

    }

}

那么用法就是:


builder.RegisterType<BarChannel>().InstancePerOwned(GetTypesImplementingInterface<IUnitOfWork>());

我不确定最后一部分是否值得纳入 Autofac 本身,但我想如果值得,那么最好将上面的两种方法组合在一起,并从现有注册中检索适用的类型列表,例如类似的内容


InstancePerOwnedImplementing<TInterface>();

或者,扩展匹配范围逻辑以在解析时检查类型之间的关系可能会有点混乱,因为并非所有标签都是 Type 类型。


查看完整回答
反对 回复 2023-07-09
  • 1 回答
  • 0 关注
  • 126 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信