在Startup.cs之外实现依赖注入

Elv*_*dov 19 c# dependency-injection .net-core asp.net-core

我想在ASP.NET CORE 1中实现依赖注入.我知道一切都与.Net Core中的DI有关.例如

   public void ConfigureServices(IServiceCollection services)
   {
      // Add application services.
     services.AddTransient<IDateTime, SystemDateTime>();
   }
Run Code Online (Sandbox Code Playgroud)

但对于拥有20多个实体和服务的Big项目,在ConfigureServices中编写所有这些代码行是如此困难和难以理解.我想知道这是否可能在Startup.cs之外实现依赖注入,然后将其添加到服务中.

谢谢你的回答.

Joe*_*tte 20

您可以编写IServiceCollection的扩展方法,将大量服务注册封装到Startup.cs中的一行代码中

例如,这是我项目中的一个:

using cloudscribe.Core.Models;
using cloudscribe.Core.Models.Setup;
using cloudscribe.Core.Web;
using cloudscribe.Core.Web.Components;
using cloudscribe.Core.Web.Components.Editor;
using cloudscribe.Core.Web.Components.Messaging;
using cloudscribe.Core.Web.Navigation;
using cloudscribe.Web.Common.Razor;
using cloudscribe.Web.Navigation;
using cloudscribe.Web.Navigation.Caching;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using System.Reflection;
using Microsoft.AspNetCore.Authorization;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class StartupExtensions
    {
        public static IServiceCollection AddCloudscribeCore(this IServiceCollection services, IConfigurationRoot configuration)
        {
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.Configure<MultiTenantOptions>(configuration.GetSection("MultiTenantOptions"));
            services.Configure<SiteConfigOptions>(configuration.GetSection("SiteConfigOptions"));
            services.Configure<UIOptions>(configuration.GetSection("UIOptions"));
            services.Configure<CkeditorOptions>(configuration.GetSection("CkeditorOptions"));
            services.Configure<CachingSiteResolverOptions>(configuration.GetSection("CachingSiteResolverOptions"));
            services.AddMultitenancy<SiteContext, CachingSiteResolver>();
            services.AddScoped<CacheHelper, CacheHelper>();
            services.AddScoped<SiteManager, SiteManager>();
            services.AddScoped<GeoDataManager, GeoDataManager>();
            services.AddScoped<SystemInfoManager, SystemInfoManager>();
            services.AddScoped<IpAddressTracker, IpAddressTracker>();
            services.AddScoped<SiteDataProtector>();
            services.AddCloudscribeCommmon();
            services.AddScoped<ITimeZoneIdResolver, RequestTimeZoneIdResolver>();
            services.AddCloudscribePagination();
            services.AddScoped<IVersionProviderFactory, VersionProviderFactory>();
            services.AddScoped<IVersionProvider, CloudscribeCoreVersionProvider>();
            services.AddTransient<ISiteMessageEmailSender, SiteEmailMessageSender>();
            services.AddTransient<ISmsSender, SiteSmsSender>();
            services.AddSingleton<IThemeListBuilder, SiteThemeListBuilder>();
            services.TryAddScoped<ViewRenderer, ViewRenderer>();
            services.AddSingleton<IOptions<NavigationOptions>, SiteNavigationOptionsResolver>();
            services.AddScoped<ITreeCacheKeyResolver, SiteNavigationCacheKeyResolver>();
            services.AddScoped<INodeUrlPrefixProvider, FolderTenantNodeUrlPrefixProvider>();
            services.AddCloudscribeNavigation(configuration);

            services.AddCloudscribeIdentity();

            return services;
        }


    }
}
Run Code Online (Sandbox Code Playgroud)

在Startup.cs中,我用一行代码调用该方法

services.AddCloudscribeCore(Configuration);
Run Code Online (Sandbox Code Playgroud)

  • 你好乔再次..我们再次见到一个问题......这是一种方法,有效,但需要大量的维护.我个人会使用汇编扫描(如我的回答所述). (2认同)

dmc*_*gin 8

有几种方法可以采用,但有些方法只是在类之间移动代码; 我建议您考虑Assembly Scanning下面的第二个选项:

1."移动问题":扩展方法

最初的选项是extension methods用于配置服务.

以下是将多个服务重新创建包装到一个扩展方法中的一个示例:

    public static IServiceCollection AddCustomServices(this IServiceCollection services)
    {
        services.AddScoped<IBrowserConfigService, BrowserConfigService>();
        services.AddScoped<IManifestService, ManifestService>();
        services.AddScoped<IRobotsService, RobotsService>();
        services.AddScoped<ISitemapService, SitemapService>();
        services.AddScoped<ISitemapPingerService, SitemapPingerService>();

        // Add your own custom services here e.g.

        // Singleton - Only one instance is ever created and returned.
        services.AddSingleton<IExampleService, ExampleService>();

        // Scoped - A new instance is created and returned for each request/response cycle.
        services.AddScoped<IExampleService, ExampleService>();

        // Transient - A new instance is created and returned each time.
        services.AddTransient<IExampleService, ExampleService>();

        return services;
    }
Run Code Online (Sandbox Code Playgroud)

这可以在以下内容中调用ConfigureServices:

services.AddCustomServices();
Run Code Online (Sandbox Code Playgroud)

注意:对于特定配置(例如,当服务需要向其传递多个选项时),这可用作"构建器模式",但是,不能解决必须通过手动编码注册多个服务的问题; 它与编写相同的代码但在不同的类文件中基本没什么不同,它仍然需要手动维护.

2.'解决问题':组装扫描

"最佳实践"选项是 程序集扫描,用于根据它们自动查找和注册组件Implemented Interfaces; 下面是一个Autofac示例:

var assembly= Assembly.GetExecutingAssembly();

builder.RegisterAssemblyTypes(assembly)
       .Where(t => t.Name.EndsWith("Repository"))
       .AsImplementedInterfaces();
Run Code Online (Sandbox Code Playgroud)

处理注册生命周期(或范围)的一个技巧是使用标记接口(例如IScopedService,空接口),并使用它来扫描和注册具有适当生命周期的服务.这是注册多个服务的最低摩擦方法,这是自动的,因此是"零维护".

注意:内置的ASP.Net Core DI实现不支持Assembly Scanning(如pf current,2016发布); 但是,Github(和Nuget)上的Scrutor项目添加了这个功能,它将服务和类型注册压缩为:

var collection = new ServiceCollection();

collection.Scan(scan => scan
    .FromAssemblyOf<ITransientService>()
        .AddClasses(classes => classes.AssignableTo<ITransientService>())
            .AsImplementedInterfaces()
            .WithTransientLifetime()
        .AddClasses(classes => classes.AssignableTo<IScopedService>())
            .As<IScopedService>()
            .WithScopedLifetime());
Run Code Online (Sandbox Code Playgroud)

摘要:

Assembly Scanning,与Extension Methods(适用时)相结合将为您节省大量维护费用,并在应用程序启动时执行一次,然后进行缓存.它不需要手动编码服务注册.