首页 > 解决方案 > 如何从接口动态创建模拟对象?

问题描述

假设我有下面定义的接口和类。

public interface MyInterface
{
    void Method1();
    int Method2(int i);
    string Method3(string s);
}

public class MyImplementation : MyInterface
{
    public void Method1()
    {

    }

    int Method2(int i)
    {
        return i;
    }

    string Method3(string s)
    {
        return s;
    }
}

MyInterface定义在一个类库中,而定义MyImplementation在第二个类库中。

现在说我有一个依赖于MyInterface并通过依赖注入获取其实现的应用程序。应用程序可以简单地引用实现类库并注册MyImplementation到 IoC 容器,对吗?没什么大不了。

但是假设我有几十个服务和 Web 应用程序都依赖于MyInterface. 它们都MyImplementation通过 DI 使用,我想更改MyInterface. 我必须更新和重新部署每个应用程序,这是可行的,但有点痛苦。

我想要完成的是将依赖项封装在服务中并开发一些中间件,这些中间件会自动模拟客户端上的指定接口,将对那个接口的调用转换为 Web 请求(可能是通过反射),将该 Web 请求发送到服务,该服务会将 Web 请求转换回同一接口上的方法调用(同样,可能是通过反射),并调用真正的实现 DI'ed 到服务中。这将允许我将依赖项隔离到一个我可以随意更改的服务,而无需重新部署所有其他应用程序和服务。

首先,这似乎是某人应该已经解决的问题,但我似乎找不到任何罐头解决方案。

其次,如果我要自己实现这样的事情。我该怎么开始?似乎我正在尝试做类似于 Moq 或 Rhino Mocks 的事情,除了我不想明确定义每种方法要做什么。我想通过反射自动处理它。我的服务应该收到一个 POST 请求,其主体包含接口的 FQN、方法的名称和参数数组,以便我可以找到方法服务器端并调用它。

public static class IServiceCollectionExtensions
{
    public static IServiceCollection AddMiddlewareClient<T>(this IServiceCollection services)
    {
        var type = typeof(T);
        var bindingFlags = BindingFlags.Public | BindingFlags.Instance;
        var members = type.GetMembers(bindingFlags);

        var mockObject = ???

        foreach(var member in members)
        {
            // Mock each method on the interface with one that sends 
            // a web request to the service.
        }

        services.AddSingleton<T>(mockObject);

        return services;
    }
}

该服务看起来像这样。

public class HomeController : Controller
{
    private IServiceProvider _services;

    public HomeController(IServiceProvider services)
    {
        _services = services;
    }

    [HttpPost("invoke/{typeName}/{memberName}")]
    public object Invoke(string typeName, string memberName, [FromBody]Parameter[] parameters = null)
    {
        var interfaceType = Type.GetType(typeName);

        var args = parameters
        .Select(p =>
        {
            var parameterType = Type.GetType(p.TypeName);
            var parameter = JsonConvert.DeserializeObject(p.Json, parameterType);
            return parameter;
        })
        .ToArray();

        var impl = _services.GetRequiredService(interfaceType);
        var implType = impl.GetType();
        var bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase;
        var result = implType.InvokeMember(memberName, bindingFlags, null, impl, args);

        return result;
    }
}

标签: .netreflectionmocking.net-coremiddleware

解决方案


推荐阅读