c# Simple Injector 仅从一个客户端在 class 中注入装饰器
c# Simple Injector inject decorator in a class only from one client
伙计们,
我有一个问题,我有一个这样的界面:
public interface ICommand<in TRequest, out TResponse>
where TRequest : class
where TResponse : BaseResponse
{
TResponse Execute(TRequest request);
}
然后我两个 class 实现这个接口是这样的:
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 是一个 "Factory/Template" 模式,它创建一个只有 属性 的 IMessage 接口,例如:正文、主题、语言。
我已经用这样的简单注射器注册了我的 class:
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);
现在我有另一个 class 是 ActivationMessageFactory 的装饰器,如下所示:
public class ActivationMessageWithoutLinkFactory : IMessageFactory
{
private readonly IMessageFactory _messageFactory;
public ActivationMessageWithoutLinkFactory(IMessageFactory messageFactory)
{
_messageFactory = messageFactory;
}
public IMessage CreateMessage(MessageData messageData)
{
// Implementation
}
}
我的问题是:
当从 ExternalAddUser class 调用此 class 时,是否可以在 AddUser class 中注入 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()));
}
}
这是我要构建的对象图:
// AddUser injected into ExternalAddUser
new ExternalAddUser(
new AddUser(
new UnitOfWork(),
new MessageService(),
new DefaultSettings(),
new ActivationMessageWithoutLinkFactory(
new ActivationMessageFactory())))
// AddUser injected into anything else
new AnythingElse(
new AddUser(
new UnitOfWork(),
new MessageService(),
new DefaultSettings(),
new ActivationMessageFactory())) // no decorator
谢谢你的回答,我希望我已经清楚了。
您要实现的是基于消费者的消费者应用装饰器。这在 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);
}
}
}
在您的 Composition Root 中,您现在可以创建一个 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<,>));
伙计们,
我有一个问题,我有一个这样的界面:
public interface ICommand<in TRequest, out TResponse>
where TRequest : class
where TResponse : BaseResponse
{
TResponse Execute(TRequest request);
}
然后我两个 class 实现这个接口是这样的:
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 是一个 "Factory/Template" 模式,它创建一个只有 属性 的 IMessage 接口,例如:正文、主题、语言。 我已经用这样的简单注射器注册了我的 class:
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);
现在我有另一个 class 是 ActivationMessageFactory 的装饰器,如下所示:
public class ActivationMessageWithoutLinkFactory : IMessageFactory
{
private readonly IMessageFactory _messageFactory;
public ActivationMessageWithoutLinkFactory(IMessageFactory messageFactory)
{
_messageFactory = messageFactory;
}
public IMessage CreateMessage(MessageData messageData)
{
// Implementation
}
}
我的问题是:
当从 ExternalAddUser class 调用此 class 时,是否可以在 AddUser class 中注入 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()));
}
}
这是我要构建的对象图:
// AddUser injected into ExternalAddUser
new ExternalAddUser(
new AddUser(
new UnitOfWork(),
new MessageService(),
new DefaultSettings(),
new ActivationMessageWithoutLinkFactory(
new ActivationMessageFactory())))
// AddUser injected into anything else
new AnythingElse(
new AddUser(
new UnitOfWork(),
new MessageService(),
new DefaultSettings(),
new ActivationMessageFactory())) // no decorator
谢谢你的回答,我希望我已经清楚了。
您要实现的是基于消费者的消费者应用装饰器。这在 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);
}
}
}
在您的 Composition Root 中,您现在可以创建一个 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<,>));