我可以根据Open Generic的类型为AutoFac制作密钥服务吗 [英] Can I make a keyed service for AutoFac based on the type of the Open Generic

查看:172
本文介绍了我可以根据Open Generic的类型为AutoFac制作密钥服务吗的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想为我的Open Generic ICommandHandler创建一个基于T的keyedService.当ICommandHandler的T继承自ConsultantCommand时,我想注册一个ConsultatCommandHanlder键控服务

任何想法怎么做?还是有可能?我是AutoFac的新手,正在苦苦挣扎.

我目前正在像这样注册CommandHandler:

        //Register All Command Handlers
        builder.RegisterAssemblyTypes(assemblies)
          .As(
              t =>
              t.GetInterfaces()
               .Where(a => a.IsClosedTypeOf(typeof (ICommandHandler<>)))
               .Select(a => new KeyedService("commandHandler", a))).InstancePerHttpRequest();

如果可以的话,我想我必须在获得Closed Type时标识CommandHandler,并以某种方式标识Command实现ConsultantCommand的那些.

我尝试过:

        builder.RegisterAssemblyTypes(assemblies)
               .As(
                 t =>
                   t.GetInterfaces()
                    .Where(a => a.IsClosedTypeOf(typeof(ICommandHandler<>)) &&
                        a.GetGenericArguments()[0].IsSubclassOf(typeof(ConsultantCommand)))
                    .Select(a => new KeyedService("ConsultantCommandHandler", a))).InstancePerHttpRequest();

但是,快乐似乎并没有奏效.它可以编译,但是现在没有注册CommandHandler,即使那些确实从ConsultantCommand继承的CommandHandler也没有注册.我认为我的语法全错了

解决方案

首先,您需要确保已声明ICommandHandler<T>以支持协方差:

public interface ICommandHandler<out T> { }

out很重要,否则您将无法立即解析所有ConsultantCommand处理程序.您还将收到一个Autofac异常.

接下来,使用Named扩展方法注册您的命名服务,而不是自己进行.语法如下所示:

builder.RegisterAssemblyTypes(assemblies)
       .Where(t =>
                t.IsClosedTypeOf(typeof(ICommandHandler<>)) &&
                t.GetInterfaces()[0]
                 .GetGenericArguments()[0]
                 .IsAssignableTo<ConsultantCommand>())
       .Named("name", typeof(ICommandHandler<ConsultantCommand>))
       .InstancePerHttpRequest();

注册所有ICommandHandler<T>服务,其中TConsultantCommand派生为ICommandHandler<ConsultantCommand>.您必须使用基本类型,否则,您将无法一次解析所有处理程序.没有任何方法可以解析从该基本类型派生的所有服务".也没有办法解析开放的泛型列表.

解析处理程序列表时,需要解析一个名为IEnumerable<T>

using(var scope = container.BeginLifetimeScope())
{
  var x =
    scope.ResolveNamed<IEnumerable<ICommandHandler<ConsultantCommand>>>("name");
}

当然,您使用的是InstancePerHttpRequest,因此更像是:

var x =
  AutofacDependencyResolver
    .Current
    .RequestLifetimeScope
    .ResolveNamed<IEnumerable<ICommandHandler<ConsultantCommand>>>("name");

如上所述,您必须注册为封闭的通用名称,因为这将不起作用:

// WON'T WORK:
scope.ResolveNamed<IEnumerable<ICommandHandler<>>>("name");

您可以根据需要修改注册和.其余的注册扩展名应照常工作-如果您要将事物注册为已实现的接口或其他任何功能,则它应与RegisterAssemblyTypes一起使用,就像您使用单个服务一样.

I would like to make a keyedService based on the T for my Open Generic ICommandHandler. I would like to register a ConsultatCommandHanlder keyed service when the ICommandHandler has a T that inherits from ConsultantCommand

Any idea how to do it? Or if it is even possible? I am new to AutoFac and am struggling.

I am presently registering CommandHandler like this:

        //Register All Command Handlers
        builder.RegisterAssemblyTypes(assemblies)
          .As(
              t =>
              t.GetInterfaces()
               .Where(a => a.IsClosedTypeOf(typeof (ICommandHandler<>)))
               .Select(a => new KeyedService("commandHandler", a))).InstancePerHttpRequest();

If it is possible I'd guess I have to identify the CommandHandlers when I get the Closed Type and in some way identify the ones where the Command implements ConsultantCommand.

I tried:

        builder.RegisterAssemblyTypes(assemblies)
               .As(
                 t =>
                   t.GetInterfaces()
                    .Where(a => a.IsClosedTypeOf(typeof(ICommandHandler<>)) &&
                        a.GetGenericArguments()[0].IsSubclassOf(typeof(ConsultantCommand)))
                    .Select(a => new KeyedService("ConsultantCommandHandler", a))).InstancePerHttpRequest();

But not joy doesn't seem to work. It compiles but now no CommandHandlers are registered even those that do inherit from ConsultantCommand. I think my syntax is all wrong

解决方案

First, you'll need to make sure your ICommandHandler<T> is declared to support covariance:

public interface ICommandHandler<out T> { }

That out is important or you won't be able to resolve all the ConsultantCommand handlers at once. You'll also get an Autofac exception.

Next, use the Named extension method to register your named service rather than doing it yourself. The syntax will look something like this:

builder.RegisterAssemblyTypes(assemblies)
       .Where(t =>
                t.IsClosedTypeOf(typeof(ICommandHandler<>)) &&
                t.GetInterfaces()[0]
                 .GetGenericArguments()[0]
                 .IsAssignableTo<ConsultantCommand>())
       .Named("name", typeof(ICommandHandler<ConsultantCommand>))
       .InstancePerHttpRequest();

That registers all of the services that are ICommandHandler<T> where T derives from ConsultantCommand as an ICommandHandler<ConsultantCommand>. You have to use the base type or, again, you won't be able to resolve all the handlers at once. There isn't any method to "resolve all the services that derive from this base type." There's also no way to resolve a list of open generics.

When you resolve the list of handlers, you'll need to resolve a named IEnumerable<T>:

using(var scope = container.BeginLifetimeScope())
{
  var x =
    scope.ResolveNamed<IEnumerable<ICommandHandler<ConsultantCommand>>>("name");
}

Of course, you're using InstancePerHttpRequest so it'd be more like:

var x =
  AutofacDependencyResolver
    .Current
    .RequestLifetimeScope
    .ResolveNamed<IEnumerable<ICommandHandler<ConsultantCommand>>>("name");

As mentioned above, you have to register as a closed generic because this won't work:

// WON'T WORK:
scope.ResolveNamed<IEnumerable<ICommandHandler<>>>("name");

You can modify the registration and such as needed. The rest of the registration extensions should work as usual - if you want to register things as implemented interfaces or whatever else, it should work with RegisterAssemblyTypes just like you were doing it with a single service.

这篇关于我可以根据Open Generic的类型为AutoFac制作密钥服务吗的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆