У меня есть универсальный интерфейс, который принимает два универсальных типа. Я хочу украсить все возвращенные версии, но поскольку я не знаю тип при вызове EnrichWith, он, очевидно, не компилируется. Я попытался использовать перегрузку EnrichWith, которая передается в контексте, думая, что, возможно, я мог бы получить переданные универсальные типы и вызвать Activator.CreateInstance, но контекст не имеет никакой полезной информации при отладке и проверке.
Вот что у меня есть. Это мой общий интерфейс:
public interface IServiceOperation<in TRequest, out TResponse> where TResponse : ServiceResult, new()
{
TResponse PerformService(TRequest validatedRequest);
}
Вот пример реализации:
public class SignUpService : IServiceOperation<SignUpRequest, SignUpResult>
{
private readonly IUserRepository _userRepo;
public SignUpService(IUserRepository userRepo)
{
_userRepo = userRepo;
}
public SignUpResult PerformService(SignUpRequest validatedRequest)
{
var user = Mapper.Map<User>(validatedRequest);
user.MarkAsLoggedIn();
user.ChangePassword(validatedRequest.UnhashedPassword);
using(var transaction = _userRepo.BeginTransaction())
{
_userRepo.Save(user);
transaction.Commit();
}
return new SignUpResult();
}
}
Вот мой декоратор, который принимает и другой сервис:
public class ValidateServiceDecorator<TRequest, TResponse> : IServiceOperation<TRequest, TResponse> where TResponse : ServiceResult, new()
{
private readonly IServiceOperation<TRequest, TResponse> _serviceOperation;
private readonly IValidationService _validationService;
public ValidateServiceDecorator(IServiceOperation<TRequest, TResponse> serviceOperation,
IValidationService validationService)
{
_serviceOperation = serviceOperation;
_validationService = validationService;
}
public TResponse PerformService(TRequest request)
{
var response = new TResponse();
var validationResult = _validationService.Validate(request);
if (!validationResult.IsValid)
{
response.ValidationErrors = validationResult.ValidationErrors;
return response;
}
return _serviceOperation.PerformService(request);
}
Наконец, вот как далеко я продвинулся в своем контейнере. Это, очевидно, не компилируется, но строка EnrichWith показывает, чего я пытаюсь достичь:
public class StructureMapServiceScanner : Registry
{
public StructureMapServiceScanner()
{
Scan(scanner =>
{
scanner.AssemblyContainingType(typeof (IServiceOperation<,>));
scanner.ConnectImplementationsToTypesClosing(typeof (IServiceOperation<,>));
});
For(typeof (IServiceOperation<,>))
.EnrichWith((ioc, original) => new ValidateServiceDecorator(original, ioc.GetInstance<IValidationService>()));
}
}
И поскольку этот вопрос требовал немного больше кода, вот мой тест, который я пытаюсь пройти:
[TestClass]
public class StructureMapServiceScannerSpecs
{
[TestMethod]
public void Test()
{
ObjectFactory.Configure(cfg =>
{
cfg.AddRegistry<StructureMapServiceScanner>();
cfg.For<IUserRepository>().Use(new Mock<IUserRepository>().Object);
cfg.For<IValidationService>().Use(new Mock<IValidationService>().Object);
});
var service = ObjectFactory.GetInstance<IServiceOperation<SignUpRequest, SignUpResult>>();
service.ShouldNotBeNull();
service.ShouldBeType<ValidateServiceDecorator<SignUpRequest, SignUpResult>>();
}
}
Мне кажется, что это что-то, что должно быть простым, и я действительно что-то упускаю из-за того, как использовать StructureMap. Я мог бы создать специфичные для типа версии для всех комбинаций типов запросов и ответов, но, очевидно, это нежелательно. Так чего мне не хватает?