c# - 使用 Autofac 解析通用接口(interface)

标签 c# reflection autofac command-pattern

这些是我的类(class):

   public interface ICommandDtc{
        string Command { get; set; }
        string Xml { get; set; }
    }
    public interface ICommandHandler<in TCommand>
        where TCommand : ICommandDtc
    {
        CommandResult Execute(TCommand command);
        Task<CommandResult> ExecuteAsync(TCommand command);
    }

    public class CommandResult
    {
        public string Description { get; set; }
        public int Code { get; set; }
    }

    public interface ICommandBus{
    Task<CommandResult> SubmitAsync<TCommand>(TCommand command) where TCommand : ICommandDtc;
    CommandResult Submit<TCommand>(TCommand command) where TCommand : ICommandDtc;
    }

    public class CommandBus : ICommandBus{
        private readonly ILifetimeScope _container;
        public CommandBus(ILifetimeScope scope){
            _container = scope;
        }
        public async Task<CommandResult> SubmitAsync<TCommand>(TCommand command)
            where TCommand : ICommandDtc{
            var commandHandler = _container.Resolve<ICommandHandler<TCommand>>();
            return await commandHandler.ExecuteAsync(command);
        }
        public CommandResult Submit<TCommand>(TCommand command)
            where TCommand : ICommandDtc
        {
        **//its worked**
            var commandHandler = _container.Resolve<ICommandHandler<IntegerationCommand>>();
        **//exception**
            var commandHandler2 = _container.Resolve<ICommandHandler<TCommand>>();
            return commandHandler2.Execute(command);
        }
    }

    public abstract class CommandBase<TCommand> : ICommandHandler<TCommand>
        where TCommand : ICommandDtc{
        public async Task<CommandResult> ExecuteAsync(TCommand command){
            var commandResult = new CommandResult();
            try{
                commandResult = await InternalExecuteAsync(command);
            }

            catch (Exception exp){

            }
            return commandResult;
        }
        public CommandResult Execute(TCommand command)
        {
            var commandResult = new CommandResult();
            try
            {
                commandResult =  InternalExecute(command);
            }
            catch (Exception exp)
            {
            }
            return commandResult;
        }

        protected abstract Task<CommandResult> InternalExecuteAsync(TCommand command);
        protected abstract CommandResult InternalExecute(TCommand command);
    }//sample class 1
    public class IntegerationCommandHandler : CommandBase<IntegerationCommand>
    {
        protected override Task<CommandResult> InternalExecuteAsync(IntegerationCommand command){
            throw new System.NotImplementedException();
        }
        protected override CommandResult InternalExecute(IntegerationCommand command){
            switch (command.Command) {
                case "SendDocument":
                    return SendDocument(command.Xml);
            }
            return new CommandResult {Code = 5,Description = ""};
        }
        private CommandResult SendDocument(string xml){
            throw new System.NotImplementedException();
        }
    }//sample class 2
 public class SocialOperationCommandHandler : CommandBase<SocialOperationCommand>
    {
        protected override Task<CommandResult> InternalExecuteAsync(SocialOperationCommand command){
            throw new System.NotImplementedException();
        }
        protected override CommandResult InternalExecute(SocialOperationCommand command){
            throw new System.NotImplementedException();
        }
    }

还有我的 Autofac:

public static IContainer InitializeBusiness()
{
    if (_lifetimeScope != null)
    {
        _lifetimeScope.Dispose();
        _lifetimeScope = null;
    }
    ConfigureAutoMapper();
    var builder = new ContainerBuilder();
    builder.RegisterType<Bootstrapper>().AsSelf();
    var assemblies = Assemblies.GetBusinessAssemblies.ToArray();
    builder.RegisterAssemblyTypes(assemblies).AsImplementedInterfaces();
    builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(ICommandDtc))).Named<ICommandDtc>(x => x.Name);

    builder.RegisterType<AutoFacValidatorFactory>().As<IValidatorFactory>();

    _container = builder.Build();
    return _container;
}

我尝试使用:

try
{
    var addFormDtc=new AddFormDtc {CommandName = "SendDocument",SiteCollectionName = "IntegerationCommand",Xml = "1"};
    var obj = _scope.ResolveNamed<ICommandDtc>(addFormDtc.SiteCollectionName);
    obj.Command = addFormDtc.CommandName;
    obj.Xml = addFormDtc.Xml;
    var commandBus = _scope.Resolve<ICommandBus>();
    return commandBus.Submit(obj);
}
catch (Exception ex){
    comandResult.Code = 0;
    comandResult.Description = ex.Message;
    return comandResult;
}

但是我在这一行中遇到了异常:

var commandHandler2 = _container.Resolve<ICommandHandler<TCommand>>();

当我手动尝试时它的工作:

var commandHandler = _container.Resolve<ICommandHandler<IntegerationCommand>>();

异常:

The requested service 'JahadServices.Business.Services.Command.ICommandHandler`1[[JahadServices.Business.Dtos.Command.ICommandDtc, JahadServices.Business.Dtos, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.

最佳答案

您正在尝试解决 ICommandHandler<ICommandDtc> , 但你只注册了 ICommandHandler<IntegerationCommand>从此

 IntegerationCommandHandler : CommandBase<IntegerationCommand>

但是ICommandHandler<ICommandDtc>ICommandHandler<IntegerationCommand>是不同的类型。

更新:

我采用了您的原始解决方案并执行了以下操作: 替换这个 commandBus.Submit(obj);以此

commandBus.GetType().GetMethod(nameof(ICommandBus.Submit))
    .MakeGenericMethod(obj.GetType())
    .Invoke(commandBus, BindingFlags.Public, null, new[] { obj},
     CultureInfo.CurrentCulture);

它奏效了 :) 更多信息在这里 Calling generic method with a type argument known only at execution time

小解释。

当您调用泛型方法(提交)时,此方法内部的类型取决于变量指针类型。在您的情况下,您将 IntegerationCommand 实例存储在类型为 ICommandDtc 的变量中。所以,当您调用 Submit(ibj) 时,它就像 Submit(ibj)。所以,这是最初的问题,你用错误的泛型参数调用了方法。我只是使用反射调用带有正确泛型参数的提交(提交)。

commandBus.GetType()
.GetMethod(nameof(ICommandBus.Submit)) //<- getting Submit<> method
    .MakeGenericMethod(obj.GetType()) //<- set generic parameter, 
                                      // so now it Submit<IntegerationCommand> 
    .Invoke(commandBus, BindingFlags.Public, null, new[] { obj}, //<- invoke method

关于c# - 使用 Autofac 解析通用接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41260717/

相关文章:

c# - Nhibernate envers,使用依赖注入(inject)将用户添加到修订实体中

c# - 作为资源的 URI

c# - 根据 XmlEnumAttribute 名称值检索枚举值

android - 从 Android 中的外部 native 可执行文件调用 java 代码

c# - Autofac 为新线程创建子范围未按预期工作 "Instances cannot be resolved and nested lifetimes cannot be created..."

c# - 如何在 EndRequest 中使用 Autofac?

C# 获取 SelectedDate.Day 字符串值并将其绑定(bind)到 gridview

c# - Observable<string> 更新事件?

c# - 使用反射创建通用 List<T>

asp.net-web-api - 使用 Autofac 和 ASP.Net Identity 将 ApplicationUserManager 传递给 ApplicationOAuthProvider