简体   繁体   中英

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.

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. 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?

Assuming you have registered interface implementations, my solution would be to have 2 interfaces. You can use interface inheritance to manage consistency.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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