西安转眼都到了冬天,春游暴龙峪,夏游太平峪仿佛就在昨天,冬季了就很少进山游玩了,昆明湖白鹿原转转就行了。
今天我们来看一下asp.net core web api框架的搭建。
首先我们先解决一下依赖注入问题,对于依赖注入,分为Transient,Singleton,Scoped,至于这三个作用域问题就不再赘述。我的想法不管是类,还是接口,只要继承我写的接口,在程序启动时就给它注入容器。ok我们看一下实现自动注入的扩展类
public static class DependencyInjectExtension { public static void RegisterDependency(this IServiceCollection services) { Assembly[] assemblies = GetSolutionAssemblies(); RegisterDependencyByAssembly<ISingleton>(services, assemblies); RegisterDependencyByAssembly<ITransient>(services, assemblies); RegisterDependencyByAssembly<IScoped>(services, assemblies); services.AddHttpClient<MessageSender>(); } private static void RegisterDependencyByAssembly<T>(IServiceCollection services, Assembly[] assemblies) where T : ILifetimeCycle { services.Scan(scan => scan.FromAssembliesOf(assemblies .SelectMany(s => s.GetTypes()) .Where(p => typeof(IUserModule).IsAssignableFrom(p))) .AddClasses(classes => classes.AssignableTo<T>()) .AsSelfWithInterfaces() .WithLifetime(ConvertLifeTimeCycle<T>())); ; } private static ServiceLifetime ConvertLifeTimeCycle<T>() where T : ILifetimeCycle { var lifeTimeCycleType = typeof(T); return EnsureCondition.RunIf(lifeTimeCycleType.IsDefined(typeof(LifeTimeAttribute)) , () => typeof(T).GetCustomAttribute<LifeTimeAttribute>().ServiceLifetime , () => ServiceLifetime.Scoped); } private static Assembly[] GetSolutionAssemblies() { var assemblies = Directory.GetFiles(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "*.dll") .Select(x => Assembly.Load(AssemblyName.GetAssemblyName(x))); return assemblies.Where(a => a.FullName.StartsWith("{namescpace start}")).ToArray(); } }
首先我们根据FullName获取到所有需要自动注入的程序集,然后通过Scrutor提供的Scan方法找到所有继承IUserModule的程序集并找到继承ISingleTon,ITransient,IScoped接口的类然后进行自动注入,这里呢AsSelfWithInterfaces意思是类既可以注入为类,也可以注入为接口,就看你怎么用,这里附上文档地址供大家参考学习https://andrewlock.net/using-scrutor-to-automatically-register-your-services-with-the-asp-net-core-di-container/
对于这三个接口,定义如下
[LifeTime(ServiceLifetime = ServiceLifetime.Singleton)] public interface ISingleton : ILifetimeCycle { } [LifeTime(ServiceLifetime = ServiceLifetime.Scoped)] public interface IScoped : ILifetimeCycle { } [LifeTime(ServiceLifetime = ServiceLifetime.Transient)] public interface ITransient : ILifetimeCycle { }
所以只要是继承了这三个接口的类都会自动实现注入,最后我们在Startup类中去注册这个扩展
services.RegisterDependency();
接下来我们看一个例子,如下
public class CommonBiz : ISingleton { private readonly IServiceConfigResolver serviceConfigResolver; private readonly IMemoryCache memoryCache; protected const string CACHE_PREFIX = "IAM_"; public CommonBiz(IServiceConfigResolver _serviceConfigResolver , IMemoryCache _memoryCache) { serviceConfigResolver = _serviceConfigResolver; memoryCache = _memoryCache; } #region Resource build public void BuildResponseStatus(ProcessStatus status, string domain, string code, params object[] errorParams) { status.IsSuccess = false; status.ResponseCode = code; status.ErrorMessage = ResourceMessageHelper.GetMessageContent(domain, code); status.ErrorMessage = string.Format(status.ErrorMessage, errorParams); } #endregion }
我们只需要CommonBiz继承ISingleTon即可,我们在看一个例子,这是一个DAL
public class MemberBufferDAL : IMemberBufferDAL, ISingleton { public bool CheckMemberDescriptionExist(int? memberCode, string memberDescription) { var dataCommand = DataCommandManager.GetDataCommand("CheckMemberDescriptionExist"); dataCommand.SetParameterValue("@MemberCode", memberCode); dataCommand.SetParameterValue("@MemberDescription", memberDescription); return dataCommand.ExecuteScalar<int?>().GetValueOrDefault(0) > 0; } }
那么他也只需要继承ISingleTon即可,那么最终在Biz层使用的时候如下
public class MemberBufferBiz : IMemberBufferBiz, ISingleton { private readonly IMemberBufferDAL memberBufferDAL; private readonly IMemberDAL memberDAL; private readonly CommonBiz commonBiz; private readonly IOptions<SystemConfigOptions> configOptions; public MemberBufferBiz( IMemberBufferDAL _memberBufferDAL , IMemberDAL _memberDAL , CommonBiz _commonBiz , IOptions<SystemConfigOptions> _configOptions) { memberBufferDAL = _memberBufferDAL; memberDAL = _memberDAL; commonBiz = _commonBiz; configOptions = _configOptions; } public List<MemberBufferEntity> GetMemberBufferByBufferID(string bufferIDs) { return memberBufferDAL.GetMemberBufferByBufferID(bufferIDs); } }
CommonBiz和memberBufferDAL自动实例化为单例。
ok,接下来我们看一些常规的配置,比如Json序列化我们不希望改变原实体的大小写,我们希望序列化忽略掉值为null的属性,我们同时也希望序列化自动去除字符串空格,那么我们配置如下
services.AddMvc().AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new JsonTrimConverter()); options.JsonSerializerOptions.PropertyNamingPolicy = null; options.JsonSerializerOptions.IgnoreNullValues = true; });
那我们主要看一下JsonTrimConverter类,在Read和Write的时候我们做一下处理就行了。
public class JsonTrimConverter : JsonConverter<string> { public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return reader.GetString()?.Trim(); } public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) { writer.WriteStringValue(value?.Trim()); } }