简体   繁体   English

ASP.NET 仅在一个请求的 scope 中的核心模拟服务

[英]ASP.NET Core mock service only in scope of one request

Let's assume I have some service registered as scoped in the application startup and I want to replace it with another implementation only for single request.假设我在应用程序启动中注册了一些服务,并且我想用另一个实现替换它,仅用于单个请求。 Is there a way for achieving that?有没有办法实现这一目标?

Why I need it?为什么我需要它? because there is a case when I want some logic to proceed without having necessary data for that logic in the database but by passing that data in a request and mocking it, so services which were getting it from database will return mocked data passed from request.因为在某些情况下,我希望在没有数据库中该逻辑的必要数据的情况下继续执行某些逻辑,而是通过在请求中传递该数据并将其传递给 mocking,因此从数据库获取它的服务将返回从请求传递的模拟数据。

Once the application is running, it is impossible to replace registration.一旦应用程序运行,就不可能替换注册。 The general solution to this problem is to use a proxy implementation that forwards to the desired implementation based on the required conditions.这个问题的一般解决方案是使用代理实现,根据所需的条件转发到所需的实现。

So consider the following abstraction and implementations:所以考虑以下抽象和实现:

public interface IMyService
{
    void DoSomething();
}

public class RealService : IMyService
{
    public void DoSomething() { ... }
}


public class AlternativeService : IMyService
{
    public void DoSomething() { ... }
}

Next to these 2 implementations, you can create a third, proxy implementation:在这两个实现旁边,您可以创建第三个代理实现:

public class ProxyService : IMyService
{
    private readonly RealService real;
    private readonly AlternativeService alternative;
    private readonly IHttpContextAccessor accessor;

    public ProxyService(
        RealService real,
        AlternativeService alternative,
        IHttpContextAccessor accessor)
    {
        this.real = real;
        this.alternative = alternative;
        this.accessor = accessor;
    }

    public void DoSomething() => this.Service.DoSomething();

    private IMyService Service => this.UseRealThing ? this.real : this.alternative.

    private bool UseRealThing => this.accessor.HttpContext.User.Name != "Artem";
}

This ProxyService implementation forwards any incoming call to either the real or the alternative implementation, based on some condition.ProxyService实现根据某些条件将任何传入呼叫转发到实际实现或替代实现。 In the example, that condition reads the user name of the current request, but it could in fact be anything.在示例中,该条件读取当前请求的用户名,但它实际上可以是任何内容。

The classes can be registered as follows:这些类可以按如下方式注册:

services.AddTransient<IMyService, ProxyService>();
services.AddScoped<RealService>();
services.AddScoped<AlternativeService>();

The generic problem is how to replace registered implementation?通用问题是如何替换已注册的实现?

I think you will find response here: Replace service registration in ASP.NET Core built-in DI container?我想你会在这里找到回应: Replace service registration in ASP.NET Core built-in DI container?

Assuming you have registered interface implementations, my solution would be to have 2 interfaces.假设您已经注册了接口实现,我的解决方案是拥有 2 个接口。 You can use interface inheritance to manage consistency.您可以使用接口 inheritance 来管理一致性。

So you'd end up with something like所以你最终会得到类似的东西

interface IDataProvider
{
   object GetData();
}

interface IDbDataProvider : IDataProvider
{
}

interface IMockDataProvider : IDataProvider
{
}

class DbDataProvider() : IDbDataProvider
{
    object GetData()
    {
        // Do databasey stuff
    }
}

class MockDataProvider() : IMockDataProvider
{
    object GetData() => new MockData(); // Or whatever
}

class Normal(IdbDataProvider dataProvider)
{
    var data = dataProvider.GetData();
}

class Weird(IMockDataProvider dataProvider)
{
    var data = dataProvider.GetData();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM