0

Ich habe (nicht-polymorphe) Nachrichten, die ich nach ihrem MessageType-Feld behandeln möchte. Es ist nahe dem Befehlsmuster hier diskutiert (und die ich die Arbeit mit Tests):Wie Schloss Windsor Befehl/Handler basierend auf Nachrichteninhalt (nicht Laufzeittyp)

  1. Castle Windsor & Command Pattern
  2. Windsor registration for generic commands/command handlers
  3. http://kozmic.net/2010/03/11/advanced-castle-windsor-ndash-generic-typed-factories-auto-release-and-more/

execpt, ich habe keine separate Klassen oder generische Typen für jede MessageType. Ich würde es vorziehen, solche Typen (Legacy-Gründe) nicht einführen zu müssen.

Etwa wie:

public interface IMessage { 
    int MessageType { get; } 
    IList<byte> Payload { get; } 
} 
class Message: IMessage { 
    // Implementation 
} 
public interface IHandler { 
    void Handle(IMessage message); 
} 
public abstract class TypedMessageHandler: IHandler { 
    public abstract int RequiredMessageType { get; } 
    public virtual void Handle(IMessage message) { 
    if (message.CommandType != RequiredMessageType) 
     throw new ArgumentException(nameof(message)) // More info :) 
    InnerHandle(message); 
    } 
    protected abstact void InnerHandle(IMessage message); 
} 
class MessageType0Handler: TypedMessageHandler { 
    public int RequiredMessageType => 0; 
    override void InnerHandle(IMessage message) => // Do stuff; 
} 
class MessageType1Handler: TypedMessageHandler { 
    public int RequiredMessageType => 1; 
    override void InnerHandle(IMessage message) => // Do stuff; 
} 
// Some registration that I can use to dispatch from `msg: IMessage` to 
// `IHandler` with `RequiredMessageType == msg.MessageType`. 

Wie kann ich diese Depesche mit Windsor zu tun? Vorzugsweise mit einigen Registrierungen basierend auf Abfragen der definierten Typen.

Der Trick mit einer TypedFactory aus den obigen Artikeln ist nicht sofort nützlich.

Ich spiele mit den Handler mit benutzerdefinierten Attributen Tagging, aber ich kann nicht herausfinden, wie man beide:

  1. Holen Sie sich das Befehlsargument (IMessage-Instanz), und
  2. Verwenden Sie einen benutzerdefinierten IHandlerSelector, um die IHandler-Implementierungen basierend auf einem solchen Attribut zu filtern.
+0

Ich habe eine Arbeitslösung bei github.com/slogen/WindsorTests/blob/master/WindsorTests/..., aber ich mag es nicht :) Es verschiebt den Parameter aus dem Griff() aufrufen, an den Konstruktor die IHandler-Instanz (die für mich OK ist) Aber es erfordert einige "Tricks" für die Registrierung. –

Antwort

0

würde ich empfehlen RequiredMessageType auf Ihre IHandler Schnittstelle hinzuzufügen:

:

Registrierung so etwas wie wäre
public class Dispatcher 
{ 
    private readonly Dictionary<int, IHandler> handlers; 

    public Dispatcher(IEnumerable<IHandler> handlers) 
    { 
     this.handlers = handlers.ToDictionary(h => h.RequiredMessageType, h => h); 
    } 

    public void Dispatch(IMessage message) 
    { 
     handlers[message.MessageType].Handle(message); 
    } 
} 

Und Schloss:

public interface IHandler 
{ 
    void Handle(IMessage message); 
    int RequiredMessageType { get; } 
} 

als Sie Ihren eigenen Dispatcher anlegen

var container = new WindsorContainer(); 

container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel)); 
container.Register(Component.For<Dispatcher>()); 
container.Register(
Classes.FromThisAssembly() 
.BasedOn(typeof(IHandler)) 
.WithServiceFromInterface(typeof(IHandler))); 

//dispatch 
var dispatcher = container.Resolve<Dispatcher>(); 
dispatcher.Dispatch(new Message()); 
+0

Dazu müssten Instanzen von (allen) IHandler-Implementierungen erstellt werden, um zu testen, ob sie mit einem bestimmten MessageType arbeiten können. –

+0

@HelgeJensen. Ja, da sich Ihre RequiredMessageType-Informationen in der Instanz Ihres Handlers befinden, daher benötigen Sie sie. Castle weiß nichts über das, was in deinen Instanzen ist, um dir einen konkreten zu geben. Castle hat nur Wissen über Typen (einschließlich ihrer Attribute). –

0

Wahrscheinlich die einfachste Möglichkeit wäre, Ihre handler s als named Komponenten nach einem bekannten Muster (vielleicht "message-handler-for-N"), wo N ist die MessageType und dann eine getippte Fabrik mit einem benutzerdefinierten ITypedFactoryComponentSelector haben Bei einer gegebenen Nachricht wird der Name des aufzulösenden Handlers ausgewählt.

+0

Ich sehe, wie das funktionieren könnte.Es würde einige Tricks bei der Registrierung erfordern, um den Namensprozess zu einer impliziten Konvention zu machen. Ich habe bereits eine ziemlich nette Lösung, wenn ich Tricks bei der Registrierung benötigen kann: https://github.com/slogen/WindsorTests/blob/master/ WindsorTests/HandlerDispatching/ByCommandTag/HandlerByCommandTagTests.cs –

Verwandte Themen