ASP.NET前后端分离,WebApi。Vue3+ElementPlus+Axios+Pinia全流程教程

news2024/11/28 2:48:44

文章目录

  • 前言
    • 1、.net core 执行过程
    • 2、中间件的执行过程
    • 3、AOP切面编程
  • Swagger
    • 添加Swagger注释
  • JWT
    • 1、解析
    • 2、配置JWT
  • 配置SqlSugar
    • 0、引入`SqlSugarCore`包
    • 1、编写`Context`类
    • 2、配置实体类
    • 3、创建`Service`服务类进行数据库的CRUD
    • 4、配置Controller进行路由
  • 依赖注入与IOC
    • IOC
    • 依赖注入DI
    • Autofac轻量容器的使用
    • 使用Autofac完成AOP日志
  • Webapi的操作返回值和方法参数
    • 返回值ActionResult
    • 操作方法的参数
      • URL
      • QueryString
      • 请求报文体
      • 总结
  • VUE项目结构
    • 主要文件
    • 项目运行流程
    • 添加Element-ui、AXIOS
  • Axios与pinia
    • AXIOS
      • 使用npm等包管理工具下载axios
      • 创建axios实例、封装get、post请求方法
      • 封装api接口调用方法
      • 在页面中调用api
    • pinia使用
      • 使用npm下载pinia
      • 创建Store文件进行状态存储
      • 在页面组件中实例化状态并赋值

前言

1、.net core 执行过程

img

2、中间件的执行过程

img

3、AOP切面编程

img

img

Swagger

添加Swagger注释

1、右击项目->选择属性->点击生成->输出,选中文档文件
在这里插入图片描述

2、配置服务

program.cs 文件里配置SwaggerUI

//增加项一
builder.Services.AddSwaggerGen(c=> {
    c.SwaggerDoc("v1", new OpenApiInfo { 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(new JwtHelper(builder.Configuration));

builder.Services.AddAuthentication( JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters()
    {
        ValidateIssuer = true, //是否验证Issuer
        ValidIssuer = builder.Configuration["Jwt:Issuer"], //发行人Issuer
        ValidateAudience = false, //是否验证Audience      
        ValidateIssuerSigningKey = true, //是否验证SecurityKey
        IssuerSigningKey = new SymmetricSecurityKey(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", new OpenApiInfo { 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", new OpenApiSecurityScheme
    {
        Description = "JWT Authorization header using the Bearer scheme",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.Http,
        Scheme = "bearer"
    });

    var securityScheme = new OpenApiSecurityScheme
    {
        Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
    };
    var securityRequirement = new OpenApiSecurityRequirement { { securityScheme, new string[] { } } };
    c.AddSecurityRequirement(securityRequirement);
});
//启用验证中间件
app.UseAuthentication();
app.UseAuthorization();

4、创建JWT类进行Token配置

using Microsoft.IdentityModel.Tokens;
using System.Diagnostics;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace Blog.core.Common.Auth
{
    /// <summary>
    /// 授权JWT类
    /// </summary>
    public class JwtHelper
    {
        private readonly IConfiguration _configuration;

        /// <summary>
        /// Token配置
        /// </summary>
        /// <param name="configuration"></param>
        public JwtHelper(IConfiguration configuration)
        {
            _configuration = configuration;
        }
        
        /// <summary>
        /// 创建Token 这里面可以保存自己想要的信息
        /// </summary>
        /// <param name="username"></param>
        /// <param name="mobile"></param>
        /// <returns></returns>
        public string CreateToken(string username, string mobile)
        {
            try
            {
                // 1. 定义需要使用到的Claims
                var claims = new[]
                {
                    new Claim("username", username),
                    new Claim("mobile", mobile),
                    /* 可以保存自己想要信息,传参进来即可
                    new Claim("sex", "sex"),
                    new Claim("limit", "limit"),
                    new Claim("head_url", "xxxxx")
                    */
                };

                // 2. 从 appsettings.json 中读取SecretKey
                var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecKey"]));

                // 3. 选择加密算法
                var algorithm = SecurityAlgorithms.HmacSha256;

                // 4. 生成Credentials
                var signingCredentials = new SigningCredentials(secretKey, algorithm);

                // 5. 根据以上,生成token
                var jwtSecurityToken = new JwtSecurityToken(
                    _configuration["Jwt:Issuer"],    //Issuer
                    _configuration["Jwt:ExpireSeconds"],  //ExpireSeconds
                    claims,                          //Claims,
                    DateTime.Now,                    //notBefore
                    DateTime.Now.AddSeconds(30),     //expires
                    signingCredentials               //Credentials
                );

                // 6. 将token变为string
                var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);

                return token;
            }
            catch (Exception)
            {

                throw;
            }
           
        }
        /// <summary>
        /// 获取信息
        /// </summary>
        /// <param name="jwt"></param>
        /// <returns></returns>
        public static string ReaderToken(string jwt)
        {
            var str = string.Empty;
            try
            {
                //获取Token的三种方式
                //第一种直接用JwtSecurityTokenHandler提供的read方法
                var jwtHander = new JwtSecurityTokenHandler();
                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>
        public string JwtDecrypt(string jwt)
        {
           
            StringBuilder sb = new StringBuilder();
            try
            {
                JwtSecurityTokenHandler tokenHandler = new();
                TokenValidationParameters valParam = new();
                var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecKey"]));
                valParam.IssuerSigningKey = securityKey;
                valParam.ValidateIssuer = false;
                valParam.ValidateAudience = false;
                //解密
                ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(jwt,
                        valParam, out SecurityToken secToken);
                foreach (var claim in claimsPrincipal.Claims)
                {
                    sb.Append($"{claim.Type}={claim.Value}");
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            return sb.ToString();
        }
    }

}

5、创建用户实体,进行用户密码的接收

using System.ComponentModel.DataAnnotations;

namespace Blog.core.Models
{
    public class UserInfo
    {
        /// <summary>
        /// 其中 [Required] 表示非空判断,其他自己研究百度
        /// </summary>
        [Required]
        public string UserName { get; set; }
        [Required]
        public string Password { get; set; }
        [Required]
        public string PhoneNumber { get; set; }

}
}

6、创建控制器,进行JWT的APi调用

using Blog.core.Common.Auth;
using Blog.core.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Blog.core.Controllers
{
   
        [Route("[controller]/[action]")]
        [ApiController]
        public class UserController : ControllerBase
        {
            private readonly JwtHelper _jwt;

            /// <summary>
            /// 初始化
            /// </summary>
            /// <param name="jwtHelper"></param>
            public UserController(JwtHelper jwtHelper)
            {
                _jwt = jwtHelper;
            }
            /// <summary>
            /// 获取Token
            /// </summary>
            /// <returns></returns>
            [HttpPost]
            public IActionResult GetToken(UserInfo user)
            {
                //参数验证等等....
                if (string.IsNullOrEmpty(user.UserName))
                {
                    return Ok("参数异常!");
                }

                //这里可以连接mysql数据库做账号密码验证


                //这里可以做Redis缓存验证等等


                //这里获取Token,当然,这里也可以选择传结构体过去
                var token = _jwt.CreateToken(user.UserName, user.PhoneNumber);
                  //解密后的Token
                  var PWToken = _jwt.JwtDecrypt( token);
                  return Ok(token+"解密后:"+PWToken);
     
            }

            /// <summary>
            /// 获取自己的详细信息,其中 [Authorize] 就表示要带Token才行
            /// </summary>
            /// <returns></returns>
            [HttpPost]
            [Authorize]
            public IActionResult GetSelfInfo()
            {
                //执行到这里,就表示已经验证授权通过了
                /*
                 * 这里返回个人信息有两种方式
                 * 第一种:从Header中的Token信息反向解析出用户账号,再从数据库中查找返回
                 * 第二种:从Header中的Token信息反向解析出用户账号信息直接返回,当然,在前面创建        Token时,要保存进使用到的Claims中。
                */
                return Ok("授权通过了!");
            }
        }  
}

7、用来验证权限的控制器

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Blog.core.Controllers
{
   
    [ApiController]
    [Route("[controller]")]
    [Authorize(Roles ="Admin")]
    [Authorize(Roles ="User")]//增加权限验证
    public class WeatherForecastController : ControllerBase 
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> _logger;    
        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }
        /// <summary>
        /// 天气
        /// </summary>
        /// <remark></remark>
        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                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

  public static SqlSugarClient db = new SqlSugarClient(
                  new ConnectionConfig()
                  {
                      ConnectionString = "server = 127.0.0.1; Database = test; Uid = root; Pwd = root; AllowLoadLocalInfile = true;",
                      DbType = DbType.MySql,//设置数据库类型
                      IsAutoCloseConnection = true,//自动释放数据务,如果存在事务,在事务结束后释放
                  });

2、配置实体类

using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Blog.Core.Model.Models
{
    [SugarTable(tableName: "Person")]
    public class User
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }
        public int Age { get; set; }
        public string? Name { get; set; }

    }
}

3、创建Service服务类进行数据库的CRUD

using Blog.core.IRepository;
using Blog.Core.Model.Models;
using static Blog.Core.Common.DbContext;
namespace Blog.Core.Repository
{
    public class UserRepository : IUserRepository
    {
        public  int Add(User user)
        {
            var line = db.Insertable(user).ExecuteCommand();
            return line;
        }

        public int Delete(int UserId)
        {
            var line = db.Deleteable<User>(new User
            {
                Id = UserId
            }).ExecuteCommand();
            return line;
        }

        public List<User> GetUsers(int Id)
        {
            List<User> users;
            if (Id is not 0)
            {
                users = db.Queryable<User>().Where(it => it.Id == Id).ToList();
            }
            else
            {
                users = db.Queryable<User>().ToList();
            }
            return users;
        }

        public int Update(User user)
        {
            var res = db.Updateable<User>(user).ExecuteCommand();
            return res;
        }
    }
}

4、配置Controller进行路由

using Blog.core.Models;
using Blog.Core.Auth;
using Blog.Core.IServices;
using Blog.Core.Model.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Blog.Core.Services;
namespace Blog.core.Controllers
{

    [Route("[controller]/[action]")]
        [ApiController]
        public class UserController : ControllerBase
        {

            private readonly IUserService _userService;
            public UserController( IUserService userService)
                {
                    _userService = userService;
                }

                /// <summary>
                /// 增加
                /// </summary>
                /// <param name="user"></param>
                /// <returns></returns>
                [HttpPost]
                public int AddUser(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]
                public int DeleteUser(int id)
                {
                    return _userService.Delete(id);
                }
                /// <summary>
                /// 更新
                /// </summary>
                /// <param name="user"></param>
                /// <returns></returns>
                [HttpPut]
                public int UpdateUsre(User user)
                {
                    return _userService.Update(user);
                }
                /// <summary>
                /// 获取数据
                /// </summary>
                /// <param name="id"></param>
                /// <returns></returns>
                [HttpGet]
                public List<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、继承接口并实现构造方法

 public class UserService : IUserService
 {
     private  IUserRepository _userService ;

     public UserService(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层使用

 public class UserController : ControllerBase
 {

     private readonly IUserService _userService ;

     public UserController(IUserService userService)
     {
         _userService = userService;
     }
 }

Autofac轻量容器的使用

1、安装Nuget包Autofac.Extensions.DependencyInjectionAutofac.Extras.DynamicProxy

2、使用程序集注册,通过Model注册(这里只列这一种Auto官方文档Assembly Scanning — Autofac 7.0.0 documentation)

**创建Model类 **

using Autofac;
using Blog.Core.IServices;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyModel;
using System.Reflection;
using System.Runtime.Loader;

namespace Blog.Core.Configuration.AutoModule
{
    public class ServiceModel: Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            // 自动对集成 IDependency 接口的类进行注册
            Type baseType = typeof(IUserService);
            var compilationLibrary = DependencyContext.Default.CompileLibraries.Where(x => !x.Serviceable && x.Type == "project").ToList();

            List<Assembly> assemblyList = new List<Assembly>();
            foreach (var _compilation in compilationLibrary)
            {
                try
                {
                    assemblyList.Add(AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(_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(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(i => i.RegisterModule<ServiceModel>());
builder.Services.AddControllers().AddControllersAsServices();

在Controller中使用

public class UserController : ControllerBase
{

    private readonly IUserService _userService ;

    public UserController(IUserService userService)
    {
        _userService = userService;
    }
}

使用Autofac完成AOP日志

1、编写AOP类

using Castle.DynamicProxy;
using Newtonsoft.Json;
using StackExchange.Profiling;
using System.Reflection;

namespace Blog.Core.AOP
{
    /// <summary>
    /// 拦截器BlogLogAOP 继承IInterceptor接口
    /// </summary>
    public class BlogLogAOP : IInterceptor
    { 

        /// <summary>
        /// 实例化IInterceptor唯一方法
        /// </summary>
        /// <param name="invocation">包含被拦截方法的信息</param>
        public void Intercept(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 value
                    if (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
        }

        private void LogEx(Exception ex, ref string dataIntercept)
        {
            if (ex != null)
            {
                //执行的 service 中,收录异常
                MiniProfiler.Current.CustomTiming("Errors:", ex.Message);
                //执行的 service 中,捕获异常
                dataIntercept += ($"方法执行中出现异常:{ex.Message + ex.InnerException}\r\n");
            }
        }

        public static bool IsAsyncMethod(MethodInfo method)
        {
            return (
                method.ReturnType == typeof(Task) ||
                (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
                );
        }

    }

    internal static class InternalAsyncHelper
    {
        public static async Task AwaitTaskWithPostActionAndFinally(Task actualReturnValue, Action<Exception> finalAction)
        {
            Exception exception = null;

            try
            {
                await actualReturnValue;
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            finally
            {
                finalAction(exception);
            }
        }

        public static async Task<T> AwaitTaskWithPostActionAndFinallyAndGetResult<T>(Task<T> actualReturnValue, Func<Task> postAction, Action<Exception> finalAction)
        {
            Exception exception = null;

            try
            {
                var result = await actualReturnValue;
                await postAction();
                return result;
            }
            catch (Exception ex)
            {
                exception = ex;
                throw;
            }
            finally
            {
                finalAction(exception);
            }
        }

        public static object CallAwaitTaskWithPostActionAndFinallyAndGetResult(Type taskReturnType, object actualReturnValue, Action<Exception> finalAction)
        {
            return typeof(InternalAsyncHelper)
                .GetMethod("AwaitTaskWithPostActionAndFinallyAndGetResult", BindingFlags.Public | BindingFlags.Static)
                .MakeGenericMethod(taskReturnType)
                .Invoke(null, [actualReturnValue, finalAction]);
        }
    }
}

2、进行服务注册

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(build =>
{
    // AOP 
    var cacheType = new List<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();

   
});

Webapi的操作返回值和方法参数

返回值ActionResult

ASP.NET Core Web API中的操作方法的返回值如果是普通数据类型,那么返回值就会默认被序列化为JSON格式的响应报文体返回。

1  [HttpGet("{id}")] 
2  public ActionResult<Person> GetPerson(int id) 
3  { 
4     if (id <= 0) 
5     return person;
10    else 
11       return NotFound(new ErrorInfo(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}")] 
2  public ActionResult<Student[]> GetAll(string schoolName, 
3                       [FromRoute(Name ="classNo")]string classNum)

QueryString

对于通过QueryString传递的参数,我们使用[FromQuery]来获取值。如果操作方法的参数的名字和我们要获取的QueryString的名字一致,我们只要为参数添加[FromQuery]即可;如果操作方法的参数的名字和要获取的QueryString的名字不一致,我们就要为设定【FromQuery】的Name属性指定和QueryString中一样的名字。

1  public ActionResult<Student[]> GetAll([FromQuery]string pageNum, 
2                             [FromQuery(Name = "pSize")]int pageSize)

URL和QueryString混用

1  [HttpGet("school/{schoolName}/class/{classNo}")] 
2  public ActionResult<Student[]> GetAll(string schoolName, 
3          [FromRoute(Name ="classNo")]string classNum, 
4           [FromQuery]string pageNum,[FromQuery(Name = "pSize")]int pageSize)

请求报文体

参数为实体类,在请求报文体(Body)里发送相应的Json数据就可以直接接收

1  [HttpPost] 
2  public ActionResult AddNew(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) => {
    return Promise.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) {
      case 404:
        console.error("资源不存在");
        break;
      case 401:
        console.error("没有权限");
        break;
      case 500:
      case 501:
      case 502:
        console.error("没有权限");
        break;
      case 400:
        console.error(error.response.data.msg + "参数错误");
        break;
      default:
        console.log("无法识别");
        break;
    }
    return Promise.reject(error);
  }
);

interface ActionResult<T> {
  data: T;
  msg: string;
  error: any;
  code: number;
}
//get请求
export const get = <T>(
  url: string,
  params?: Object
): Promise<ActionResult<T>> => {
  return axiosInstance.get(url, { params });
};
//post请求
export const post = <T>(
  url: string,
  data?: Object
): Promise<ActionResult<T>> => {
  return axiosInstance.post(url, data);
};
//put请求
export const put = <T>(
  url: string,
  data?: Object
): Promise<ActionResult<T>> => {
  return axiosInstance.put(url, data);
};
//delete请求
export const 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";
export const loginApi = (data: user) => {
  return post<any>("/api/Login/login", data);
};
export const getUserInfo = (ID: string) => {
  return get<any>("/api/Index/UserInfo", { ID });
};

在页面中调用api

import { loginApi } from "@/common/api";
const emailLoginApi = async () => {
  phoneLoding.value = true;
  try {
    const res = await loginApi({
      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";
export const 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);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1631653.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

将针孔模型相机 应用到3DGS

Motivation 3DGS 的 投影采用的是 CG系的投影矩阵 P P P, 默认相机的 principal point (相机光心) 位于图像的中点处。但是 实际应用的 绝大多数的 相机 并不满足这样一个设定&#xff0c; 因此我们 需要根据 f , c x , c y {f,c_x, c_y} f,cx​,cy​ 这几个参数重新构建3D …

Android权限问题

问题&#xff1a;mate60pro弹出了一个读取已安装应用列表的权限弹框&#xff0c;需确认相关场景 分析&#xff1a; 1.AndroidManifest.xml中声明了权限标签 <uses-permission android:name"android.permission.QUERY_ALL_PACKAGES" /> 它赋予应用查询设备上…

结构方程模型(SEM)时间重复测量数据分析

张老师&#xff08;研究员&#xff09;&#xff0c;长期从事R语言结构方程模型、群落生态学、保护生物学、景观生态学和生态模型方面的研究和教学工作&#xff0c;已发表了多篇论文&#xff0c;拥有丰富的科研及实践经验。 很多研究需要进行多个时间点&#xff08;如天/月/年&…

java实现模板填充word,word转pdf,pdf转图片

Java实现Word转PDF及PDF转图片 在日常开发中&#xff0c;我们经常需要将文件操作&#xff0c;比如&#xff1a; 根据模板填充wordword文档中插入图片Word文档转换为PDF格式将PDF文件转换为图片。 这些转换可以帮助我们在不同的场景下展示或处理文档内容。下面&#xff0c;我将…

OpenHarmony实战开发-动画效果、如何实现阴影效果

阴影接口shadow可以为当前组件添加阴影效果&#xff0c;该接口支持两种类型参数&#xff0c;开发者可配置ShadowOptions自定义阴影效果。ShadowOptions模式下&#xff0c;当radius 0 或者 color 的透明度为0时&#xff0c;无阴影效果。 Entry Component struct ShadowOptionD…

MybatisPlus 页数page过大数据溢出问题

最近在修改公司代码时前端报了个奇怪的bug&#xff0c;即某个分页接口明明数据量只有42条&#xff0c;但是使用page 500 size 10 的配置时仍然可以查出数据 如下图所示 可见 total 属性只有 42条数据&#xff0c;页数都到500了但是很夸张的还是查出来10条数据 查询后端…

从阿里云崩溃看IT系统非功能能力验证

昨天下午6点左右学员群里有人说阿里云又出问题了&#xff0c;并且还挺长时间没有恢复了。 我也登录了一下&#xff0c;结果登录直接不停地302。如下所示&#xff1a; 做为阿里云重要的基础设施&#xff0c;这一故障影响了。如官方通告的处理时间线&#xff1a; 17:44起&#…

【笔试训练】day12

1.牛牛冲砖五 思路&#xff1a; 看懂样例即可。 代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std;int main() {int t;cin >> t;string str;while (t--) {int n, k;cin >> n >> k >> str;int an…

鸿蒙OpenHarmony【小型系统 烧录】(基于Hi3516开发板)

烧录 针对Hi3516DV300开发板&#xff0c;除了DevEco Device Tool&#xff08;操作方法请参考烧录)&#xff09;外&#xff0c;还可以使用HiTool进行烧录。 前提条件 开发板相关源码已编译完成&#xff0c;已形成烧录文件。客户端&#xff08;操作平台&#xff0c;例如Window…

微软开源了 MS-DOS 4.00

DOS的历史源远流长&#xff0c;很多现在的年轻人不知道DOS了。其实早期的windows可以看做是基于DOS的窗口界面的模拟器&#xff0c;系统的本质其实是DOS。后来DOS的漏洞还是太多了&#xff0c;微软重新写了windows的底层内核。DOS只是一个辅助终端的形式予以保留了。 微软是在…

FTP 文件传输协议

FTP 文件传输协议 作用 用来传输文件的 FTP协议采用的是TCP作为传输协议&#xff0c; 21号端口用来传输FTP控制命令的&#xff0c; 20号端口用来传输文件数据的 FTP传输模式&#xff1a; 主动模式&#xff1a; FTP服务端接收下载控制命令后&#xff0c;会主动从tcp/20号端口…

pyaibote--安卓自动化环境配置与基础的使用方法

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 pyaibote介绍 pyaibote是一个全新&#xff0c;强大的办公自动化库。 支持找图&#xff0c;识别像素等操作。 比appium快十倍。 文章介绍 有大佬给我提到这个库后&#xff0c;我来查看。然后发现这个库太新了&am…

自然语言处理 (NLP) 中的迁移学习

--懂王 在大数据高速发展的时代&#xff0c;AI的发展日新月异&#xff0c;充满挑战的迎接未来。 自然语言处理 (NLP) 中的迁移学习: 迁移学习在 NLP 中越来越受欢迎&#xff0c;特别是在数据稀缺的情况下。如何有效地利用预训练的语言模型&#xff0c;并将其迁移到新的任务和领…

windows驱动开发-中断(一)

中断是windows中最难的一部分&#xff0c;这是因为中断本身属于操作系统的一部分&#xff0c;理解了中断和内存&#xff0c;对整个系统也就了解了。 中断部分会先从中断优先级、中断处理、中断服务例程入手&#xff0c;大概讲述一下中断的概念&#xff1b;接着从中断的一般实现…

如何买到“30元以下”的免备案服务器?

对于预算有限的个人和小型企业来说&#xff0c;30 元以下免备案服务器的价格非常亲民。用户可以以极低的成本获得所需的服务器资源&#xff0c;这对创业者、个人开发者、学生和站长来说简直不要太划算&#xff0c;毕竟配置可以升级真不够后面再付费升级也行。 何为“免备案”&…

ROS1快速入门学习笔记 - 07话题消息的定义与使用

目录 一、话题模型 二、自定义话题消息 1. 在功能包下创建msg目录用于存储话题文件 2. 在package.xml文件中添加功能包依赖&#xff1b; 3. 在CMakeLists.txt增加编译选项&#xff1b; 4. 完成编译 5. 配置CMakeLists.txt中的编译规则&#xff08;增加发布者和订阅者&am…

Meta Llama 3 性能提升与推理服务部署

利用 NVIDIA TensorRT-LLM 和 NVIDIA Triton 推理服务器提升 Meta Llama 3 性能 我们很高兴地宣布 NVIDIA TensorRT-LLM 支持 Meta Llama 3 系列模型&#xff0c;从而加速和优化您的 LLM 推理性能。 您可以通过浏览器用户界面立即试用 Llama 3 8B 和 Llama 3 70B&#xff08;该…

卫浴品牌商家做展示预约小程序的作用是什么

卫浴品牌类别多、普通/智能、场景化等&#xff0c;无论企业还是经销商市场门店都比较饱满&#xff0c;虽然市场需求度高&#xff0c;但同样需要商家不断拓宽销售渠道和挖掘客户价值&#xff0c;破圈增长。 线上多平台发展尤为重要&#xff0c;而小程序作为连接点&#xff0c;对…

深度学习模型的优化和调优de了解

深度学习模型的优化和调优&#xff1a;随着深度学习应用的广泛&#xff0c;优化和调优神经网络模型成为了一个重要的问题。这包括选择合适的网络架构、调整超参数、应对过拟合等。 深度学习模型的优化和调优是指在训练神经网络模型时&#xff0c;通过一系列技术和方法来提高模型…

无缝迁移:从阿里云WAF到AWS的成功转变之路

在当今数字化浪潮中&#xff0c;网络安全已经成为企业发展的重要组成部分。阿里云WAF&#xff08;Web 应用防火墙&#xff09;作为一种重要的网络安全解决方案&#xff0c;帮助企业保护其 Web 应用免受各种网络攻击。 然而&#xff0c;随着企业业务的扩展和需求的变化&#xf…