开始之前确保已完成步骤1创建解决方案和类库项目,并在对应项目中安装nuget包
自动注入
项目中需要通过Autofac注入多个服务时,可通过反射机制实现服务的自动注入。
实现思路为:定义一个IBaseService接口,所有需要注入的服务都继承此接口,通过反射获取所有继承了IBaseService的服务和其实现类并注入。Microsoft.Extensions.DependencyInjection也可通过此方式实现。
ACD.Application项目中创建接口文件IBaseService.cs
1 2
| public interface IBaseService { }
|
ACD.Application项目中创建类文件Extensions.AppDomain.cs,封装AppDomain的扩展方法实现通过反射加载引用的程序集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public static partial class Extensions { public static List<Assembly> GetReferanceAssemblies(this AppDomain domain, Func<AssemblyName, bool> func) { var list = new List<Assembly>(); domain.GetAssemblies().ForEachItem(i => { GetReferanceAssemblies(i, list,func); }); return list; } static void GetReferanceAssemblies(Assembly assembly, List<Assembly> list, Func<AssemblyName, bool> func) { assembly.GetReferencedAssemblies().WhereIF(true, func).ForEachItem(i => { var ass = Assembly.Load(i); if (!list.Contains(ass)) { list.Add(ass); GetReferanceAssemblies(ass, list,func); } }); } }
|
ACD.Infrastructure项目中的Startup中实现注入方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| public static class Startup { public static ContainerBuilder AddInfrastructure(this ContainerBuilder builder) { return builder .AddServices(); }
public static async Task<AppSettingConfig> AddAppConfig(this ContainerBuilder builder,string configFileName = "appsettings.json") { var configFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, configFileName);
if (!File.Exists(configFile)) throw new FileNotFoundException($"{configFileName} 配置文件不存在");
string jsonString; using (var stream = File.OpenRead(configFile)) { var reader = new StreamReader(stream); jsonString = await reader.ReadToEndAsync(); }
var appSetting = JsonConvert.DeserializeObject<AppSettingConfig>(jsonString);
builder .RegisterInstance(appSetting) .SingleInstance();
return appSetting; }
private static ContainerBuilder AddServices(this ContainerBuilder builder) { var interfaceType = typeof(IBaseService);
var types = AppDomain.CurrentDomain.GetReferanceAssemblies(x => x.FullName.StartsWith("ACD."));
var interfaceTypes = types .SelectMany(s => s.GetTypes()) .Where(t => interfaceType.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract) .Select(t => new { Service = t.GetInterfaces().FirstOrDefault(), Implementation = t }) .Where(t => t.Service != null && interfaceType.IsAssignableFrom(t.Service));
foreach (var type in interfaceTypes) { builder.RegisterType(type.Implementation) .As(type.Service) .InstancePerDependency(); }
return builder; } }
|
如果要将多个服务按不同的生命周期分别注入,实现思路一样:删除IBaseService.cs接口文件,用三个接口文件例如IScopeService,ITransientService,ISingletonService代替其作用
继承自这三个接口的服务分别注入不同的生命周期
ACD.Client项目中AppInit.cs调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| internal class AppInit { private static IContainer Container;
internal static async Task Init() { var builder = new ContainerBuilder();
var config = await builder.AddAppConfig("appsettings.json");
builder.AddInfrastructure();
Container = builder.Build(); }
internal static T Resolve<T>() => Container.Resolve<T>(); }
|
NLog注入为例
项目ACD.Application中创建接口文件IloggerService.cs,继承自IBaseService
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public interface IloggerService:IBaseService { void Info(string msg);
void Info(string msg,params object[] args);
void Warn(string msg);
void Warn(string msg, params object[] args);
void Error(string msg);
void Error(string msg, params object[] args); }
|
项目ACD.Infrastructure中创建类文件LoggerService.cs,实现自IloggerService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class LoggerService : IloggerService { private readonly ILogger _logger; public LoggerService(ILogger logger) { _logger = logger; }
public void Error(string msg)=>_logger.Error(msg);
public void Error(string msg, params object[] args) => _logger.Error(msg, args);
public void Info(string msg)=>_logger.Info(msg);
public void Info(string msg, params object[] args)=>_logger.Info(msg, args);
public void Warn(string msg)=>_logger.Warn(msg);
public void Warn(string msg, params object[] args) => _logger.Warn(msg, args); }
|
项目ACD.Infrastructure中Startup.cs静态类中的AddInfrastructure方法添加以下代码,注入NLog模块
1
| builder.RegisterModule<NLogModule>()
|
修改后
1 2 3 4 5 6 7
| public static ContainerBuilder AddInfrastructure(this ContainerBuilder builder) { builder.RegisterModule<NLogModule>();
return builder .AddServices(); }
|
至此IloggerService已注入完成,使用方法同步骤6.配置文件注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
await AppInit.Init();
将AppInit中的内容在Global.asax中或ApplicationStart中实现
IloggerService _logger = AppInit.Resolve<IloggerService>(); _logger.Error("hello");
public class ACDesign { private readonly IloggerService _logger;
public ACDesign(IloggerService logger) => _logger = logger;
public void Demo() { } }
|
NLog需要单独的配置文件,ACD.Client创建nlog.config,配置文件内容网上资料很多,示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets> <target name="asyncFile" xsi:type="AsyncWrapper"> {basedir}{shortdate}{记录器名称}{单级记录}{shortdate} <target name="log_file" xsi:type="File" fileName="${basedir}/ACDesignLogs/${shortdate}/${level}-${shortdate}.txt" layout="${longdate} | ${message} ${onexception:${exception:format=message} ${newline} ${stacktrace} ${newline}" archiveFileName="${basedir}/archives/${level}-${shortdate}-{#####}.txt" archiveAboveSize="102400" archiveNumbering="Sequence" concurrentWrites="true" keepFileOpen="false" /> </target> <target name="colorConsole" xsi:type="ColoredConsole" layout="[${date:format=HH\:mm\:ss}]:${message} ${exception:format=message}" /> </targets>
<rules> <logger name="Microsoft.*" minlevel="Info" writeTo="" final="true" /> <logger name="*" minlevel="Info" writeTo="asyncFile" /> <logger name="*" minlevel="Warn" writeTo="colorConsole" /> </rules> </nlog>
|