Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在ASP.NET内核中基于请求配置服务_C#_Asp.net Core_Dependency Injection - Fatal编程技术网

C# 如何在ASP.NET内核中基于请求配置服务

C# 如何在ASP.NET内核中基于请求配置服务,c#,asp.net-core,dependency-injection,C#,Asp.net Core,Dependency Injection,在ASP.NET Core中,我们可以在启动期间注册所有依赖项,这些依赖项在应用程序启动时执行。然后,注册的依赖项将被注入控制器构造函数中 public class ReportController { private IReportFactory _reportFactory; public ReportController(IReportFactory reportFactory) { _reportFactory = reportFactory;

在ASP.NET Core中,我们可以在启动期间注册所有依赖项,这些依赖项在应用程序启动时执行。然后,注册的依赖项将被注入控制器构造函数中

public class ReportController
{
    private IReportFactory _reportFactory;

    public ReportController(IReportFactory reportFactory)
    {
        _reportFactory = reportFactory;
    }

    public IActionResult Get()
    {
        vart report = _reportFactory.Create();
        return Ok(report);
    }
}
现在,我想根据当前请求中的数据(用户授权级别或随请求传递的querystring中的某个值)注入不同的
IReportFactory
实现

问:ASP.NET核心中是否有内置的抽象(中间件),我们可以在其中注册接口的另一个实现

如果没有内置功能,可能的方法是什么

更新
IReportFactory
接口被用作一个简单的示例。实际上,我在不同的地方注入了大量的低级接口。现在,我希望基于请求数据注入这些低级接口的不同实现

public class OrderController
{
    private IOrderService _orderService;

    public OrderController(IOrderService orderService)
    {
        _orderService = orderService;
    }

    public IActionResult Create()
    {
        var order = _orderService.Create();
        return Ok(order);
    }
}    

 public class OrderService
 {
    private OrderBuilder _orderBuilder;
    private IShippingService _shippingService; // This now have many different implementations

    public OrderService(
        OrderBuilder _orderBuilder,
        IShippingService _shippingService)
    {
        _orderService = orderService;
        _shippingService = shippingService;
    }

    public Order Create()
    {
        var order = _orderBuilder.Build();
        var order.ShippingInfo = _shippingService.Ship();
        return order;
    }
 }  

因为我们知道我们需要在应用程序的入口点上使用哪个实现(我认为控制器操作可以被视为应用程序的入口点),所以我们希望已经在那个里注入正确的实现-在已经存在的设计中不需要更改。

不,你们不能。
IServiceCollection
在应用程序启动期间填充,并在调用
Configure
方法之前构建。在此之后(容器被构建),注册不能再被更改

但是,您可以实现抽象工厂,无论是作为工厂方法还是作为接口/类

// Its required to register the IHttpContextAccessor first
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IReportService>(provider => {
    var httpContext = provider.GetRequired<IHttpContextAccessor>().HttpContext;

    if(httpContext.User.IsAuthorized) 
    {
        return new AuthorizedUserReportService(...);
        // or resolve it provider.GetService<AuthorizedUserReportService>()
    }

    return new AnonymousUserReportService(...);
    // or resolve it provider.GetService<AnonymousUserReportService>()
});
//需要先注册IHttpContextAccessor
services.AddSingleton();
services.AddScoped(provider=>{
var httpContext=provider.GetRequired().httpContext;
if(httpContext.User.IsAuthorized)
{
返回新的AuthorizedUserReportService(…);

//或者解析it provider.GetService

恐怕您无法通过简单的依赖注入直接实现目标,因为在启动阶段配置的依赖注入,换句话说,所有服务和实现都是在请求提交之前配置的

但是,您可以注入一个createservice委托,这样我们就可以在运行时创建所需的服务实现实例

例如,如果我们有一个
IReportFactory
接口和两个实现,如下所示:

public interface IReportFactory
{
    object Create();
}

public class ReportFactory1 : IReportFactory
{
    public object Create()
    {
        return new { F = 1, };
    }
}
public class ReportFactory2 : IReportFactory {
    public object Create()
    {
        return new { F = 2, }; 
    }
}
由于我们希望在将来获得所需的实现,我们需要首先注册这些实现

services.AddScoped<ReportFactory1>();
services.AddScoped<ReportFactory2>();
现在,我们可以将
CreateReportFactoryDelegate
注入控制器:

public class HomeController : Controller
{
    private CreateReportFactoryDelegate _createReportFactoryDelegate;

    public HomeController(CreateReportFactoryDelegate createDelegate) {
        this._createReportFactoryDelegate = createDelegate;
        // ...
    }

    public async Task<IActionResult> CacheGetOrCreateAsync() {

        IReportFactory reportFactory = this._createReportFactoryDelegate(this.HttpContext);
        var x=reportFactory.Create();

        // ...
        return View("Cache", cacheEntry);
    }
}
公共类HomeController:控制器
{
私有CreateReportFactoryDelegate _CreateReportFactoryDelegate;
公共HomeController(CreateReportFactoryDelegate createDelegate){
这。_createReportFactoryDelegate=createDelegate;
// ...
}
公共异步任务cacheGetOrCreateAync(){
IReportFactory reportFactory=this.\u createReportFactoryDelegate(this.HttpContext);
var x=reportFactory.Create();
// ...
返回视图(“缓存”,cacheEntry);
}
}

可以在Startup.cs中使用HttpContextAccessor

services.AddHttpContextAccessor();
services.AddScoped<IYourService>(provider =>
            {
                var contextAccessor = provider.GetService<IHttpContextAccessor>();
                var httpContext = contextAccessor.HttpContext;
                
                var contextVariable = httpContext. ...
                
                // Return implementation of IYourService that corresponds to your contextVariable

              
            });
services.AddHttpContextAccessor();
services.AddScoped(provider=>
{
var contextAccessor=provider.GetService();
var httpContext=contextAccessor.httpContext;
var contextVariable=httpContext。。。
//返回与contextVariable对应的IYourService的实现
});

您已经有了工厂。使用带有参数的工厂方法
Create
来检索特定实例。如果您需要有不同的工厂(为什么?)然后,您可以使用抽象工厂模式。您可以注册同一接口的多个实现,您将得到一个
IEnumerable
注入。如果创建
AuthorizedUserReportService
implements
IDisposed
,ASP.NET Core会在退出作用域时自动处理它,还是应该手动处理(如何处理?)?它应该可以工作,但只能说看了代码一次。但我现在正在工作的路上,它应该被处理。毕竟,这是一个工厂方法,它只告诉它是如何实例化的,而不告诉它的生命周期(注册方法就是这样做的,
AddScoped
/
AddTransient
/
AddSingleton
)一些DI框架可以在构建服务提供商后进行注册。然后,您可以在中间件中注册新的依赖项。例如,DryIoC可以这样做。但这需要对现有项目进行重大更改。请注意:使用服务更为清晰。AddHttpContextAccessor();扩展方法而不是services.AddSingleton();
services.AddHttpContextAccessor();
services.AddScoped<IYourService>(provider =>
            {
                var contextAccessor = provider.GetService<IHttpContextAccessor>();
                var httpContext = contextAccessor.HttpContext;
                
                var contextVariable = httpContext. ...
                
                // Return implementation of IYourService that corresponds to your contextVariable

              
            });