2

シンプルなインジェクターの優れた機能のいくつかを利用しようとしています。

私は現在、デコレーターに問題があります。私が期待しているときにもヒットしません。

私はこのようにそれらを登録しています:

container.RegisterManyForOpenGeneric(
      typeof(ICommandHandler<>),
      AppDomain.CurrentDomain.GetAssemblies());

container.RegisterDecorator(
      typeof(ICommandHandler<>),
      typeof(CreateValidFriendlyUrlCommandHandler<>),
      context => context.ServiceType == typeof(ICommandHandler<CreateProductCommand>)
 );

 container.RegisterDecorator(
      typeof(ICommandHandler<>),
      typeof(CreateProductValidationCommandHandler<>),
      context => context.ServiceType == typeof(ICommandHandler<CreateProductCommand>)
 );

ICommandHandler<CreateProductCommand>への呼び出しが呼び出されCreateValidFriendlyUrlCommandHandler<>CreateProductValidationCommandHandler<>それ自体を実行する前に呼び出されることを期待しているため、何かが欠けているに違いないと思います。

次のような別の登録を試みました。

container.RegisterManyForOpenGeneric(
      typeof(ICommandHandler<>),
      AppDomain.CurrentDomain.GetAssemblies());

container.RegisterDecorator(
      typeof(ICommandHandler<>),
      typeof(CreateValidFriendlyUrlCommandHandler<>),
      context => context.ImplementationType == typeof(CreateProductCommandHandler)
 );

 container.RegisterDecorator(
      typeof(ICommandHandler<>),
      typeof(CreateProductValidationCommandHandler<>),
      context => context.ImplementationType == typeof(CreateProductCommandHandler)
 );

ICommandHandler<CreateProductCommand>私が考えたように、型のデコレーターを登録すると、実装ICommandHandler<CreateProductCommand>時に少し循環参照が発生する可能性があります。CreateProductValidationCommandHandlerCreateValidFriendlyUrlCommandHandlerICommandHandler<CreateProductCommand>

しかし、それを変更しても違いはありませんでした。

これが私のものCreateProductValidationCommandHandler<TCommand>です:

public class CreateProductValidationCommandHandler<TCommand> 
    : ICommandHandler<CreateProductCommand>
{
    private readonly ICommandHandler<TCommand> decorated;
    private readonly IValidationService validationService;

    public CreateProductValidationCommandHandler(
        ICommandHandler<TCommand> decorated,
        IValidationService validationService)
    {
        this.decorated = decorated;
        this.validationService = validationService;
    }

    public void Handle(CreateProductCommand command)
    {
        if (!validationService.IsValidFriendlyName(
            command.Product.ProductFriendlyUrl))
        {
            command.ModelStateDictionary.AddModelError(
                "ProductFriendlyUrl", 
                "The Friendly Product Name is not valid...");

            return;
        }

        if (!validationService.IsUniqueFriendlyName(
            command.Product.ProductFriendlyUrl))
        {
            command.ModelStateDictionary.AddModelError(
                "ProductFriendlyUrl", 
                "The Friendly Product Name is ...");

            return;
        }
    }
}

そして、これは私のものCreateValidFriendlyUrlCommandHandler<TCommand>です:

public class CreateValidFriendlyUrlCommandHandler<TCommand>
    : ICommandHandler<CreateProductCommand>
{
    private readonly ICommandHandler<TCommand> decorated;

    public CreateValidFriendlyUrlCommandHandler(ICommandHandler<TCommand> decorated)
    {
        this.decorated = decorated;
    }

    public void Handle(CreateProductCommand command)
    {
        if (string.IsNullOrWhiteSpace(
            command.Product.ProductFriendlyUrl))
        {
            command.Product.ProductFriendlyUrl = 
                MakeFriendlyUrl(command.Product.Name);
        }
    }
}
4

1 に答える 1

3

ICommandHandler<T>問題は、解決できないジェネリック型があるため、Simple Injector がデコレーターの 1 つで実装をラップできないことTCommandです。Handleデコレーターのメソッドがインスタンスを呼び出す場合、これに気付くでしょうdecorated。例えば:

public class CreateValidFriendlyUrlCommandHandler<TCommand>
    : ICommandHandler<CreateProductCommand>
{
    private readonly ICommandHandler<TCommand> decorated;

    public CreateValidFriendlyUrlCommandHandler(
        ICommandHandler<TCommand> decorated)
    {
        this.decorated = decorated;
    }

    public void Handle(CreateProductCommand command)
    {
        // This won't compile since CreateProductCommand and
        // TCommand are not related.
        this.decorated.Handle(command);
    }
}

このコードはコンパイルされません。デコレータのHandleメソッドはCreateProductCommand引数を取るのに対し、decoratedインスタンスは指定されていない引数を取るためです (そして、それが aTCommandであるとどこにも述べられていません)。CreateProductCommandTCommand

実際、デコレータをまったく作成していません。デコレーターは、それが実装する同じインターフェースのインスタンスをラップします。ICommandHandler<TCommand>を実装している間にラップしますICommandHandler<CreateProductCommand>。これを機能させる唯一の方法は、次のようTCommandに を aに明示的に指定する場合です。CreateProductCommand

ICommandHandler<CreateProductCommand> handler = 
    new CreateValidFriendlyUrlCommandHandler<CreateProductCommand>(
        new CreateProductCommandHandler()
    );

TCommandそれでも、Simple Injector がこれが であるべきだと「推測」する方法はなく、それがCreateProductCommand「デコレータ」がラップされなかった理由です。

簡単に言えば、次のものを捨てるTCommand

public class CreateValidFriendlyUrlCommandHandler
    : ICommandHandler<CreateProductCommand>
{
    private ICommandHandler<CreateProductCommand> decorated;

    public CreateValidFriendlyUrlCommandHandler(
        ICommandHandler<CreateProductCommand> decorated)
    {
        this.decorated = decorated;
    }

    public void Handle(CreateProductCommand command)
    {
        // logic here
    }
}

または、型制約を使用してジェネリックにします。

   public class CreateValidFriendlyUrlCommandHandler<TCommand>
        : ICommandHandler<TCommand>
        where TCommand : CreateProductCommand
    {
        private ICommandHandler<TCommand> decorated;

        public CreateValidFriendlyUrlCommandHandler(
            ICommandHandler<TCommand> decorated)
        {
            this.decorated = decorated;
        }

        public void Handle(TCommand command)
        {
            // logic here
        }
    }

または、型制約を削除して、 だけでなく、任意の型のコマンドを処理できるようにしCreateProductCommandます。

特定の 1 つのタイプのコマンド ハンドラーしか処理できない多くのデコレーターを定義している場合は、戦略を再検討する必要があることに注意してください。設計に問題がある可能性があります。

于 2012-11-18T08:20:43.747 に答える