我在Autofac中有一个相当复杂的解决方案。基本上我希望容器中的所有对象实现具有特定参数类型的特定命名方法。我已经实现了一些有点疯狂的代码来为我提供它
var services = (from registrations in _componentContext.ComponentRegistry.Registrations
from service in registrations.Services
select service).Distinct();
foreach (var service in services.OfType<Autofac.Core.TypedService>())
{
foreach (var method in service.ServiceType.GetMethods().Where(m => m.Name == "Handle"
&& m.GetParameters().Where(p => p.ParameterType.IsAssignableFrom(implementedInterface)).Count() > 0))
{
var handler = _componentContext.Resolve(service.ServiceType);
method.Invoke(handler, new Object[] { convertedMessage });
}
}
我的问题出现了处理程序返回的解决步骤始终是相同的处理程序,我看不到解决与服务绑定的注册集合的方法,正如通常用container.Resolve&gt;所做的那样。 ()。
我觉得我正在努力克服AutoFac的设计目标,并且可以通过基于MEF的解决方案做得更好。是否有一个简单的基于AutoFac的解决方案来解决这个问题,还是应该跳到更基于组合的方法?
答案 0 :(得分:1)
G&#39;天,
在MEF中,您可以使用&#39;方法导出&#39;为此(http://mef.codeplex.com/wikipage?title=Declaring%20Exports)但这可能有点激烈。有几种方法可以在Autofac中实现您想要的效果。
您 可以通过搜索注册而不是服务来使上述代码生效:
var implementorMethods = _componentContext.ComponentRegistry.Registrations
.Select(r => new {
Registration = r,
HandlerMethod = r.Services.OfType<TypedService>()
.SelectMany(ts => ts.ServiceType.GetMethods()
.Where(m => m.Name == "Handle" && ...))
.FirstOrDefault()
})
.Where(im => im.HandlerMethod != null);
foreach (var im in implementorMethods)
{
var handler = _componentContext.ResolveComponent(im.Registration, new List<Parameter>());
im.HandlerMethod.Invoke(handler, new object[] { convertedMessage });
}
即。 implementorMethods
是实现处理程序方法的组件列表,以及方法本身。 ResolveComponent()
并不依赖服务来识别实施,因此服务没有唯一标识特定实施者的问题。
这种技术通常可能表现不佳(如果这是一个关注点),而且你怀疑它会违反Autofac(和MEF)的设计目标,从而消除了一些好处。
理想情况下,您需要为处理程序定义一个合约,让您在一次操作中查找所有处理程序以获取消息类型。
典型的配方如下:
interface IHandler<TMessage>
{
void Handle(TMessage message);
}
处理程序然后实现适当的接口:
class FooHandler : IHandler<Foo> { ... }
...并在构建时注册,如下:
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(typeof(FooHandler).Assembly)
.AsClosedTypesOf(typeof(IHandler<>));
要调用处理程序,请定义消息调度程序合同:
interface IMessageDispatcher
{
void Dispatch(object message);
}
...然后实施:
class AutofacMessageDispatcher : IMessageDispatcher
{
static readonly MethodInfo GenericDispatchMethod =
typeof(AutofacMessageDispatcher).GetMethod(
"GenericDispatch", BindingFlags.NonPublic | BindingFlags.Instance);
IComponentContext _cc;
public AutofacMessageDispatcher(IComponentContext cc)
{
_cc = cc;
}
public void Dispatch(object message)
{
var dispatchMethod = GenericDispatchMethod
.MakeGenericMethod(message.GetType());
dispatchMethod.Invoke(this, new[] { message });
}
void GenericDispatch<TMessage>(TMessage message)
{
var handlers = _cc.Resolve<IEnumerable<IHandler<TMessage>>>();
foreach (var handler in handlers)
handler.Handle(message);
}
}
...这样注册:
builder.RegisterType<AutofacMessageDispatcher>()
.As<IMessageDispatcher>();
然后,消息中的组件将解析/使用IMessageDispatcher
将消息发送给处理程序。
var dispatcher = _cc.Resolve<IMessageDispatcher>();
dispatcher.Dispatch(message);
如果没有接口,仍然有办法做到这一点,但所有这些都依赖于创建某种合同,该合同唯一地定义特定消息的处理程序(例如委托)。
从长远来看,通用处理程序模式将是最容易维护的。
希望这有帮助,尼克。