装饰用Structuremap通用接口 [英] Decorating a generic interface with Structuremap

查看:117
本文介绍了装饰用Structuremap通用接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个通用的接口,这需要两个泛型类型。我想装饰返回的所有版本,但因为我不知道类型调用EnrichWith时,它显然不会编译。我已经使用了EnrichWith超载传递的背景下试过,想也许我可以抢泛型传递和调用Activator.CreateInstance,但是在调试和检查它时,背景上没有任何有用的信息。

I have a generic interface, that takes in two generic types. I want to decorate all versions returned, but since I don't know the type when calling EnrichWith, it obviously doesn't compile. I've tried using the EnrichWith overload that passes in the context, thinking maybe I could grab the generic types passed in and call Activator.CreateInstance, but the context doesn't have any useful information on it when debugging and inspecting it.

下面是我到目前为止所。这是我的通用接口:

Here's what I have so far. This is my generic interface:

public interface IServiceOperation<in TRequest, out TResponse> where TResponse : ServiceResult, new()
{
    TResponse PerformService(TRequest validatedRequest);
}

下面是一个简单的实现:

Here's a sample implementation:

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();
    }
}

下面是我的装饰,它接受其他服务,以及:

Here is my decorator, that takes in another service as well:

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线显示我想要实现的:

Lastly, here is how far I've gotten on my container. This obviously doesn't compile, but the EnrichWith line shows what I'm trying to achieve:

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>()));
    }
}

和正因为这个问题需要多一点code,这是我的测试,我试图去通过:

And just because this question needed a little more code, here's my test that I'm trying to get to pass:

[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。我可以创建特定类型的版本请求和响应类型的所有组合,但显然这是不可取的。所以我缺少什么?

I feel like this is something that should be simple, and I'm really missing something with how to use StructureMap. I could create type-specific versions for all combinations of Request and Response types, but obviously that's not desirable. So what am I missing?

推荐答案

之所以能够弄明白,最终。我创建了一个RegistrationConvention:

Was able to figure it out, eventually. I created a RegistrationConvention:

public class ServiceRegistrationConvention : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
        var interfacesImplemented = type.GetInterfaces();

        foreach (var interfaceImplemented in interfacesImplemented)
        {
            if (interfaceImplemented.IsGenericType && interfaceImplemented.GetGenericTypeDefinition() == typeof(IServiceOperation<,>))
            {
                var genericParameters = interfaceImplemented.GetGenericArguments();
                var closedValidatorType = typeof(ValidateServiceDecorator<,>).MakeGenericType(genericParameters);

                registry.For(interfaceImplemented)
                    .EnrichWith((context, original) => Activator.CreateInstance(closedValidatorType, original,
                                                                                context.GetInstance<IValidationService>()));
            }
        }
    }
}

这篇关于装饰用Structuremap通用接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆