隐藏

.NET6中一些常用组件的配置及使用记录

发布:2022/6/23 22:05:15作者:管理员 来源:本站 浏览次数:1013

.NET 6的CoreApp框架,用来学习.NET6的一些变动和新特性,使用EFCore,等一系列组件的运用,每个用单独的文档篇章记录,持续更新文档哦。


如果对您有帮助,点击右上角⭐Star⭐关注 ,感谢支持开源!

软件架构


分为模型层,服务层,接口层来做测试使用

0.如何使用IConfiguration、Environment


直接在builder后的主机中使用。


builder.Configuration;

builder.Environment


1.如何使用Swagger


.NET 6 自带模板已经默认添加Swagger,直接使用即可。


builder.Services.AddSwaggerGen();


if (app.Environment.IsDevelopment())

{

   app.UseSwagger();

   app.UseSwaggerUI();

}


2. 如何添加EFCore到.NET 6中


按照EFCore常规使用方法,申明表的Entity及Dbcontext后,在program.cs文件中添加


builder.Services.AddDbContext<Service.DataContext>(opt => {

   opt.UseSqlServer(builder.Configuration.GetConnectionString("Default"));

});


即可在其他地方注入使用 DataContext


使用Sqlite数据库,需要引用 Microsoft.EntityFrameworkCore.Sqlite,

并在添加服务时,改为


opt.UseSqlite(builder.Configuration.GetConnectionString("Default"));


包管理控制台数据库结构生成方法:

使用 add-migration 创建迁移

使用 update-database 更新数据结构

3.如何注入一个服务


builder.Services.AddScoped<UserIdentyService>();


4.如何定义全局的using引用


在根目录下新建一个 cs文件,比如Globalusing.cs,在里面添加你的全局引用,和常规引用不同的是,在using前面添加 global


global using Service;

global using Entity;

global using Entity.Dto;


5.如何使用Autofac


添加 Nuget 引用


Autofac.Extensions.DependencyInjection


program.cs文件添加autofac的使用和注入配置


builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

builder.Host.ConfigureContainer<ContainerBuilder>(builder =>

{

    Assembly assembly = Assembly.Load("Service.dll");

    builder.RegisterAssemblyTypes(assembly)

           //.AsImplementedInterfaces()// 无接口的注入方式

           .InstancePerDependency();

});


此时即可构造函数注入使用。

6.如何使用Log4Net


添加引用


Microsoft.Extensions.Logging.Log4Net.AspNetCore


新建配置文件 log4net.config;

添加service配置


//注入Log4Net

builder.Services.AddLogging(cfg =>

{

   //默认的配置文件路径是在根目录,且文件名为log4net.config

   //cfg.AddLog4Net();

   //如果文件路径或名称有变化,需要重新设置其路径或名称

   //比如在项目根目录下创建一个名为config的文件夹,将log4net.config文件移入其中,并改名为log4net.config

   //则需要使用下面的代码来进行配置

   cfg.AddLog4Net(new Log4NetProviderOptions()

   {

       Log4NetConfigFileName = "config/log4net.config",

       Watch = true

   });

});


即可在需要的地方定义使用


_logger = LogManager.GetLogger(typeof(UserController));


7.如何使用全局异常过滤器


首先新建 GlobalExceptionFilter 全局异常过滤器,继承于 ExceptionFilter ,用于接收处理抛出的异常


public class GlobalExceptionFilter : IExceptionFilter

{

   readonly IWebHostEnvironment hostEnvironment;

   readonly ILog logger;

   public GlobalExceptionFilter(IWebHostEnvironment _hostEnvironment)

   {

       this.hostEnvironment = _hostEnvironment;

       this.logger = LogManager.GetLogger(typeof(GlobalExceptionFilter));

   }

   public void OnException(ExceptionContext context)

   {

       if (!context.ExceptionHandled)//如果异常没有处理

       {

           var result = new ApiResult

           {

               Code = 500,

               IsSuccess = false,

               Message = "服务器发生未处理的异常"

           };


           if (hostEnvironment.IsDevelopment())

           {

               result.Message += "," + context.Exception.Message;

               result.Data = context.Exception.StackTrace;

           }


           logger.Error(result);


           context.Result = new JsonResult(result);

           context.ExceptionHandled = true;//异常已处理

       }

   }

}


然后在Service中添加全局异常过滤器


builder.Services.AddControllers(option =>

   {

       option.Filters.Add<GlobalExceptionFilter>();

   }

);


添加控制器方法完成测试


[HttpGet("exception")]

public ApiResult ExceptionAction()

{

   throw new NotImplementedException();

}


8.如何使用redis做缓存


使用 StackExchange.Redis 作为缓存组件(其他组件类似的使用方式)。nuget 安装 StackExchange.Redis.Extensions.Core

首先,先建立一个类 RedisClient ,用于管理redis的连接和操作,再建立一个 RedisClientFactory 类,用于创建 redis的连接;


public class RedisClient{...}

public class RedisClientFactory{...}


appsettings.json 中添加redis的配置


"RedisConfig": {

   "Redis_Default": {

     "Connection": "127.0.0.1:6379",

     "InstanceName": "Redis1:"

   },

   "Redis_6": {

     "Connection": "127.0.0.1:6379",

     "DefaultDatabase": 6,

     "InstanceName": "Redis2:"

   }

 }


service中添加 redis客户端的引用


//添加redis的使用

builder.Services.AddSingleton<RedisClient>(_=> RedisClientFactory.GetInstance(builder.Configuration));


一顿操作后,就可以在你想要使用redis的地方引用了


RedisClient redisClient

...

this.redisDb = redisClient.GetDatabase("Redis_Default");

redisDb.StringSet("clientId", "clientId", TimeSpan.FromSeconds(10));


要使用redis做分布式缓存,先引用 Microsoft.Extensions.Caching.StackExchangeRedis


//将Redis分布式缓存服务添加到服务中

builder.Services.AddStackExchangeRedisCache(options =>

   {

       //用于连接Redis的配置  Configuration.GetConnectionString("RedisConnectionString")读取配置信息的串

       options.Configuration = "Redis_6";// Configuration.GetConnectionString("RedisConnectionString");

       //Redis实例名RedisDistributedCache

       options.InstanceName = "RedisDistributedCache";

   });


   引用自 "分布式 Redis 缓存"


9 如何添加使用定时任务组件


此处使用 Hangfire 定时任务组件,轻便,可持久化,还有面板。

引用 Hangfire 后,即可新增定时任务。


//启用Hangfire服务.

builder.Services.AddHangfire(x => x.UseStorage(new MemoryStorage()));

builder.Services.AddHangfireServer();


...


//启用Hangfire面板

app.UseHangfireDashboard();

//开启一个定时任务

RecurringJob.AddOrUpdate("test",() => Console.WriteLine("Recurring!"), Cron.Minutely());


访问 https://localhost:7219/hangfire 即可看到任务面板

10. 如何使用业务锁锁住下单或者支付操作


首先,做这个事需要能先构建出一个锁出来,这个锁有个锁的标识key,可以根据这个key判定key对应的锁是否存在,

这样的话,在某个用户支付或者下单减库存啥的时候,就可以按照这个key先上锁,后面有用户走其他渠道进行同样的操作的时候,就可以根据是否上锁了,来判断操作能否继续。


比如一个支付订单的业务,可以在手机上操作,也可以在电脑上操作,这个时候就可以给支付接口上锁,只要一个支付过程存在着,并且没有超时,那就不能在其他渠道进行操作。

我们上面已经使用了redis,下面就用redis构建个锁来模拟这个操作,具体看代码:


/// <summary>

   /// 测试业务锁

   /// </summary>

   /// <returns></returns>

   [HttpGet("lockhandle")]

   public async Task<ApiResult> LockHandle(int userId)

   {

       var key = "user";

       var token = $"ID:{userId}";

       try

       {

           if (redisDb.LockTake(key, token, TimeSpan.FromSeconds(50)))

           {

               await Task.Delay(30 * 1000);

               return await Task.FromResult(ApiResult.Success($"ID:{userId} 获取到锁了,操作正常,connectId:{Request.HttpContext.Connection.Id}"));

           }

           else

           {

               return await Task.FromResult(ApiResult.Fail($"有正在操作的锁,connectId:{Request.HttpContext.Connection.Id}"));

           }

       }

       catch (Exception)

       {

           throw;

       }

       finally

       {

           redisDb.LockRelease(key, token);

       }

   }


11. 如何配置跨域


此处主要记录全局跨域,不包括指定api跨域。先增加一个配置 "Cors": "http:127.0.0.1:5001",配置可以跨域的url,也可以使用默认跨域配置。

host配置以下服务,按需使用:


builder.Services.AddCors(delegate (CorsOptions options)

{

   options.AddPolicy("CorsPolicy", delegate (CorsPolicyBuilder corsBuilder)

   {

       //指定url跨域

       corsBuilder.WithOrigins(builder.Configuration.GetValue<string>("Cors").Split(','));

       //默认跨域

       corsBuilder.SetIsOriginAllowed((string _) => true).AllowAnyMethod().AllowAnyHeader()

           .AllowCredentials();

   });

});


12. 如何使用NewtonsoftJson


.NET6 默认的系列化库是内置的 System.Text.Json,使用中如果有诸多不熟悉的地方,那肯定是想换回 NewtonsoftJson,需要nuget 引用 Microsoft.AspNetCore.Mvc.NewtonsoftJson 来配置使用,

常用配置包括日期格式、大小写规则、循环引用配置。。。等,下面是一个配置


builder.Services.AddControllers(option =>

   {

       option.Filters.Add<GlobalExceptionFilter>();

   }

).AddNewtonsoftJson(options =>

{

   options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); //序列化时key为驼峰样式

   options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;

   options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";

   options.SerializerSettings.ReferenceLoopHandling =  ReferenceLoopHandling.Ignore;//忽略循环引用

});


13. 如何使用SignalR


首先添加一个 ChatHub 作为 交互中心处理器


public class ChatHub : Hub

   {

       public async Task SendMessage(string user, string message)

       {

           await Clients.All.SendAsync("ReceiveMessage", user, message);

       }

   }


在主机中使用服务


builder.Services.AddSignalR();

...

app.UseEndpoints(endpoints =>

{

   endpoints.MapHub<ChatHub>("/chatHub");

});