[英]Ninject mapping to generic type
I have a bunch of events which are processed by event handlers such as the following:我有一堆由事件处理程序处理的事件,例如:
Event Handler:事件处理程序:
public class DeliveryEventHandlers :
IConsume<DeliveryCreated>,
IConsume<DeliveryUpdated>{
readonly IDocumentSession _documentSession;
public DeliveryEventHandlers(IDocumentSession documentSession)
{
_documentSession = documentSession;
}
public void Consume(DeliveryCreated @event)
{
//...
}
public void Consume(DeliveryUpdated @event)
{
//...
}
...
Events:事件:
public class DeliveryCreated : IEvent
{
public Guid DeliveryId { get; set; }
...
}
public class DeliveryUpdated : IEvent
{
public Guid DeliveryId { get; set; }
...
}
And I need to write a Ninject binding that will on request of an Event type, give me the Event handler(s) that consume those events.我需要编写一个 Ninject 绑定,它将根据事件类型的请求,为我提供使用这些事件的事件处理程序。 This is what I have come up with:
这是我想出的:
public void BindEventHandlers(IContext context) {
Kernel.Bind(x =>
{
x.FromAssemblyContaining(typeof(DeliveryCreated))
.SelectAllClasses()
.InheritedFrom<IEvent>()
.BindWith(new EventBindingGenerator());
});
}
public class EventBindingGenerator : IBindingGenerator
{
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
yield return bindingRoot.Bind(x =>
{
x.FromAssemblyContaining(typeof(DeliveryEventHandlers))
.SelectAllClasses()
.InheritedFrom(IConsume<typeof(type)>);
// This Part ^
});
}
}
but this will not actually compile - I have hit a snag on the line above the comment: // This Part ^但这实际上不会编译 - 我在评论上方的行上遇到了障碍://这部分^
I need to do a query for:我需要查询:
_context.Get<DeliveryCreated>()
and recieive a DeliveryCreatedEventHandler.并接收 DeliveryCreatedEventHandler。
Any help would be muchos appreciated!!任何帮助将不胜感激!
Thanks, H谢谢,H
This can actually be solved quite easily with the conventions extension functionality:这实际上可以通过约定扩展功能很容易地解决:
kernel.Bind(x => x.FromAssemblyContaining(typeof(DeliveryCreated))
.IncludingNonePublicTypes() // may not be needed in your case
.SelectAllClasses()
.InheritedFrom(typeof(IConsume<>))
.BindAllInterfaces());
the following test succeeds (syntax is from FluentAssertions ):以下测试成功(语法来自FluentAssertions ):
kernel.Get<IConsume<DeliverCreated>>().Should().BeOfType<DeliveryEventHandlers>();
kernel.Get<IConsume<DeliveryUpdated>>().Should().BeOfType<DeliveryEventHandlers>();
Alternatively, if you want to make sure you don't want to bind the IConsume<...>
implementations to more types than necessary, you can replace the BindAllInterfaces
statement as follows:或者,如果您想确保不想将
IConsume<...>
实现绑定到更多类型,您可以按如下方式替换BindAllInterfaces
语句:
private static IEnumerable<Type> SelectConsumeInterfacesOnly(
Type type, IEnumerable<Type> baseTypes)
{
var matchingTypes = baseTypes.Where(t =>
t.IsGenericType
&& t.GetGenericTypeDefinition() == typeof (IConsume<>));
return matchingTypes;
}
kernel.Bind(x => x.FromThisAssembly()
.IncludingNonePublicTypes()
.SelectAllClasses()
.InheritedFrom(typeof(IConsume<>))
.BindSelection(SelectConsumeInterfacesOnly));
Again, I've verified that it actually works.再次,我已经验证它确实有效。
You can manually scan the assembly and register all classes that implement the IConsumer<>
interface.您可以手动扫描程序集并注册所有实现
IConsumer<>
接口的类。 Like this:像这样:
foreach (Type type in assembly.GetTypes().Where(x => x.IsClass))
{
foreach (
var @interface in
type.GetInterfaces()
.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IConsume<>)))
{
kernel.Bind(@interface).To(type);
}
}
If you know that there will be a single consumer of the event, use the following:如果您知道该事件将只有一个使用者,请使用以下命令:
var single_consumer = kernel.Get<IConsume<DeliveryCreated>>();
In case that there can be multiple consumers, use the following to obtain all of them:如果可以有多个消费者,请使用以下方法获取所有消费者:
var all_consumers = kernel.GetAll<IConsume<DeliveryCreated>>();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.