ASP.NET 核心模拟服务仅在一个请求范围内
ASP.NET Core mock service only in scope of one request
假设我在应用程序启动时将某些服务注册为作用域,并且我想将其替换为仅针对单个请求的另一个实现。
有办法实现吗?
为什么我需要它?因为在某些情况下,我希望在数据库中没有该逻辑所需的数据的情况下继续执行某些逻辑,而是通过在请求中传递该数据并对其进行模拟,因此从数据库获取它的服务将 return 模拟数据从请求传递。
通用问题是如何替换注册实现?
我想你会在这里找到回复:
假设您已经注册了接口实现,我的解决方案是拥有 2 个接口。您可以使用接口继承来管理一致性。
所以你最终会得到类似
的东西
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();
}
一旦申请运行,就无法更换注册了。这个问题的一般解决方案是使用代理实现,根据所需条件转发到所需的实现。
因此考虑以下抽象和实现:
public interface IMyService
{
void DoSomething();
}
public class RealService : IMyService
{
public void DoSomething() { ... }
}
public class AlternativeService : IMyService
{
public void DoSomething() { ... }
}
在这 2 个实现旁边,您可以创建第三个代理实现:
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";
}
此 ProxyService
实现根据某些条件将任何传入调用转发到真实或替代实现。在示例中,该条件读取当前请求的用户名,但实际上它可以是任何内容。
类可以注册如下:
services.AddTransient<IMyService, ProxyService>();
services.AddScoped<RealService>();
services.AddScoped<AlternativeService>();
假设我在应用程序启动时将某些服务注册为作用域,并且我想将其替换为仅针对单个请求的另一个实现。 有办法实现吗?
为什么我需要它?因为在某些情况下,我希望在数据库中没有该逻辑所需的数据的情况下继续执行某些逻辑,而是通过在请求中传递该数据并对其进行模拟,因此从数据库获取它的服务将 return 模拟数据从请求传递。
通用问题是如何替换注册实现?
我想你会在这里找到回复:
假设您已经注册了接口实现,我的解决方案是拥有 2 个接口。您可以使用接口继承来管理一致性。
所以你最终会得到类似
的东西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();
}
一旦申请运行,就无法更换注册了。这个问题的一般解决方案是使用代理实现,根据所需条件转发到所需的实现。
因此考虑以下抽象和实现:
public interface IMyService
{
void DoSomething();
}
public class RealService : IMyService
{
public void DoSomething() { ... }
}
public class AlternativeService : IMyService
{
public void DoSomething() { ... }
}
在这 2 个实现旁边,您可以创建第三个代理实现:
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";
}
此 ProxyService
实现根据某些条件将任何传入调用转发到真实或替代实现。在示例中,该条件读取当前请求的用户名,但实际上它可以是任何内容。
类可以注册如下:
services.AddTransient<IMyService, ProxyService>();
services.AddScoped<RealService>();
services.AddScoped<AlternativeService>();