2012-01-20 47 views
3

在我的应用程序中,我有一个名为Message的类。在Message类中存在一个名为MessageType的字符串类型的属性。 MessageType属性用于提醒应用程序在Message类的实例中将存在哪个数据模式。 Message类来自名为IMessage的接口。在使用Castle Windsor IoC容器注册组件时设置Name属性

举一个例子,假设我们有一个Message类的实例,它的MessageType属性的值为“com.business.product.RegisterUser”。

每个MessageType模式都有一个相应的消息处理程序类(MessageHandler),它从接口IMessageHandler派生。在上面的例子中,会有一个名为RegisterUserMessageHandler的类。所有消息处理程序类都从IMessageHandler派生。 IMessageHandler定义了一个GetMessageType函数,它将返回派生消息实例的MessageType属性。

在使用Castle Windsor IoC容器注册类/组件期间,我想将Name属性设置为Message实例的MessageType属性的值。我也想使用'按照惯例注册组件'的方法来注册这些类/组件来实现这一点。

本练习的最终目的是让我的代码使用Message的MessageType属性调用Resolve方法以获取正确的消息处理程序实例。例如:

string messageType = "com.business.product.RegisterUser";

IMessageHandler registerUserMessageHandler = _container.Resolve<IMessageHandler>(messageType);

我希望得到任何帮助解决这个问题。非常感谢。

+0

我看到的挑战是messageType(来自您的描述)是一个实例字段。当你注册组件时,你只是在处理类型信息 - 而不是实际的实例。或者messageType是静态的? – PatrickSteele

+0

嗨帕特里克。消息类型是一个常量,因此可以通过多种方式进行定义。类中的私有静态常量字符串是定义它的好方法。我还注意到示例代码中的“参数”的引用。我不确定什么属性是或表示的,但它看起来好像它可能是一个.NET类属性。不确定,但希望任何人都可以提供的信息。 –

回答

2

这是我提出的解决方案,但它确实有一些缺点。您必须决定这些缺点是否适合您的情况。但是,好处是配置基于约定,并且添加新的IMessageIMessageHandler类型将不需要任何额外的Windsor配置。

我使用了温莎的TypedFactoryFacility以及自定义ITypedFactoryComponentSelector的组合。通过使用工厂,我不再需要您的代码来直接调用容器的Resolve方法。当一个类需要基于消息类型获得IMessageHandler时,它只能依赖于工厂。这里的工厂:

public interface IMessageHandlerFactory 
{ 
    IMessageHandler GetMessageHandler(string messageType); 
} 

由于我使用温莎TypedFactoryFacility我并不需要实现这个方法,但是当涉及到调用GetMessageHandler方法,我会“帮助”温莎通过挑选合适的组件定义一个自定义组件选择:

public class HandlerTypeSelector : DefaultTypedFactoryComponentSelector 
{ 
    private readonly WindsorContainer container; 

    public HandlerTypeSelector(WindsorContainer container) 
    { 
     this.container = container; 
    } 

    protected override string GetComponentName(MethodInfo method, object[] arguments) 
    { 
     if (method.Name == "GetMessageHandler") 
     { 
      var type = arguments[0].ToString(); 
      var messageHandlers = container.ResolveAll<IMessageHandler>(); 
      var single = messageHandlers.SingleOrDefault(h => h.GetMessageType() == type); 
      if(single != null) 
       return single.GetType().FullName; 
     } 

     return base.GetComponentName(method, arguments); 
    } 
} 

注册这一切很简单,只要:

var container = new WindsorContainer(); 
container.AddFacility<TypedFactoryFacility>(); 

container.Register(
    Component.For<IMessageHandlerFactory>().AsFactory(c => c.SelectedWith(new HandlerTypeSelector(container))), 
    AllTypes.FromThisAssembly().BasedOn<IMessage>().WithService.AllInterfaces(), 
    AllTypes.FromThisAssembly().BasedOn<IMessageHandler>().WithService.AllInterfaces() 
    ); 

这是我用来验证一些测试代码:

var sampleMessage = new RegisterUserMessage(); 
var factory = container.Resolve<IMessageHandlerFactory>(); 

var handler = factory.GetMessageHandler(sampleMessage.MessageType); 

而且我用测试类/接口:现在

public interface IMessage 
{ 
    string MessageType { get; } 
} 

public interface IMessageHandler 
{ 
    string GetMessageType(); 
} 

public class RegisterUserMessage : IMessage 
{ 
    public string MessageType 
    { 
     get { return "RegisterUser"; } 
    } 
} 

public class RegisterUserMessageHandler : IMessageHandler 
{ 
    public string GetMessageType() 
    { 
     return "RegisterUser"; 
    } 
} 

public class RemoveUserMessage : IMessage 
{ 
    public string MessageType 
    { 
     get { return "RemoveUser"; } 
    } 
} 

public class RemoveUserMessageHandler : IMessageHandler 
{ 
    public string GetMessageType() 
    { 
     return "RemoveUser"; 
    } 
}  

,其缺点:内部组件选择,我解决所有IMessageHandler的,然后再决定使用哪一个基于名称(因为我没有在注册时给消息处理程序命名,所以它们将以其完全合格的名称在Windsor中注册)。如果你的消息处理器是轻量级的,并且/或者它们不是很多,或者它们是静态的,这可能不是问题。如果它们是暂时的和/或有重要的初始化代码,那么每次需要单个代码时解决它们可能代价很高。在这种情况下,我会放弃整个方法,并使用更多配置的东西,但可以直接按名称解析单个消息处理程序。

+0

太棒了!非常感谢帕特里克。感谢您对此的帮助。 –

0

也许,这是一个有点晚了,但是,你可以这样做:

foreach (string messageType in allMessages) 
{ 
    container.Register(
     Component.For<IMessageHangler>() 
     .ImplementedBy(GetImplementationFor(messageType)) 
     .Named(messageType); 
    ); 
} 

Type GetImplementationFor(string messageType) 
{ 
    switch (messageType) 
    { 
     case "com.business.product.RegisterUser": return typeof(RegisterUserService); 
     // more .... 
     default: throw new Exception("Unhandled message type!"); 
    } 
} 

// In work: 
void ProcessMessage(IMessage message) 
{ 
    var handler = this.Container.Resolve<IMessageHandler>(message.MessageType); 
    handler.handle(message); 
} 

但要肯定的是,既然这种方法,你将无法使用任何消息类型的注册任何其他组件名字,例如

container.Register<IFoo>() 
.ImplementedBy<FooHandler>() 
.Named("com.business.product.RegisterUser"); 

将引发异常,尽管IFoo不是IMessageHandler。

+0

收集知识和信息永远不会太迟:o)。非常感谢分享。 –

相关问题