Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.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# 使用DI引导包含多个模块类型的ASP.NET Core 2.1应用程序_C#_Asp.net Core_Dependency Injection - Fatal编程技术网

C# 使用DI引导包含多个模块类型的ASP.NET Core 2.1应用程序

C# 使用DI引导包含多个模块类型的ASP.NET Core 2.1应用程序,c#,asp.net-core,dependency-injection,C#,Asp.net Core,Dependency Injection,已开始为多租户ASP.NET Core 2.1应用程序构建基础架构,该应用程序现在和将来将由许多模块组成 这样做的目的是使将来要添加的任何模块都能够插入系统,在应用程序启动时注册它们自己所需的依赖项,并在需要时使用已经注册的依赖项(由其他模块注册的依赖项) 让我们首先从我的头顶上看一下我想象中的示例代码。 假设我们有一个模块管理器,我们将其命名为-ModuleManager public class ModuleManager { // Let's store all of our mo

已开始为多租户ASP.NET Core 2.1应用程序构建基础架构,该应用程序现在和将来将由许多模块组成

这样做的目的是使将来要添加的任何模块都能够插入系统,在应用程序启动时注册它们自己所需的依赖项,并在需要时使用已经注册的依赖项(由其他模块注册的依赖项)

让我们首先从我的头顶上看一下我想象中的示例代码。 假设我们有一个模块管理器,我们将其命名为-
ModuleManager

public class ModuleManager
{
    // Let's store all of our module types here
    private List<Type> moduleTypes;

    void RegisterModules(Type webHostModuleType, IServiceCollection services)
    {
        // Find all module dependencies recursively 
        // (i.e. all modules that are specified in some, let's say 'DependsOn' attribute
        // which decorates webHostModuleType)
        moduleTypes = FindDependencies();

        // Now we need to register all dependencies
        foreach (Type moduleType in moduleTypes)
        {
            services.AddSingleton(moduleType);
        }

        // ... and we shouldn't forget to register the webHostModuleType too
        services.AddSingleton(webHostModuleType);
    }
}
然后我们将定义一些具体的模块类型,如下所示:

public class CoreModule : BaseModule
{
    // some dependencies that need to be injected...
    private readonly IHostingEnvironment hostingEnvironment;

    private readonly IDontKnowSomeOtherDependency someOtherDependency;

    public CoreModule(IHostingEnvironment hostingEnvironment, IDontKnowSomeOtherDependency someOtherDependency)
    {
        this.hostingEnvironment = hostingEnvironment;
        this.someOtherDependency = someOtherDependency;
    }

    public override void Init()
    {
        // Somehow register additional services defined by this module,
        // after it's been instantiated
    }
}
[DependsOn(typeof(CoreModule))]
public class WebHostModule : BaseModule
{
    private readonly ISomeDependencyRegisteredInCoreModule someDependency;

    public WebHostModule(ISomeDependencyRegisteredInCoreModule someDependency)
    {
        this.someDependency = someDependency;
    }

    public override void Init()
    {
        // Register some other service based on something from 'someDependency' field
    }
}
比如说,为了完整性起见,我们的
webHostModuleType
定义如下:

public class CoreModule : BaseModule
{
    // some dependencies that need to be injected...
    private readonly IHostingEnvironment hostingEnvironment;

    private readonly IDontKnowSomeOtherDependency someOtherDependency;

    public CoreModule(IHostingEnvironment hostingEnvironment, IDontKnowSomeOtherDependency someOtherDependency)
    {
        this.hostingEnvironment = hostingEnvironment;
        this.someOtherDependency = someOtherDependency;
    }

    public override void Init()
    {
        // Somehow register additional services defined by this module,
        // after it's been instantiated
    }
}
[DependsOn(typeof(CoreModule))]
public class WebHostModule : BaseModule
{
    private readonly ISomeDependencyRegisteredInCoreModule someDependency;

    public WebHostModule(ISomeDependencyRegisteredInCoreModule someDependency)
    {
        this.someDependency = someDependency;
    }

    public override void Init()
    {
        // Register some other service based on something from 'someDependency' field
    }
}
最后,让我们回到模块管理器。现在它应该有另一个方法,在
RegisterModules
之后执行,该方法应该以正确的顺序实例化每个模块,然后以正确的顺序调用
Init()
PostInit()
,从
CoreModule
开始,以
WebHostModule
结束。类似于此:

public void(?) LoadModules()
{
    // Sort our modules first so dependencies come in first and webHostModuleType the last
    SortEm(moduleTypes);

    // Now we need to instantiate them. 
    // Can't do it manually as all of them might have different constructors
    // So need to do it using our service collection 
    IServiceProvider serviceProvider = serviceCollection.BuildServicePRovider();

    foreach (Type moduleType in moduleTypes)
    {
        BaseModule moduleInstance = serviceProvider.GetRequiredService(moduleType) as BaseModule;

        // This is where we can register everything needed by the module instance. 
        // But can we?
        moduleInstance.Init();
        moduleInstance.PostInit();
    }

    // Maybe return the IServiceProvider instance we've built 
    // so we can return in to the `ConfigureServices` and return to ASP.NET Core from there?
}
正如您所看到的,这种方法提出了许多问题。我走的方向对吗?是否有一种方法可以正确地使用模块的
Init()和
PostInit()方法注册服务

如果调用
BuildServiceProvider()
然后实例化单例实例,我必须将
IServiceProvider
实例返回到
ConfigureServices()
以便ASP.NET Core可以使用它。如果我没有,它将构建一个新的,然后所有这些单例将再次实例化

但是如果我调用
ConfigureServices()
,那么我将无法添加新的服务,这必须在模块实例化之后进行。如果可能的话,方法是什么?有什么意见、想法吗


哇,这样的文字墙,感谢阅读

好吧,还有一个意见,但我们使用与Net Core团队相同的标准广告,创建扩展方法,因此我们只需要添加需要的服务:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddVtaeCommonServices();
        services.AddMyServiceMX(Configuration);
        services.AddOtherService(Configuration);

        return VtaeConfig.ConfigVtae(services);
    }
}
例如,使用此扩展方法:

public static class CommonServicesExtension
{

    public static IServiceCollection AddVtaeCommonServices(this IServiceCollection services)
    {
        services.AddNodaDateTime();
        services.AddMemoryCache();
        services.AddScoped<AuthorizedIpFilter>();
        services.AddScoped<HttpContextManager>();
        services.AddTransient<ProspectService>();
        services.AddTransient<TokenService>();
        services.AddTransient<TokenGenerator>();
        services.AddTransient<ProspectsRepository>();
        services.AddSingleton<UniqueIDGenerator>();
        services.AddSingleton<SchedulerService>();
        services.AddSingleton<ChecksumService>();
        return services;
    }
}
公共静态类CommonServicesExtension
{
公共静态IServiceCollection添加VTAECommonServices(此IServiceCollection服务)
{
services.addNodeAdateTime();
services.AddMemoryCache();
services.addScope();
services.addScope();
services.AddTransient();
services.AddTransient();
services.AddTransient();
services.AddTransient();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
返回服务;
}
}
通过这种方式,我们可以将函数提取到nuget包中,然后通过在启动中添加
AddXXXService()
简单地重新利用它们