使用 Autofac 解析通用接口
Resolving Generic Interface with Autofac
这些是我的 类:
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)。所以,这是最初的问题,你用错误的泛型参数调用了方法。我只是使用反射调用带有正确泛型参数 (Submit) 的 Submit。
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
这些是我的 类:
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)。所以,这是最初的问题,你用错误的泛型参数调用了方法。我只是使用反射调用带有正确泛型参数 (Submit) 的 Submit。
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