c#Simple Injector在仅来自一个客户端的类中注入装饰器

时间:2019-05-28 10:45:36

标签: c# .net design-patterns simple-injector

大家好,
我有问题,我有这样的界面:

public interface ICommand<in TRequest, out TResponse> 
    where TRequest : class
    where TResponse : BaseResponse
{
    TResponse Execute(TRequest request);
}

然后我通过两个类来实现此接口,如下所示:

public class ExternalAddUser : ICommand<ExternalAddUserRequest, ExternalAddUserResponse>
{
    private readonly ICommand<AddUserRequest, AddUserResponse> _command;

    public ExternalAddUser(ICommand<AddUserRequest, AddUserResponse> command)
    {
        _command = command;
    }

    public ExternalAddUserResponse Execute(ExternalAddUserRequest request)
    {
        var response = _command.Execute(Mapper.Map<AddUserRequest>(request));

        return Mapper.Map<ExternalAddUserResponse>(response);
    }
}

还有:

public class AddUser : ICommand<AddUserRequest, AddUserResponse>
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IMessageService _messageService;
    private readonly IDefaultSettings _settings;
    private readonly IMessageFactory _messageFactory;

    public AddUser(IUnitOfWork unitOfWork, IMessageService messageService, IDefaultSettings settings, IMessageFactory messageFactory)
    {
        _unitOfWork = unitOfWork;
        _messageService = messageService;
        _settings = settings;
        _messageFactory = messageFactory;
    }

    public AddUserResponse Execute(AddUserRequest request)
    {
        // My implementation here
    }
}

接口IMessageFactory是一个“工厂/模板”模式,该模式创建一个仅具有以下属性的IMessage接口:正文,主题,语言。 我已经使用简单的注射器注册了我的课程,如下所示:

container.Register(typeof(ICommand<,>), businessLayerAssembly);   
container.Register<IDefaultSettings, DefaultSettings>(Lifestyle.Singleton);
container.Register<ISecuritySettings, SecuritySettings>(Lifestyle.Singleton);
container.RegisterConditional<IMessageFactory, ActivationMessageFactory>
            (c => c.Consumer.ImplementationType == typeof(AddUser) 
                  || c.Consumer.ImplementationType == typeof(SendActivationEmail));
container.RegisterConditional<IMessageFactory, RecoveryMessageFactory>
            (c => !c.Handled);

现在,我有另一个类是ActivationMessageFactory的装饰器,如下所示:

public class ActivationMessageWithoutLinkFactory : IMessageFactory 
{
    private readonly IMessageFactory _messageFactory;

    public ActivationMessageWithoutLinkFactory(IMessageFactory messageFactory)
    {
         _messageFactory = messageFactory;
    }

    public IMessage CreateMessage(MessageData messageData)
    {
        // Implementation
    }
}

我的问题是:
从ExternalAddUser类调用此类时,是否可以在AddUser类中注入ActivationMessageWithoutLinkFactory装饰器? 气味代码示例:

public class ExternalAddUser : ICommand<ExternalAddUserRequest, ExternalAddUserResponse>
{
    public ExternalAddUserResponse Execute(ExternalAddUserRequest request)
    {

        ICommand<AddUserRequest, AddUserResponse> command = new AddUser(new SqlUnitOfWork(), new EmailService(), 
            new DefaultSettings(), new ActivationMessageWithoutLinkFactory(new ActivationMessageFactory()));
    }
} 

谢谢您的回答,我希望我很清楚。

1 个答案:

答案 0 :(得分:1)

您要实现的目标是根据消费者的消费者应用装饰器。这在Simple Injector中无法轻松实现。相反,您可以尝试以下操作:不必使装饰器成为条件接收器,而向其注入可以在请求开始时设置的上下文数据。装饰者可以通过这种方式决定是否应执行其逻辑,或者只需将调用转发给被装饰者。

更新

您可以定义以下抽象:

public class ICommandContext
{
    Type RootRequest { get; }
}

此抽象允许您检查当前正在运行的根请求的类型。您可以在装饰器中使用此抽象:

public class ActivationMessageWithoutLinkFactory : IMessageFactory 
{
    private readonly ICommandContext _context;
    private readonly IMessageFactory _messageFactory;

    public ActivationMessageWithoutLinkFactory(
        ICommandContext context,
        IMessageFactory messageFactory)
    {
        _context = context;
        _messageFactory = messageFactory;
    }

    public IMessage CreateMessage(MessageData messageData)
    {
        if (_context.RootRequest == typeof(ExternalAddUser))
        {
            // Begin decorated stuff
            var message = _messageFactory.CreateMessage(messageData);
            // End decorated stuff

            return message;
        }
        else
        {
            return _messageFactory.CreateMessage(messageData);
        }
    }
}

现在,在您的“合成根”内部,可以创建一个ICommandContext实现和一个ICommand<,>装饰器来管理此上下文:

public class CommandContext : ICommandContext
{
    public Stack<Type> Requests = new Stack<Type>();

    public Type RootRequest => Requests.First();
}

public class ContextCommandDecorator<TRequest, TResponse> : ICommand<TRequest, TResponse>
{
    private readonly CommandContext _context;
    private readonly ICommand<TRequest, TResponse> _decoratee;
    public ContextCommandDecorator(
        CommandContext context,
        ICommand<TRequest, TResponse> decoratee)
    {
        _context = context;
        _decoratee = decoratee;
    }

    public TResponse Execute(TRequest request)
    {
        _context.Push(typeof(TRequest));

        try
        {
            return _decoratee.Execute(request);
        }
        finally
        {
            _context.Pop();
        }
    }
}

最后,您可以将以下三个注册添加到您的应用程序中:

container.Register<ICommandContext, CommandContext>(Lifestyle.Scoped);
container.Register<CommandContext>(Lifestyle.Scoped);

container.RegisterDecorator(typeof(ICommand<,>), typeof(ContextCommandDecorator<,>));