在启动ASPNET Core时可以从外部程序集向应用添加增强功能。例如,外部库可以用托管启动( hosting startup) 实现为应用程序提供附加配置(Configuration)或服务(service)。

具体实现如下:

1、实现 IHostingStartup 接口

2、标注程序集(HostingStartup)属性。

[assembly: HostingStartup(typeof(StartupEnhancement.StartupEnhancementHostingStartup))]

3、在CreateHostBuilder中配置加载的程序集,如果多个程序集 分号 隔开

        public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
//增加外部启动项Fap.Core.DI.ServicesInjection,初始化所有service
webBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey,"Fap.Core") .UseStartup<Startup>();
});

如果阻止Hosting Startup加载,需要以下设置

 webBuilder.UseSetting(WebHostDefaults.PreventHostingStartupKey, "true")

如果排除某些程序集的Hosting Startup加载

 webBuilder.UseSetting(WebHostDefaults.HostingStartupExcludeAssembliesKey, "ASSEMBLY1;ASSEMBLY2; ...")

多个程序集 分号 隔开。

ASPNET Core 中的 DI 没有批量注册service的功能。下面我就实现一个批量注册service的功能。

采用注解的形式,在需要注册为service的类上进行标注。

定义一个Attribute

    [AttributeUsage(AttributeTargets.Class)]
public class ServiceAttribute:Attribute
{
public ServiceAttribute(ServiceLifetime serviceLifetime)
{
ServiceLifetime = serviceLifetime;
}
public ServiceLifetime ServiceLifetime { get; set; } = ServiceLifetime.Transient;
}

定义需要注册的类和接口

    public interface IUser
{
string Get(string userName);
}
public interface IUser1
{
string Get1(string userName);
} [Service(Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton)]
public class User : IUser,IUser1
{
private string s = Guid.NewGuid().ToString();
public string Get(string userName)
{
return $"{s}===={userName}";
} public string Get1(string userName)
{
return s;
}
}

如上,在User类上标注ServiceAttribute属性,设置ServiceLifetime为单利模式ServiceLifetime.Singleton

接下来实现 利用host startup来实现自动注册功能。根据class上标注的service attribute 来自动注册service

//标注程序集属性 HostingStartup
[assembly: HostingStartup(typeof(Fap.Core.DI.ServicesInjection))]
namespace Fap.Core.DI
{
public class ServicesInjection : IHostingStartup
{
public void Configure(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
var basePath = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
var assemblies = Directory.GetFiles(basePath, "*.dll").Select(Assembly.LoadFrom).ToArray();
var types = assemblies.SelectMany(a => a.DefinedTypes).Select(type => type.AsType()).Where(t => t.GetCustomAttribute<ServiceAttribute>() != null).ToArray();
var implementTypes = types.Where(t => t.IsClass).ToArray();
foreach (var implementType in implementTypes)
{
var interfaceTypes = implementType.GetInterfaces();
foreach (var interfaceType in interfaceTypes)
{
var attr = implementType.GetCustomAttribute<ServiceAttribute>();
              //根据serviceLifetime来向容器中注册
_ = (attr.ServiceLifetime switch
{
ServiceLifetime sl when sl == ServiceLifetime.Scoped => services.AddScoped(interfaceType, implementType),
ServiceLifetime sl when sl == ServiceLifetime.Singleton => services.AddSingleton(interfaceType, implementType),
ServiceLifetime sl when sl == ServiceLifetime.Transient => services.AddTransient(interfaceType, implementType),
_ => throw new FileNotFoundException("未找到此类型")
});
}
}
});
}
}
}

下面在Host builder时设置HostStartup

        public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
//增加外部启动项Fap.Core.DI.ServicesInjection,初始化所有service
webBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey,"Fap.Core") .UseStartup<Startup>();
});

这样我们在Controller中就可以使用已经自动注册到servicecontainer中的service了。

   public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IUser1 _userService1;
private readonly IUser _userService;
public HomeController(ILogger<HomeController> logger,IUser1 userService1,IUser user)
{
_logger = logger;
_userService1 = userService1;
_userService = user;
} public IActionResult Index()
{
ViewBag.CC = _userService.Get("zhangsan")+_userService1.Get1("lisi");
return View();
}
}

除了利用IHostingStartup为应用提供服务注册,还可以提供额外配置。

[assembly: HostingStartup(typeof(HostingStartupLibrary.ServiceKeyInjection))]

namespace HostingStartupLibrary
{
public class ServiceKeyInjection : IHostingStartup
{
public void Configure(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration(config =>
{
var dict = new Dictionary<string, string>
{
{"DevAccount_FromLibrary", "DEV_1111111-1111"},
{"ProdAccount_FromLibrary", "PROD_2222222-2222"}
}; config.AddInMemoryCollection(dict);
});
}
}
}

在controller中就可以访问到如上配置项

        public IndexModel(IConfiguration config)
{
ServiceKey_Development_Library = config["DevAccount_FromLibrary"];
ServiceKey_Production_Library = config["ProdAccount_FromLibrary"]; }

-----------------------------------------------------------------------------------------------------------

具体源码实现:

webBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey,"Fap.Core")

设置了WebHostOptions中的HostingStartupAssemblies属性,存放我们要加载的IHostingStartup的程序集。

在IWebHostBuilder 调用 Builder()返回IWebHost方法中进行调用。下面为关键代码

            _options = new WebHostOptions(_config, Assembly.GetEntryAssembly()?.GetName().Name);
       //没有设置阻止加载webBuilder.UseSetting( WebHostDefaults.PreventHostingStartupKey, "false")
if (!_options.PreventHostingStartup)
{
var exceptions = new List<Exception>(); // 执行 hosting startup assemblies
foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies().Distinct(StringComparer.OrdinalIgnoreCase))
{
try
{
var assembly = Assembly.Load(new AssemblyName(assemblyName)); foreach (var attribute in assembly.GetCustomAttributes<HostingStartupAttribute>())
{
                 //实例化自定义的hostingStartup
var hostingStartup = (IHostingStartup)Activator.CreateInstance(attribute.HostingStartupType);
                 //调用Configure方法,执行我们自定的逻辑
hostingStartup.Configure(this);
}
}
catch (Exception ex)
{
// Capture any errors that happen during startup
exceptions.Add(new InvalidOperationException($"Startup assembly {assemblyName} failed to execute. See the inner exception for more details.", ex));
}
} if (exceptions.Count > )
{
hostingStartupErrors = new AggregateException(exceptions);
}
}
_options.GetFinalHostingStartupAssemblies()方法代码如下:
   public IEnumerable<string> GetFinalHostingStartupAssemblies()
{
       //返回HostingStartupAssemblies中排除掉HostingStartupExcludeAssemblies的程序集
return HostingStartupAssemblies.Except(HostingStartupExcludeAssemblies, StringComparer.OrdinalIgnoreCase);
}
 

在ASP.NET Core中使用托管启动(hosting startup)程序集,实现批量注册service的更多相关文章

  1. ASP.NET Core中的依赖注入(3): 服务的注册与提供

    在采用了依赖注入的应用中,我们总是直接利用DI容器直接获取所需的服务实例,换句话说,DI容器起到了一个服务提供者的角色,它能够根据我们提供的服务描述信息提供一个可用的服务对象.ASP.NET Core ...

  2. [08]ASP.NET Core 中 launchsettings.json 启动配置文件

    ASP.NET Core launchsettings.json 启动配置文件 本文作者:梁桐铭- 微软最有价值专家(Microsoft MVP) 文章会随着版本进行更新,关注我获取最新版本 本文出自 ...

  3. ASP.NET Core Web 应用程序系列(二)- 在ASP.NET Core中使用Autofac替换自带DI进行批量依赖注入(MVC当中应用)

    在上一章中主要和大家分享在MVC当中如何使用ASP.NET Core内置的DI进行批量依赖注入,本章将继续和大家分享在ASP.NET Core中如何使用Autofac替换自带DI进行批量依赖注入. P ...

  4. ASP.NET Core中的依赖注入(1):控制反转(IoC)

    ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化&qu ...

  5. ASP.NET Core中的依赖注入(2):依赖注入(DI)

    IoC主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用"好莱坞原则"是应用程序以被动的方式实现对流程的定制.我们可以采用若干设计 ...

  6. ASP.NET Core使用HostingStartup增强启动操作

    概念 在ASP.NET Core中我们可以使用一种机制来增强启动时的操作,它就是HostingStartup.如何叫"增强"操作,相信了解过AOP概念的同学应该都非常的熟悉.我们常 ...

  7. ASP.NET Core中的依赖注入(4): 构造函数的选择与服务生命周期管理

    ServiceProvider最终提供的服务实例都是根据对应的ServiceDescriptor创建的,对于一个具体的ServiceDescriptor对象来说,如果它的ImplementationI ...

  8. ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【总体设计 】

    本系列前面的文章我们主要以编程的角度对ASP.NET Core的依赖注入系统进行了详细的介绍,如果读者朋友们对这些内容具有深刻的理解,我相信你们已经可以正确是使用这些与依赖注入相关的API了.如果你还 ...

  9. ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【解读ServiceCallSite 】

    通过上一篇的介绍我们应该对实现在ServiceProvider的总体设计有了一个大致的了解,但是我们刻意回避一个重要的话题,即服务实例最终究竟是采用何种方式提供出来的.ServiceProvider最 ...

随机推荐

  1. PHP 教你使用 Swoole-Tracker 秒级定位 PHP 卡死问题

    PHPer 肯定收到过这样的投诉:小菊花一直在转!你们网站怎么这么卡!当我们线上业务遇到这种卡住(阻塞)的情况,大部分 PHPer 会两眼一抹黑,随后想起那句名言:性能瓶颈都在数据库然后把锅甩给DBA ...

  2. linux服务器MySQL数据从磁盘拷贝以及恢复

    偶有感触:遇到这个问题,经过一个下午的排查, 终于解决. 故事情节:我的阿里云服务器突然被黑客攻击了,整个系统down了. 找客服,他们排查说usr目录的文件全部丢失.让我重新初始化系统盘.初始化之前 ...

  3. Java代码自动生成,生成前端vue+后端controller、service、dao代码,根据表名自动生成增删改查功能

    本项目地址:https://github.com/OceanBBBBbb/ocean-code-generator 项目简介 ocean-code-generator采用(适用):     ,并使用m ...

  4. pat 1041 Be Unique(20 分)

    1041 Be Unique(20 分) Being unique is so important to people on Mars that even their lottery is desig ...

  5. pat 1023 Have Fun with Numbers(20 分)

    1023 Have Fun with Numbers(20 分) Notice that the number 123456789 is a 9-digit number consisting exa ...

  6. 如何解决UNMOUNTABLE BOOT VALUME

    Windows error:UNMOUNTABLE BOOT VALUME 解决方法:Windows 修复工具 chkdsk命令 chkdsk D:/f ps:chkdsk 磁盘名 /f

  7. CentOS7和Ubuntu下安装Docker & Docker-Compose

    本篇介绍如何在CentOS 7.6和Ubuntu 16.04下安装Docker & Docker-Compose. CentOS篇 安装Docker # cat /etc/redhat-rel ...

  8. hopper逆向的伪代码令人大跌眼镜

    网上介绍hopper有逆向伪代码的文章很多,并以为其是万能而且cool B的.但是并没有人去求证hopper的逆向伪代码参考系数(参考价值,大家做过开发都清楚明白,有些功能看起来很花很cool但不实用 ...

  9. windows anaconda python3.7 import ssl,psycopg2报错

    使用anaconda,本来是为了减少装第三方模块依赖出错问题的. 但是,今天发现,也是有坑啊. 首先 import ssl 报错,import _ssl 说DLL load failed 解决办法:用 ...

  10. 如何使用C#调用C++类虚函数(即动态内存调用)

      本文讲解如何使用C#调用只有.h头文件的c++类的虚函数(非实例函数,因为非虚函数不存在于虚函数表,无法通过类对象偏移计算地址,除非用export导出,而gcc默认是全部导出实例函数,这也是为什么 ...