2021年10月24日 18:18
原创作品,转载时请务必以超链接形式标明文章原始出处,否则将追究法律责任。

西安转眼都到了冬天,春游暴龙峪,夏游太平峪仿佛就在昨天,冬季了就很少进山游玩了,昆明湖白鹿原转转就行了。

image.png

今天我们来看一下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());
    }
}


发表评论
匿名  
用户评论
暂无评论