- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正着手开发一个消息处理系统,其中各种消息将从外部源到达并需要“处理”。消息对象基本上是 DTO。
我正在考虑让消息类存在于它们自己的程序集中,消息处理系统和外部系统都可用,并让处理程序从通用抽象类继承,大致如下:
Messages.dll
public abstract class Message {}
public class FooMessage : Message
{
...
}
public class BarMessage : Message
{
...
}
MessageHandlers.dll
public abstract class MessageHandler<TMessage> where TMessage : Message
{
public void Handle(TMessage message);
}
public class FooHandler : MessageHandler<FooMessage>
{
public void Handle(FooMessage message)
{
...
}
}
现在是问题:将所有这些粘合在一起的最佳方法是什么?我当然可以做一些反射(reflection)并编写一个辅助函数来根据传入的消息名称实例化适当的处理程序,但这不正是 IoC 容器应该擅长的事情吗?有没有更适合这份工作的人?意见和建议表示赞赏。
谢谢!
最佳答案
有几种方法可以注册您的处理程序。我总是从手动配置一切开始。在您的示例中,它看起来像这样:
<!-- language: c# -->
container.Register<IMessageHandler<FooMessage>, FooHandler>();
container.Register<IMessageHandler<BarMessage>, BarHandler>();
// etc
提示:与其使用抽象基类,不如定义一个 IMessageHandler<T>
界面。
一旦应用程序增长,这会变得很麻烦,因此在您的情况下,批量注册应该是可行的方法。所有 DI 容器都有不同的机制。大多数容器开箱即用地支持这一点,而其他容器则不支持。这是使用 Simple Injector 的方法:
<!-- language: c# -->
container.RegisterManyOpenGeneric(typeof(MessageHandler<>),
typeof(MessageHandler<>).Assembly);
这将注册所有实现 MessageHandler<T>
的具体类型和MessageHandler<T>
住在同一个集会.同样,这取决于您选择的容器如何编写。
为了处理传入的任意消息,您需要进行一些反射(reflection),但您不应该在应用程序本身中这样做。只需在应用程序中定义一个良好的抽象,并将反射的使用移动到应用程序中您拥有 DI 配置的部分。
例如,您可以定义一个 IMessageProcessor
接口(interface),允许处理任何类型的 Message
:
<!-- language: c# -->
public interface IMessageProcessor
{
void Process(Message message);
}
在您的 DI 配置附近,您可以定义 IMessageProcessor
的实现,它可能看起来像这样:
<!-- language: c# -->
private class DIMessageProcessor : IMessageProcessor
{
private readonly Container container;
public DIMessageProcessor(Container container)
{
this.container = container;
}
public void Process(Message message)
{
if (message == null) throw new ArgumentNullException("message");
Type messageType = message.GetType();
Type handlerType =
typeof(IMessageHandler<>).MakeGenericType(messageType);
var handler = this.container.GetInstance(handlerType);
handlerType.GetMethod("Handle").Invoke(handler, message);
}
}
将此排除在应用程序之外很重要。您不仅会混合职责,而且会更难添加新行为。例如,考虑防止消息重播(当消息被多次执行时)。将此行为实现为 IMessageProcessor
的装饰器很容易.除此之外,DIMessageProcessor
将很容易进行单元测试,或替换为性能更高的新实现(并再次进行单元测试)。
有几种方法可以注册 DIMessageProcessor
,取决于您选择的容器。例如使用简单注入(inject)器:
<!-- language: c# -->
container.RegisterSingle<IMessageProcessor>(new DIMessageProcessor(container));
有了这个,你可以注入(inject) IMessageProcessor
进入需要这个的类型。这是 WCF 的示例:
<!-- language: c# -->
[ServiceKnownType("GetKnownMessageTypes")]
public class WCFMessageService
{
private readonly IMessageProcessor processor;
public WCFMessageService()
{
this.processor =
Global.Container.GetInstance<IMessageProcessor>();
}
[OperationContract]
public void Process(Message message)
{
this.processor.Process(message);
}
public static IEnumerable<Type> GetKnownMessageTypes(
ICustomAttributeProvider provider)
{
var knownMessageTypes =
from type in typeof(Message).Assembly.GetTypes()
where typeof(Message).IsAssignableFrom(type)
select type;
return knownMessageTypes.ToArray();
}
}
希望对您有所帮助。
关于.net - 如何最好地组装大量消息处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6069428/
我是一名优秀的程序员,十分优秀!