文章目录
前言
1、.net core 执行过程
2、中间件的执行过程
3、AOP切面编程
Swagger
添加Swagger注释
1、右击项目->选择属性->点击生成->输出,选中文档文件
2、配置服务
在
program.cs
文件里配置
SwaggerUI
//增加项一
builder.Services.AddSwaggerGen(c=>{
c.SwaggerDoc("v1",newOpenApiInfo{ Title ="Web API", Version ="v1"});var xmlFile =$"{Assembly.GetEntryAssembly().GetName().Name}.xml";var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);});//增加项二if(app.Environment.IsDevelopment()){
app.UseSwagger();
app.UseSwaggerUI(c =>{
c.SwaggerEndpoint("/swagger/v1/swagger.json","My API V1");});}
3、在控制器的方法上加上注释即可在swagger网页上看到注释
4、添加实体类的Swagger注释
JWT
1、解析
1)客户端向授权服务系统发起请求,申请获取“令牌”。
2)授权服务根据用户身份,生成一张专属“令牌”,并将该“令牌”以JWT规范返回给客户端
3)客户端将获取到的“令牌”放到http请求的headers中后,向主服务系统发起请求。主服务系统收到请求后会从headers中获取“令牌”,并从“令牌”中解析出该用户的身份权限,然后做出相应的处理(同意或拒绝返回资源)
2、配置JWT
1、添加NuGet包
Microsoft.AspNetCore.Authentication.JwtBearer
2、在
appsettings.json
中添加JWT配置节点
"JWT":{"SecKey":"Jamin1127!#@$%@%^^&*(~Czmjklneafguvioszb%yuv&*6WVDf5dw#5dfw6f5w6faW%FW^f5wa65f^AWf56",//密钥"Issuer":"Jamin",//发行者"ExpireSeconds":7200//过期时间}
3、在Program类里进行服务注册
#region JWT服务// 注册JWT服务
builder.Services.AddSingleton(newJwtHelper(builder.Configuration));
builder.Services.AddAuthentication( JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>{
options.TokenValidationParameters =newTokenValidationParameters(){
ValidateIssuer =true,//是否验证Issuer
ValidIssuer = builder.Configuration["Jwt:Issuer"],//发行人Issuer
ValidateAudience =false,//是否验证Audience
ValidateIssuerSigningKey =true,//是否验证SecurityKey
IssuerSigningKey =newSymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecKey"])),//SecurityKey
ValidateLifetime =true,//是否验证失效时间
ClockSkew = TimeSpan.FromSeconds(30),//过期时间容错值,解决服务器端时间不同步问题(秒)
RequireExpirationTime =true,};});
builder.Services.AddAuthorization(options =>{/*** "Client" 策略要求用户必须拥有 "Client" 角色才能访问相关资源。
"Admin" 策略要求用户必须拥有 "Admin" 角色才能访问相关资源。
"SystemOrAdmin" 策略要求用户必须拥有 "Admin" 或者 "System" 角色之一才能访问相关资源。***/
options.AddPolicy("Client", policy => policy.RequireRole("Client").Build());
options.AddPolicy("Admin", policy => policy.RequireRole("Admin").Build());
options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin","System"));});#endregion//swagger里添加JWT授权
builder.Services.AddSwaggerGen(c=>{
c.SwaggerDoc("v1",newOpenApiInfo{ Title ="Web API", Version ="v1"});//开启注释var xmlFile =$"{Assembly.GetEntryAssembly().GetName().Name}.xml";var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath,true);// 配置 JWT Bearer 授权
c.AddSecurityDefinition("Bearer",newOpenApiSecurityScheme{
Description ="JWT Authorization header using the Bearer scheme",
Name ="Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme ="bearer"});var securityScheme =newOpenApiSecurityScheme{
Reference =newOpenApiReference{ Type = ReferenceType.SecurityScheme, Id ="Bearer"}};var securityRequirement =newOpenApiSecurityRequirement{{ securityScheme,newstring[]{}}};
c.AddSecurityRequirement(securityRequirement);});//启用验证中间件
app.UseAuthentication();
app.UseAuthorization();
4、创建JWT类进行Token配置
usingMicrosoft.IdentityModel.Tokens;usingSystem.Diagnostics;usingSystem.IdentityModel.Tokens.Jwt;usingSystem.Security.Claims;usingSystem.Text;namespaceBlog.core.Common.Auth{/// <summary>/// 授权JWT类/// </summary>publicclassJwtHelper{privatereadonlyIConfiguration _configuration;/// <summary>/// Token配置/// </summary>/// <param name="configuration"></param>publicJwtHelper(IConfiguration configuration){
_configuration = configuration;}/// <summary>/// 创建Token 这里面可以保存自己想要的信息/// </summary>/// <param name="username"></param>/// <param name="mobile"></param>/// <returns></returns>publicstringCreateToken(string username,string mobile){try{// 1. 定义需要使用到的Claimsvar claims =new[]{newClaim("username", username),newClaim("mobile", mobile),/* 可以保存自己想要信息,传参进来即可
new Claim("sex", "sex"),
new Claim("limit", "limit"),
new Claim("head_url", "xxxxx")
*/};// 2. 从 appsettings.json 中读取SecretKeyvar secretKey =newSymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecKey"]));// 3. 选择加密算法var algorithm = SecurityAlgorithms.HmacSha256;// 4. 生成Credentialsvar signingCredentials =newSigningCredentials(secretKey, algorithm);// 5. 根据以上,生成tokenvar jwtSecurityToken =newJwtSecurityToken(
_configuration["Jwt:Issuer"],//Issuer
_configuration["Jwt:ExpireSeconds"],//ExpireSeconds
claims,//Claims,
DateTime.Now,//notBefore
DateTime.Now.AddSeconds(30),//expires
signingCredentials //Credentials);// 6. 将token变为stringvar token =newJwtSecurityTokenHandler().WriteToken(jwtSecurityToken);return token;}catch(Exception){throw;}}/// <summary>/// 获取信息/// </summary>/// <param name="jwt"></param>/// <returns></returns>publicstaticstringReaderToken(string jwt){var str =string.Empty;try{//获取Token的三种方式//第一种直接用JwtSecurityTokenHandler提供的read方法var jwtHander =newJwtSecurityTokenHandler();JwtSecurityToken jwtSecurityToken = jwtHander.ReadJwtToken(jwt);
str = jwtSecurityToken.ToString();}catch(Exception ex){
Debug.WriteLine(ex.Message);}return str;}/// <summary>/// 解密jwt/// </summary>/// <param name="jwt"></param>/// <returns></returns>publicstringJwtDecrypt(string jwt){StringBuilder sb =newStringBuilder();try{JwtSecurityTokenHandler tokenHandler =new();TokenValidationParameters valParam =new();var securityKey =newSymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecKey"]));
valParam.IssuerSigningKey = securityKey;
valParam.ValidateIssuer =false;
valParam.ValidateAudience =false;//解密ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(jwt,
valParam,outSecurityToken secToken);foreach(var claim in claimsPrincipal.Claims){
sb.Append($"{claim.Type}={claim.Value}");}}catch(Exception ex){
Debug.WriteLine(ex.Message);}return sb.ToString();}}}
5、创建用户实体,进行用户密码的接收
usingSystem.ComponentModel.DataAnnotations;namespaceBlog.core.Models{publicclassUserInfo{/// <summary>/// 其中 [Required] 表示非空判断,其他自己研究百度/// </summary>[Required]publicstring UserName {get;set;}[Required]publicstring Password {get;set;}[Required]publicstring PhoneNumber {get;set;}}}
6、创建控制器,进行JWT的APi调用
usingBlog.core.Common.Auth;usingBlog.core.Models;usingMicrosoft.AspNetCore.Authorization;usingMicrosoft.AspNetCore.Mvc;namespaceBlog.core.Controllers{[Route("[controller]/[action]")][ApiController]publicclassUserController:ControllerBase{privatereadonlyJwtHelper _jwt;/// <summary>/// 初始化/// </summary>/// <param name="jwtHelper"></param>publicUserController(JwtHelper jwtHelper){
_jwt = jwtHelper;}/// <summary>/// 获取Token/// </summary>/// <returns></returns>[HttpPost]publicIActionResultGetToken(UserInfo user){//参数验证等等....if(string.IsNullOrEmpty(user.UserName)){returnOk("参数异常!");}//这里可以连接mysql数据库做账号密码验证//这里可以做Redis缓存验证等等//这里获取Token,当然,这里也可以选择传结构体过去var token = _jwt.CreateToken(user.UserName, user.PhoneNumber);//解密后的Tokenvar PWToken = _jwt.JwtDecrypt( token);returnOk(token+"解密后:"+PWToken);}/// <summary>/// 获取自己的详细信息,其中 [Authorize] 就表示要带Token才行/// </summary>/// <returns></returns>[HttpPost][Authorize]publicIActionResultGetSelfInfo(){//执行到这里,就表示已经验证授权通过了/*
* 这里返回个人信息有两种方式
* 第一种:从Header中的Token信息反向解析出用户账号,再从数据库中查找返回
* 第二种:从Header中的Token信息反向解析出用户账号信息直接返回,当然,在前面创建 Token时,要保存进使用到的Claims中。
*/returnOk("授权通过了!");}}}
7、用来验证权限的控制器
usingMicrosoft.AspNetCore.Authorization;usingMicrosoft.AspNetCore.Mvc;namespaceBlog.core.Controllers{[ApiController][Route("[controller]")][Authorize(Roles ="Admin")][Authorize(Roles ="User")]//增加权限验证publicclassWeatherForecastController:ControllerBase{privatestaticreadonlystring[] Summaries =new[]{"Freezing","Bracing","Chilly","Cool","Mild","Warm","Balmy","Hot","Sweltering","Scorching"};privatereadonlyILogger<WeatherForecastController> _logger;publicWeatherForecastController(ILogger<WeatherForecastController> logger){
_logger = logger;}/// <summary>/// 天气/// </summary>/// <remark></remark>[HttpGet]publicIEnumerable<WeatherForecast>Get(){return Enumerable.Range(1,5).Select(index =>newWeatherForecast{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20,55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]}).ToArray();}}}
**注:获取Token后在Swagger上输入token的value就可以进行接口的调用了 **
配置SqlSugar
0、引入
SqlSugarCore
包
1、编写
Context
类
publicstaticSqlSugarClient db =newSqlSugarClient(newConnectionConfig(){
ConnectionString ="server = 127.0.0.1; Database = test; Uid = root; Pwd = root; AllowLoadLocalInfile = true;",
DbType = DbType.MySql,//设置数据库类型
IsAutoCloseConnection =true,//自动释放数据务,如果存在事务,在事务结束后释放});
2、配置实体类
usingSqlSugar;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceBlog.Core.Model.Models{[SugarTable(tableName:"Person")]publicclassUser{[SugarColumn(IsPrimaryKey =true, IsIdentity =true)]publicint Id {get;set;}publicint Age {get;set;}publicstring? Name {get;set;}}}
3、创建
Service
服务类进行数据库的CRUD
usingBlog.core.IRepository;usingBlog.Core.Model.Models;usingstaticBlog.Core.Common.DbContext;namespaceBlog.Core.Repository{publicclassUserRepository:IUserRepository{publicintAdd(User user){var line = db.Insertable(user).ExecuteCommand();return line;}publicintDelete(int UserId){var line = db.Deleteable<User>(newUser{
Id = UserId
}).ExecuteCommand();return line;}publicList<User>GetUsers(int Id){List<User> users;if(Id isnot0){
users = db.Queryable<User>().Where(it => it.Id == Id).ToList();}else{
users = db.Queryable<User>().ToList();}return users;}publicintUpdate(User user){var res = db.Updateable<User>(user).ExecuteCommand();return res;}}}
4、配置Controller进行路由
usingBlog.core.Models;usingBlog.Core.Auth;usingBlog.Core.IServices;usingBlog.Core.Model.Models;usingMicrosoft.AspNetCore.Authorization;usingMicrosoft.AspNetCore.Mvc;usingBlog.Core.Services;namespaceBlog.core.Controllers{[Route("[controller]/[action]")][ApiController]publicclassUserController:ControllerBase{privatereadonlyIUserService _userService;publicUserController(IUserService userService){
_userService = userService;}/// <summary>/// 增加/// </summary>/// <param name="user"></param>/// <returns></returns>[HttpPost]publicintAddUser(User user){// User user = new User() { Id = 2024325, Name = "Czm", Age = 20 };return _userService.Add(user);}/// <summary>/// 删除/// </summary>/// <param name="id"></param>/// <returns></returns>[HttpDelete]publicintDeleteUser(int id){return _userService.Delete(id);}/// <summary>/// 更新/// </summary>/// <param name="user"></param>/// <returns></returns>[HttpPut]publicintUpdateUsre(User user){return _userService.Update(user);}/// <summary>/// 获取数据/// </summary>/// <param name="id"></param>/// <returns></returns>[HttpGet]publicList<User>GetUser(int id){return _userService.GetUsers(id);}}}
依赖注入与IOC
IOC
IOC 是 Inversion of Control(控制反转)的缩写。在软件开发中,IOC 是一种设计模式,它改变了传统的程序设计流程,使得对象之间的依赖关系由代码本身控制变为由外部容器控制。
而采用IOC 设计模式后,对象之间的依赖关系由外部容器来管理和注入,对象本身不需要关心依赖的具体实现,只需要定义自己的接口或抽象类,并在外部容器中配置依赖关系。这样可以降低代码的耦合度,提高代码的灵活性、可维护性和可扩展性。
常见的IOC 容器包括 Spring Framework 中的 Spring IoC ,dotnet中的autofoc,它通过依赖注入(Dependency Injection)的方式来实现控制反转。通过IOC 容器,可以将对象之间的依赖关系集中管理,实现了代码的松耦合,使得程序更易于理解、扩展和维护。
依赖注入DI
1、继承接口并实现构造方法
publicclassUserService:IUserService{privateIUserRepository _userService ;publicUserService(IUserRepository userService){
_userService = userService;}}
2、在program里加上
builder.Services.AddTransient<IUserRepository, UserRepository>();
builder.Services.AddTransient<IUserService, UserService>();
.net提供了三种生命周期的容器
builder.Services.AddTransient<IOperationTransient, Operation>(); builder.Services.AddScoped<IOperationScoped, Operation>(); builder.Services.AddSingleton<IOperationSingleton, Operation>();
- 暂时性对象始终不同。
IndexModel
和中间件中的临时OperationId
值不同。- 范围内对象对给定请求而言是相同的,但在每个新请求之间不同。
- 单一实例对象对于每个请求是相同的。
3、Controller层使用
publicclassUserController:ControllerBase{privatereadonlyIUserService _userService ;publicUserController(IUserService userService){
_userService = userService;}}
Autofac轻量容器的使用
1、安装Nuget包
Autofac.Extensions.DependencyInjection
和
Autofac.Extras.DynamicProxy
2、使用程序集注册,通过Model注册(这里只列这一种Auto官方文档Assembly Scanning — Autofac 7.0.0 documentation)
**创建Model类 **
usingAutofac;usingBlog.Core.IServices;usingMicrosoft.AspNetCore.Mvc;usingMicrosoft.Extensions.DependencyModel;usingSystem.Reflection;usingSystem.Runtime.Loader;namespaceBlog.Core.Configuration.AutoModule{publicclassServiceModel:Autofac.Module{protectedoverridevoidLoad(ContainerBuilder builder){// 自动对集成 IDependency 接口的类进行注册Type baseType =typeof(IUserService);var compilationLibrary = DependencyContext.Default.CompileLibraries.Where(x =>!x.Serviceable && x.Type =="project").ToList();List<Assembly> assemblyList =newList<Assembly>();foreach(var _compilation in compilationLibrary){try{
assemblyList.Add(AssemblyLoadContext.Default.LoadFromAssemblyName(newAssemblyName(_compilation.Name)));}catch(Exception ex){
Console.WriteLine(_compilation.Name + ex.Message);}}
builder.RegisterAssemblyTypes(assemblyList.ToArray()).Where(type => baseType.IsAssignableFrom(type)&&!type.IsAbstract).AsSelf().AsImplementedInterfaces().PropertiesAutowired().InstancePerLifetimeScope();var controllersTypesInAssembly =typeof(Program).Assembly.GetExportedTypes().Where(type =>typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
builder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired();}}}
**在program.cs中解析Model **
builder.Host.UseServiceProviderFactory(newAutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(i => i.RegisterModule<ServiceModel>());
builder.Services.AddControllers().AddControllersAsServices();
在Controller中使用
publicclassUserController:ControllerBase{privatereadonlyIUserService _userService ;publicUserController(IUserService userService){
_userService = userService;}}
使用Autofac完成AOP日志
1、编写AOP类
usingCastle.DynamicProxy;usingNewtonsoft.Json;usingStackExchange.Profiling;usingSystem.Reflection;namespaceBlog.Core.AOP{/// <summary>/// 拦截器BlogLogAOP 继承IInterceptor接口/// </summary>publicclassBlogLogAOP:IInterceptor{/// <summary>/// 实例化IInterceptor唯一方法/// </summary>/// <param name="invocation">包含被拦截方法的信息</param>publicvoidIntercept(IInvocation invocation){string UserName ="Jamin";//记录被拦截方法信息的日志信息var dataIntercept =""+$"【当前操作用户】:{UserName} \r\n"+$"【当前执行方法】:{invocation.Method.Name} \r\n"+$"【携带的参数有】: {string.Join(", ", invocation.Arguments.Select(a =>(a ??"").ToString()).ToArray())} \r\n";try{
MiniProfiler.Current.Step($"执行Service方法:{invocation.Method.Name}() -> ");//在被拦截的方法执行完毕后 继续执行当前方法,注意是被拦截的是异步的
invocation.Proceed();// 异步获取异常,先执行if(IsAsyncMethod(invocation.Method)){//Wait task execution and modify return valueif(invocation.Method.ReturnType ==typeof(Task)){
invocation.ReturnValue = InternalAsyncHelper.AwaitTaskWithPostActionAndFinally((Task)invocation.ReturnValue,
ex =>{LogEx(ex,ref dataIntercept);});}else//Task<TResult>{
invocation.ReturnValue = InternalAsyncHelper.CallAwaitTaskWithPostActionAndFinallyAndGetResult(
invocation.Method.ReturnType.GenericTypeArguments[0],
invocation.ReturnValue,
ex =>{LogEx(ex,ref dataIntercept);});}}else{// 同步1 }}catch(Exception ex)// 同步2{LogEx(ex,ref dataIntercept);}var type = invocation.Method.ReturnType;if(typeof(Task).IsAssignableFrom(type)){var resultProperty = type.GetProperty("Result");
dataIntercept +=($"【执行完成结果】:{JsonConvert.SerializeObject(resultProperty.GetValue(invocation.ReturnValue))}");}else{
dataIntercept +=($"【执行完成结果】:{invocation.ReturnValue}");}// 你的日志记录 比如log4#region 输出到当前项目日志var path = Directory.GetCurrentDirectory()+@"\Log";if(!Directory.Exists(path)){
Directory.CreateDirectory(path);}string fileName = path +$@"\InterceptLog-{DateTime.Now.ToString("yyyyMMddHHmmss")}.log";StreamWriter sw = File.AppendText(fileName);
sw.WriteLine(dataIntercept);
sw.Close();#endregion}privatevoidLogEx(Exception ex,refstring dataIntercept){if(ex !=null){//执行的 service 中,收录异常
MiniProfiler.Current.CustomTiming("Errors:", ex.Message);//执行的 service 中,捕获异常
dataIntercept +=($"方法执行中出现异常:{ex.Message + ex.InnerException}\r\n");}}publicstaticboolIsAsyncMethod(MethodInfo method){return(
method.ReturnType ==typeof(Task)||(method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition()==typeof(Task<>)));}}internalstaticclassInternalAsyncHelper{publicstaticasyncTaskAwaitTaskWithPostActionAndFinally(Task actualReturnValue,Action<Exception> finalAction){Exception exception =null;try{await actualReturnValue;}catch(Exception ex){
exception = ex;}finally{finalAction(exception);}}publicstaticasyncTask<T>AwaitTaskWithPostActionAndFinallyAndGetResult<T>(Task<T> actualReturnValue,Func<Task> postAction,Action<Exception> finalAction){Exception exception =null;try{var result =await actualReturnValue;awaitpostAction();return result;}catch(Exception ex){
exception = ex;throw;}finally{finalAction(exception);}}publicstaticobjectCallAwaitTaskWithPostActionAndFinallyAndGetResult(Type taskReturnType,object actualReturnValue,Action<Exception> finalAction){returntypeof(InternalAsyncHelper).GetMethod("AwaitTaskWithPostActionAndFinallyAndGetResult", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(taskReturnType).Invoke(null,[actualReturnValue,finalAction]);}}}
2、进行服务注册
builder.Host.UseServiceProviderFactory(newAutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(build =>{// AOP var cacheType =newList<Type>();
build.RegisterType<BlogLogAOP>();
cacheType.Add(typeof(BlogLogAOP));// 获取 Service.dll 程序集服务,并注册var assemblysServices = Assembly.LoadFrom(servicesDllFile);
build.RegisterAssemblyTypes(assemblysServices).AsImplementedInterfaces().InstancePerDependency().EnableInterfaceInterceptors()//引用Autofac.Extras.DynamicProxy;.InterceptedBy(cacheType.ToArray());//允许将拦截器服务的列表分配给注册。// 获取 Repository.dll 程序集服务,并注册var assemblysRepository = Assembly.LoadFrom(repositoryDllFile);
build.RegisterAssemblyTypes(assemblysRepository).AsImplementedInterfaces().InstancePerDependency();});
使用扩展进行服务注册
1、创建
utils
文件夹
2、创建Swagger、AOP、JWT的类
Swagger
usingMicrosoft.OpenApi.Models;usingSystem.Reflection;namespaceBlog.Core.Helper{publicstaticclassSwaggerExt{publicstaticvoidAddSwagger(thisIServiceCollection services){
services.AddSwaggerGen(c =>{
c.SwaggerDoc("v1",newOpenApiInfo{ Title ="Web API", Version ="v1"});//开启注释var xmlFile =$"{Assembly.GetEntryAssembly().GetName().Name}.xml";var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath,true);// 配置 JWT Bearer 授权
c.AddSecurityDefinition("Bearer",newOpenApiSecurityScheme{
Description ="JWT Authorization header using the Bearer scheme",
Name ="Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme ="bearer"});var securityScheme =newOpenApiSecurityScheme{
Reference =newOpenApiReference{ Type = ReferenceType.SecurityScheme, Id ="Bearer"}};var securityRequirement =newOpenApiSecurityRequirement{{ securityScheme,newstring[]{}}};
c.AddSecurityRequirement(securityRequirement);});}publicstaticvoidUseSwagger(thisWebApplication application){
application.UseSwagger();
application.UseSwaggerUI(c =>{
c.SwaggerEndpoint("/swagger/v1/swagger.json","My API V1");});}}}
AOP
usingAutofac.Extensions.DependencyInjection;usingAutofac;usingBlog.Core.AOP;usingSystem.Reflection;usingAutofac.Extras.DynamicProxy;namespaceBlog.Core.Helper{publicstaticclassAOPAndIOCExt{publicstaticvoidAddAOP(thisWebApplicationBuilder builder){//IOC//builder.Services.AddTransient<IUserRepository, UserRepository>();//builder.Services.AddTransient<IUserService, UserService>();var basePath = AppContext.BaseDirectory;var servicesDllFile = Path.Combine(basePath,"Blog.Core.Services.dll");//服务层var repositoryDllFile = Path.Combine(basePath,"Blog.Core.Repository.dll");//仓储层if(!(File.Exists(servicesDllFile)&& File.Exists(repositoryDllFile))){thrownewException("Repository.dll和service.dll 丢失,因为项目解耦了,所以需要先F6编译,再F5运行,请检查 bin 文件夹,并拷贝。");}
builder.Host.UseServiceProviderFactory(newAutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(build =>{// AOP var cacheType =newList<Type>();
build.RegisterType<BlogLogAOP>();
cacheType.Add(typeof(BlogLogAOP));// 获取 Service.dll 程序集服务,并注册var assemblysServices = Assembly.LoadFrom(servicesDllFile);
build.RegisterAssemblyTypes(assemblysServices).AsImplementedInterfaces().InstancePerDependency().EnableInterfaceInterceptors()//引用Autofac.Extras.DynamicProxy;.InterceptedBy(cacheType.ToArray());//允许将拦截器服务的列表分配给注册。// 获取 Repository.dll 程序集服务,并注册var assemblysRepository = Assembly.LoadFrom(repositoryDllFile);
build.RegisterAssemblyTypes(assemblysRepository).AsImplementedInterfaces().InstancePerDependency();});}}}
JWT
usingMicrosoft.AspNetCore.Authentication.JwtBearer;usingMicrosoft.IdentityModel.Tokens;usingSystem.Text;namespaceBlog.Core.Helper{publicstaticclassJWTExt{publicstaticvoidAddJWT(thisWebApplicationBuilder builder){
builder.Services.AddSingleton(newAuth.JwtHelper(builder.Configuration));
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>{
options.TokenValidationParameters =newTokenValidationParameters(){
ValidateIssuer =true,//是否验证Issuer
ValidIssuer = builder.Configuration["Jwt:Issuer"],//发行人Issuer
ValidateAudience =false,//是否验证Audience
ValidateIssuerSigningKey =true,//是否验证SecurityKey
IssuerSigningKey =newSymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecKey"])),//SecurityKey
ValidateLifetime =true,//是否验证失效时间
ClockSkew = TimeSpan.FromSeconds(30),//过期时间容错值,解决服务器端时间不同步问题(秒)
RequireExpirationTime =true,};});
builder.Services.AddAuthorization(options =>{/*** "Client" 策略要求用户必须拥有 "Client" 角色才能访问相关资源。
"Admin" 策略要求用户必须拥有 "Admin" 角色才能访问相关资源。
"SystemOrAdmin" 策略要求用户必须拥有 "Admin" 或者 "System" 角色之一才能访问相关资源。***/
options.AddPolicy("Client", policy => policy.RequireRole("Client").Build());
options.AddPolicy("Admin", policy => policy.RequireRole("Admin").Build());
options.AddPolicy("System", policy => policy.RequireRole("System").Build());
options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin","System"));
options.AddPolicy("ClientOrAdmin", policy => policy.RequireRole("Admin","Client"));});}}}
3、在
program
类里进行 调用
usingAutofac;usingAutofac.Extensions.DependencyInjection;usingAutofac.Extras.DynamicProxy;usingBlog.Core.AOP;usingBlog.Core.Auth;usingBlog.Core.Helper;usingMicrosoft.AspNetCore.Authentication.JwtBearer;usingMicrosoft.IdentityModel.Tokens;usingMicrosoft.OpenApi.Models;usingSystem.Reflection;usingSystem.Text;var builder = WebApplication.CreateBuilder(args);// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddMemoryCache();// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle#region JWT服务
builder.AddJWT();#endregion#regionSwagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwagger();#endregion#regionAOPAndIOC
builder.AddAOP();#endregion//跨域
builder.Services.AddCors(options =>{
options.AddPolicy("CorsPolicy", opt => opt.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().WithExposedHeaders("X-Pagination"));});var app = builder.Build();
app.UseStaticFiles();
app.UseRouting();
app.UseCors("CorsPolicy");// Configure the HTTP request pipeline.if(app.Environment.IsDevelopment()){
app.UseSwagger();}//启用验证中间件
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Webapi的操作返回值和方法参数
返回值ActionResult
ASP.NET Core Web API中的操作方法的返回值如果是普通数据类型,那么返回值就会默认被序列化为JSON格式的响应报文体返回。
1[HttpGet("{id}")]2publicActionResult<Person>GetPerson(int id)3{4if(id <=0)5return person;10else11returnNotFound(newErrorInfo(2,"人员不存在"));12}
注:一般是创建一个ResInfo类{code,message}作为返回的实体。符合Restful开发
操作方法的参数
我们在给服务器端传递参数的时候,有URL、QueryString、请求报文体3种方式。
URL
如果GetAll方法的参数中有同名的参数,那么这个参数就会被自动赋值。如果捕捉的占位符的名字和参数名一致,那么我们就不需要为参数添加[FromRoute];如果占位符的名字和参数名不一致,我们就需要为参数添加[FromRoute],并且通过[FromRoute]的Name属性来设置匹配的占位符的名字,比如一个名字为classNum的参数要想获得占位符中{classNo}的值,那么我们就要为classNum参数添加[FromRoute(Name=“classNo”)]
1[HttpGet("school/{schoolName}/class/{classNo}")]2publicActionResult<Student[]>GetAll(string schoolName,3[FromRoute(Name ="classNo")]string classNum)
QueryString
对于通过QueryString传递的参数,我们使用[FromQuery]来获取值。如果操作方法的参数的名字和我们要获取的QueryString的名字一致,我们只要为参数添加[FromQuery]即可;如果操作方法的参数的名字和要获取的QueryString的名字不一致,我们就要为设定【FromQuery】的Name属性指定和QueryString中一样的名字。
1publicActionResult<Student[]>GetAll([FromQuery]string pageNum,2[FromQuery(Name ="pSize")]int pageSize)
URL和QueryString混用
1[HttpGet("school/{schoolName}/class/{classNo}")]2publicActionResult<Student[]>GetAll(string schoolName,3[FromRoute(Name ="classNo")]string classNum,4[FromQuery]string pageNum,[FromQuery(Name ="pSize")]int pageSize)
请求报文体
参数为实体类,在请求报文体(Body)里发送相应的Json数据就可以直接接收
1[HttpPost]2publicActionResultAddNew(Student s)
总结
对于GET、DELETE等请求,我们尽量从URL或者QueryString中获取数据;对于PUT、POST等请求,我们尽量通过JSON格式的报文体获取数据,当然我们一定要设定请求报文头中的Content-Type的值为application/json。
VUE项目结构
project-name/
│
├── public/
│ ├── index.html # 主HTML文件
│ └── ...
│
├── src/
│ ├── assets/ # 静态资源,如图片、字体等
│ ├── components/ # Vue组件
│ ├── views/ # 页面级组件
│ ├── router/ # 路由配置
│ ├── store/ # Vuex状态管理相关文件
│ ├── utils/ # 工具函数、帮助类等
│ ├── styles/ # 全局样式文件
│ ├── App.vue # 根组件
│ └── main.js # 入口文件
│
├── tests/ # 测试文件夹
│
├── node_modules/ # 依赖的第三方包
│
├── .gitignore # Git忽略文件配置
├── babel.config.js # Babel配置文件
├── package.json # 项目配置及依赖管理文件
└── README.md # 项目说明文件
public 目录包含了静态资源,例如 HTML 入口文件和网站图标。
src 目录是主要的工作目录,包含了所有的源代码。
assets 存放应用中使用的静态资源,例如图片、字体等。
components 包含了应用中的 Vue 组件。
views 包含了页面级别的 Vue 组件。
router 包含了 Vue Router 的路由配置。
store 包含了 Vuex 的状态管理相关文件。
styles 包含了全局样式文件。
utils 包含了应用中可能用到的工具函数。
App.vue 是根组件,通常包含应用的整体结构和布局。
main.js 是应用的入口文件,用于初始化 Vue 实例和加载其他组件。
tests 目录包含应用的测试文件。
.gitignore 是 Git 忽略文件配置,指定不需要被版本控制的文件和目录。
babel.config.js 是 Babel 的配置文件,用于指定 JavaScript 代码的转换规则。
package.json 是项目的配置文件,包含了项目的依赖和一些脚本命令。
README.md 是项目的说明文件,通常包含了项目的介绍、安装方法和使用说明等。
vue.config.js 是 Vue CLI 的配置文件,用于配置构建工具的行为,如 webpack、babel 等(这是可选的,只有在需要自定义配置时才添加)。
主要文件
- main.ts : 进行vue的注入、路由的注入、ui组件的注入
- App.vue : 项目的主界面,其他组件进行插入到这个界面显示视图
- router/index.ts :进行页面路由
- components : 其他页面的视图,用来插入到App.vue中
项目运行流程
vite 项目的运行流程
在工程化的项目中,vue 要做的事情很单纯:通过 main.js 把 App.vue 渲染到 index.html 的指定区域中
其中:
① App.vue 用来编写待渲染的 模板结构
② index.html 中需要预留一个 el 区域
③ main.js 把 App.vue 渲染到了 index.html 所预留的区域中
添加Element-ui、AXIOS
**注:elementui在VUE3进行了更改
npm i element-plus
**
**Axios:
npm install --save axios
**
注:Nodejs下载完成后需要换源
npm config set registry https://registry.npm.taobao.org
Axios与pinia
AXIOS
Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js
http
模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。
使用npm等包管理工具下载axios
npm i axios
创建axios实例、封装get、post请求方法
import axios from"axios";import{ user }from"@/store/Store";const requestUrl ="http://localhost:5250";const userStore =user();//创建实例const axiosInstance = axios.create({
baseURL: requestUrl,// timeout: 3000,});//请求拦截器,请求前
axiosInstance.interceptors.request.use((config)=>{if(userStore.data){// console.log("请求头toekn=====>", userStore.data.token);// 设置请求头// config.headers['token'] = useToken.token;
config.headers.Authorization =`Bearer ${userStore.data.token}`;}return config;},(error)=>{returnPromise.reject(error);});//请求拦截器,请求后
axiosInstance.interceptors.response.use((response)=>{if(response.status ===200)return response.data;},(error)=>{console.log(error);const status:number= error.response.status;switch(status){case404:console.error("资源不存在");break;case401:console.error("没有权限");break;case500:case501:case502:console.error("没有权限");break;case400:console.error(error.response.data.msg +"参数错误");break;default:console.log("无法识别");break;}returnPromise.reject(error);});interfaceActionResult<T>{
data:T;
msg:string;
error:any;
code:number;}//get请求exportconst get =<T>(
url:string,
params?: Object
):Promise<ActionResult<T>>=>{return axiosInstance.get(url,{ params });};//post请求exportconst post =<T>(
url:string,
data?: Object
):Promise<ActionResult<T>>=>{return axiosInstance.post(url, data);};//put请求exportconst put =<T>(
url:string,
data?: Object
):Promise<ActionResult<T>>=>{return axiosInstance.put(url, data);};//delete请求exportconst delete1 =<T>(
url:string,
params?: Object
):Promise<ActionResult<T>>=>{return axiosInstance.delete(url,{ params });};
封装api接口调用方法
import{ get, post, delete1, put }from"./request";import{ user }from"@/types/index";exportconstloginApi=(data: user)=>{returnpost<any>("/api/Login/login", data);};exportconstgetUserInfo=(ID:string)=>{returnget<any>("/api/Index/UserInfo",{ID});};
在页面中调用api
import{ loginApi }from"@/common/api";constemailLoginApi=async()=>{
phoneLoding.value =true;try{const res =awaitloginApi({EMAIL: emailNumber.value,PASSWORD: PassWard.value,});// localStorage.setItem("userInfo", JSON.stringify(res.data.token));// Cookies.set("token", res.data.token);console.log(res);
userStore.setData(res.data);console.log(userStore.data);
$router.push("/index");
phoneLoding.value =false;}catch(error){
phoneLoding.value =false;}};
pinia使用
使用npm下载pinia
npm i pinia
创建Store文件进行状态存储
import{ defineStore }from"pinia";exportconst user =defineStore("userInfo",{state:()=>({
data:{ id:"", Name:"", token:"", Email:""},}),
actions:{setData(payload:any){this.data = payload;},},});
在页面组件中实例化状态并赋值
import{ user }from"@/store/Store";const userStore =user();// 实例化 store
userStore.setData(res.data);
版权归原作者 以明志、 所有, 如有侵权,请联系我们删除。