.Net Core 6 WebApi 项目搭建

文章目录

  • 前言
  • 一、创建第一个Core 6 项目
    • 创建项目
    • Program.cs
    • 创建Controller
    • 总结
  • 二、读取appsettings.json
  • 三、修改Program.cs
    • 跨域
    • 修改启动的Url
    • 建立数据库连接(SQLServer)
    • 建立数据库连接(MySQL)
  • 四、启用JWT鉴权
    • 生成Token令牌
    • 安装需要的包
    • 新建TokenModel类
    • 新建JwtHelper.cs
    • 获取Token
    • Swagger中开启JWT服务
    • JWT授权认证
    • API接口授权策略
    • 解析Token
    • 补充说明
  • 五、.NET Core 6中使用Code First
    • 建立实体类
    • 建立上下文
    • 迁移
  • 六、构造数据库逆向工程
  • 七、.Net Core 6 中使用腾讯云COS对象存储服务
  • 八、EF6记录
    • 1.扩展执行原生SQL
  • 九、其他
  • Ⅰ.发布常见问题汇总
  • 参考链接


前言

微软文档
刚开始上手Core 6,写博客记录一下。有不足之处请多指教。


一、创建第一个Core 6 项目

开发工具:Visual Studio 2022
Core版本:.Net Core 6

创建项目

Ⅰ.**创建新项目:**打开开发工具>创建新项目>搜索API>选择C#语言的ASP.NET Core Web API
.Net Core 6 WebApi 项目搭建_第1张图片Ⅱ.**配置新项目:**自定义项目信息以及存储路径
.Net Core 6 WebApi 项目搭建_第2张图片Ⅲ.其他信息:这里框架必须选择.NET 6.0,其他配置默认勾选即可,也可以根据自己的需求进行更改。(如果没有安装6.0,请看下一步)
.Net Core 6 WebApi 项目搭建_第3张图片Ⅳ.更改开发工具安装
①打开开发工具,选择 继续但无需代码.Net Core 6 WebApi 项目搭建_第4张图片

②导航栏>工具>获取工具和功能
.Net Core 6 WebApi 项目搭建_第5张图片
③安装你需要的工具和功能
.Net Core 6 WebApi 项目搭建_第6张图片

Ⅴ.创建完成之后就得到了一个最基础的Core6项目框架代码
.Net Core 6 WebApi 项目搭建_第7张图片

Program.cs

Program.cs就是该项目程序的配置,在Core6中Program.cs 集成了 Startup.cs 的配置,详细的查看官网文档或者百度都行。因为我也是小白一枚请见谅。
官网文档
迁移到 ASP.NET Core 6.0 中新的最小托管模型的代码示例

创建Controller

可以先将系统默认创建的WeatherForecastController.cs和WeatherForecast.cs进行删除,然后在controller文件夹新建一个控制器,命名:UserController.cs

.Net Core 6 WebApi 项目搭建_第8张图片.Net Core 6 WebApi 项目搭建_第9张图片.Net Core 6 WebApi 项目搭建_第10张图片

在UserController中增加一个Hello的get方式的接口方法,返回"你好世界",通过请求api/user/hello来获取该接口的结果

点击运行后,开发工具会自动编译后启动。
会生成一个exe文件并自动运行,运行成功后会打开浏览器进行查看

.Net Core 6 WebApi 项目搭建_第11张图片
.Net Core 6 WebApi 项目搭建_第12张图片

由于在创建项目时我们已经勾选了Swagger服务,所以启动后的项目会使用Swagger UI 进行展示。

点击User接口>Try it out 就可以得到该接口的返回值及一些相关的属性
.Net Core 6 WebApi 项目搭建_第13张图片

总结

其实项目的创建以及控制器的创建和 core3是一致,只是.Net Core 6 给我的感觉就是比以往的版本更精简。可以将Swagger在创建项目时直接生成,而不需要手动的去配置。

二、读取appsettings.json

参考文章一
参考文章二

使用Nuget安装
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.Json
Microsoft.Extensions.Configuration.Binder
根据自己的开发环境选择合适的版本进行安装

最近发布后遇到了点读取的问题,已经解决更新到代码里面了,写在注释上,看一眼就行了。

Ⅰ、新建Helper文件夹用来存放帮助类,并添加一个AppSettings.cs
这里

	/// 
    /// appsettings.json操作类
    /// 
    public class Appsettings
    {
        static IConfiguration? Configuration { get; set; }
        static string? ContentPath { get; set; }

        public Appsettings(string contentPath)
        {
            string Path = "appsettings.json";

            //如果你把配置文件 是 根据环境变量来分开了,可以这样写
            //1.获取当前环境 不能直接使用 Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")进行获取,开发环境不会报错,发布以后会报错,需要发布后再配置,所以不建议使用这种方法获取
            //var env = Environment.GetEnvironmentVariables();
            //2.从env中获取环境
            //var envName = env["ASPNETCORE_ENVIRONMENT"];
            //string Path = $"appsettings.{envName}.json";

            Configuration = new ConfigurationBuilder()
               .SetBasePath(contentPath)
               .Add(new JsonConfigurationSource { Path = Path, Optional = false, ReloadOnChange = true })//这样的话,可以直接读目录里的json文件,而不是 bin 文件夹下的,所以不用修改复制属性
               .Build();
        }

        public Appsettings(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        /// 
        /// 封装要操作的字符
        /// 
        /// 节点配置
        /// 
        public static string App(params string[] sections)
        {
            try
            {

                if (sections.Any())
                {
#pragma warning disable CS8602 // 解引用可能出现空引用。
                    return Configuration[string.Join(":", sections)];
#pragma warning restore CS8602 // 解引用可能出现空引用。
                }
            }
            catch (Exception)
            {

            }

            return "";
        }

        /// 
        /// 递归获取配置信息数组
        /// 
        /// 
        /// 
        /// 
        public static List<T> App<T>(params string[] sections)
        {
            List<T> list = new();
            Configuration.Bind(string.Join(":", sections), list);
            return list;
        }
    }

Ⅱ、修改Program.cs
①在 var builder = WebApplication.CreateBuilder(args); 前增加

//获取当前环境:提供两种方法
//方法一
//① var env = Environment.GetEnvironmentVariables();
//从env中获取环境
//② var envName = env["ASPNETCORE_ENVIRONMENT"];
//方法二
//var env2 = WebApplication.CreateBuilder().Environment.EnvironmentName;
//读取配置文件
//IConfiguration configuration = new ConfigurationBuilder().AddJsonFile($"appsettings.{env2}.json").Build();

//读取配置文件
IConfiguration configuration = new ConfigurationBuilder()
                            .AddJsonFile("appsettings.json")
                            .Build();

②在 var builder = WebApplication.CreateBuilder(args); 后增加

builder.Services.AddSingleton(new Appsettings(configuration));

③读取
appsettings.json 代码

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "AppSettings": {
    //数据库连接字符串
    "ConnectionString": "Server=127.0.0.1;User Id=用户id;Password=密码;Database=数据库名称;"
  }
}

读取

var text = Appsettings.App(new string[] { "AppSettings", "ConnectionString" });

.Net Core 6 WebApi 项目搭建_第14张图片


三、修改Program.cs

跨域

官方文档
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
在 ASP.NET Core 中启用跨源请求 (CORS)
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
官网文档给出了不同的跨域请求解决方案,可以根据实际需求进行选择自己喜欢的方案。
我这里就配置最简单的 具有默认策略和中间件的 CORS

var builder = WebApplication.CreateBuilder(args); 后面添加如下代码;在这里我并没有针对到具体的地址,而是使用 AllowAnyOrigin() 确保策略允许任何源
这里 policy后面的方法可以查看CorsPolicyBuilder 类

方法 属性
AllowAnyHeader() 确保策略允许任何标头
AllowAnyMethod() 确保策略允许任何方法
AllowAnyOrigin() 确保策略允许任何源
AllowCredentials() 设置策略以允许凭据
builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(
        policy =>
        {
            policy.AllowAnyOrigin().AllowAnyHeader();
        });
});

注册中间件
中间件顺序 ASP.NET Core 中间件
注册中间件时,顺序最好按照官网给出的依次进行注册,不然会无法生效

UseCors 添加 CORS 中间件。 对 UseCors 的调用必须放在 UseRouting 之后,但在 UseAuthorization 之前。

app.UseRouting();
//注册中间件
app.UseCors();

app.UseAuthorization();

完整代码

IConfiguration configuration = new ConfigurationBuilder()
                            .AddJsonFile("appsettings.json")
                            .Build();
var builder = WebApplication.CreateBuilder(args);
//读取配置文件
builder.Services.AddSingleton(new Appsettings(configuration));
var text = Appsettings.App(new string[] { "AppSettings", "ConnectionString" });
Console.WriteLine($"ConnectionString:{text}");
// Add services to the container.
//跨域
builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
    {
        policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
    });
});

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
//app.UseHttpsRedirection();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();

修改启动的Url

虽然修改启动的Url的并不需要动Program.cs文件中的配置,为了方便查看我还是放到这里来进行叙述。

其实这个也没啥好说的,只是Core6版的配置和之前的有那么一丢丢不一样,俗话说好记性不如烂笔头。所以我还是在这记录下来啦。
其实在查看官网文档Kestrel 终结点配置 之后你就会觉得So easy

Kestrel 特定的终结点配置将覆盖所有跨服务器终结点配置
找到项目中的 appsettings.json 文件,在该Josn文件中加入以下代码

"Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://localhost:7521"
      },
      "Https": {
        "Url": "https://localhost:7526"
      }
    }
  },
这里的IP地址根据core3的配置方法,我猜测可以将IP地址换为*号,只是开发工具会发出警告,因为部署到服务器上我想让他自己匹配服务器的IP,而不是我在这进行编辑。因为我也还没部署到服务器上,先大胆假设一下吧,等到后面我部署到服务器上在回来完善这一部分。

然后在启动项目后,项目的请求地址就会发生改变
.Net Core 6 WebApi 项目搭建_第15张图片
在这里还有一个问题哈,就是在创建的时候如果默认勾选了HTTS服务,那么在项目创建完成之后会在Program.cs 的中间件中默认注册
app.UseHttpsRedirection();
在执行了上面修改启动URL的时候,如果此时加入了一个HTTP的URL,你会发现去请求这个HTTP下的接口服务时,它会告诉你请求不了,然而HTTS下的接口服务却正常。

原因:HTTPS 重定向中间件 (UseHttpsRedirection) 将 HTTP 请求重定向到 HTTPS。

这时候只需要将app.UseHttpsRedirection();注释或者删除即可
.Net Core 6 WebApi 项目搭建_第16张图片

建立数据库连接(SQLServer)

1.找到Program.cs文件 2.插入以下代码,注意:安装包 **Microsoft.EntityFrameworkCore.SqlServer**
//Connection通过读取配置文件得到,其实就是数据库连接字符串,如何读取前面讲过
builder.Services.AddDbContext<EFDbContext>(options =>
  options.UseSqlServer(Connection));

建立数据库连接(MySQL)

appsettings.json中加入Mysql的连接字符
.Net Core 6 WebApi 项目搭建_第17张图片

1.找到Program.cs文件 2.插入以下代码,注意:安装包 **Pomelo.EntityFrameworkCore.MySql**
var MySqlConnection = Appsettings.App(new string[] { "AppSettings", "MyConnectionString" });
//Connection通过读取配置文件得到,其实就是数据库连接字符串,如何读取前面讲过
builder.Services.AddDbContext<CodeFirstContext>(options =>
  options.UseMySql(MySqlConnection, new MySqlServerVersion(new Version(8, 0, 2))));

其中new Version(8, 0, 2) 为Mysql的版本。如何查看mysql的版本,如下(windows环境下)
1.以管理员身份打开cmd,输入以下命令

mysql -uroot -p

2.输入Mysql登录密码
3. 随后输入**select version();**即可得到MySQL的版本
mysql的安装以及配置去网上搜即可


四、启用JWT鉴权

什么是 JSON Web 令牌?
JSON Web Token (JWT) 是一种开放标准 (RFC 7519),它定义了一种紧凑且独立的方式,用于将信息作为 JSON 对象在各方之间安全地传输。此信息可以进行验证和信任,因为它是经过数字签名的。JWT 可以使用密钥(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。
JWT官网
JWT详解

网上对JWT的讲解有很多,我就不在这过多叙述啦。

生成Token令牌

在项目中找到appsettings.json,在appsettings.json中配置jwt参数的值 【注意】 SecretKey必须大于16个,是大于,不是大于等于。

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "AppSettings": {
    //数据库连接字符串
    "ConnectionString": "Server=127.0.0.1;User Id=用户id;Password=密码;Database=数据库名称;",
    //JWT参数
    "JwtSetting": {
      "Issuer": "jwtIssuer", //颁发者
      "Audience": "jwtAudience", //可以给哪些客户端使用
      "SecretKey": "chuangqianmingyueguang" //加密的Key
    }
  }
}

安装需要的包

  1. IdentityModel
  2. Microsoft.AspNetCore.Authentication.JwtBearer
  3. Microsoft.AspNetCore.Authorization

.Net Core 6 WebApi 项目搭建_第18张图片

新建TokenModel类

该类是JWT的返回实体类,创建位置根据你的项目情况而定,注意刚刚安装的包的位置!!!

/// 
    /// 令牌
    /// 
    public class TokenModel
    {
        /// 
        /// Id
        /// 
        public string? Uid { get; set; }
        /// 
        /// 角色
        /// 
        public string? Role { get; set; }

    }

新建JwtHelper.cs

注意建立的位置与刚刚安装的包的位置!!!
以下代码来自博客园

 public class JwtHelper
    {
        /// 
        /// 颁发JWT字符串
        /// 
        /// 
        /// 
        public static string IssueJwt(TokenModel tokenModel)
        {
            //获取Appsetting配置
            string iss = Appsettings.App(new string[] { "AppSettings", "JwtSetting", "Issuer" });
            string aud = Appsettings.App(new string[] { "AppSettings", "JwtSetting", "Audience" });
            string secret = Appsettings.App(new string[] { "AppSettings", "JwtSetting", "SecretKey" });

            //var claims = new Claim[] //old
            var claims = new List<Claim>
                {
                 /*
                 * 特别重要:
                   1、这里将用户的部分信息,比如 uid 存到了Claim 中,如果你想知道如何在其他地方将这个 uid从 Token 中取出来,请看下边的SerializeJwt() 方法,或者在整个解决方案,搜索这个方法,看哪里使用了!
                   2、你也可以研究下 HttpContext.User.Claims ,具体的你可以看看 Policys/PermissionHandler.cs 类中是如何使用的。
                 */



                new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ToString()),
                new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
                new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                //这个就是过期时间,目前是过期1000秒,可自定义,注意JWT有自己的缓冲过期时间
                new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds()}"),
                new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(1000).ToString()),
                new Claim(JwtRegisteredClaimNames.Iss,iss),
                new Claim(JwtRegisteredClaimNames.Aud,aud),


               };

            // 可以将一个用户的多个角色全部赋予;
            claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));



            //秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常)
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var jwt = new JwtSecurityToken(
                issuer: iss,
                claims: claims,
                signingCredentials: creds);

            var jwtHandler = new JwtSecurityTokenHandler();
            var encodedJwt = jwtHandler.WriteToken(jwt);

            return encodedJwt;
        }

        /// 
        /// 解析
        /// 
        /// 
        /// 
        public static TokenModel SerializeJwt(string jwtStr)
        {
            var jwtHandler = new JwtSecurityTokenHandler();
            JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
            object role;
            try
            {
                jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
            var tm = new TokenModel
            {
                Uid = jwtToken.Id.ToString(),
                Role = role != null ? role.ToString() : "",
            };
            return tm;
        }
    }

获取Token

UserController新建Login接口,用来获取token
注意一个控制器多个接口时[HttpGet(“Login”)]需要在方法后面加入接口名称

[HttpGet("Login")]
public IActionResult Login(string role)
 {
   string jwtStr = string.Empty;
    bool suc = false;
	if (role != null)
		{
                // 将用户id和角色名,作为单独的自定义变量封装进 token 字符串中。
                TokenModel tokenModel = new TokenModel { Uid = "abcde", Role = role };
                jwtStr = JwtHelper.IssueJwt(tokenModel);//登录,获取到一定规则的 Token 令牌
                suc = true;
            }
            else
            {
                jwtStr = "login fail!!!";
            }

            return Ok(new
            {
                success = suc,
                token = jwtStr
            });
        }

运行项目,请求Login接口输入参数即可获得Token值
.Net Core 6 WebApi 项目搭建_第19张图片

Swagger中开启JWT服务

要测试 JWT 授权认证,就必定要输入 Token令牌,那怎么输入呢,平时的话,我们可以使用 Postman 来控制输入,就是在请求的时候,在 Header 中,添加Authorization属性。但是现在使用了 Swagger 作为接口文档,那怎么输入呢,其实 Swagger 已经帮我们实现了这个录入 Token令牌的功能。

在Program.cs文件中找到builder.Services.AddSwaggerGen();方法,将该方法改为以下所示
注意需要安装包 Swashbuckle.AspNetCore.Filters

//为swagger配置JWT
builder.Services.AddSwaggerGen(options =>
{
    // 在header中添加token,传递到后台
    //安装包 Swashbuckle.AspNetCore.Filters
    options.OperationFilter<SecurityRequirementsOperationFilter>();
    #region Token绑定到ConfigureServices
    options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
    {
        Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"",
        Name = "Authorization",//jwt默认的参数名称
        In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
        Type = SecuritySchemeType.ApiKey
    });
    #endregion
});

运行项目后在接口主页面右上方就能看到Token的入口。
.Net Core 6 WebApi 项目搭建_第20张图片.Net Core 6 WebApi 项目搭建_第21张图片

JWT授权认证

新建AuthorizationSetup.cs
代码来自博客园

/// 
    /// 身份验证服务
    /// 
    public static class AuthorizationSetup
    {
        /// 
        /// 注册身份验证服务
        /// 
        /// 
        /// 
        public static void AddAuthorizationSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            //读取配置文件
            var symmetricKeyAsBase64 = Appsettings.App(new string[] { "AppSettings", "JwtSetting", "SecretKey" });
            var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey = new SymmetricSecurityKey(keyByteArray);
            var Issuer = Appsettings.App(new string[] { "AppSettings", "JwtSetting", "Issuer" });
            var Audience = Appsettings.App(new string[] { "AppSettings", "JwtSetting", "Audience" });
            // 令牌验证参数
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = signingKey,
                ValidateIssuer = true,
                ValidIssuer = Issuer,//发行人
                ValidateAudience = true,
                ValidAudience = Audience,//订阅人
                ValidateLifetime = true,
                ClockSkew = TimeSpan.FromSeconds(30),
                RequireExpirationTime = true,
            };

            //2.1【认证】、core自带官方JWT认证
            // 开启Bearer认证
            services.AddAuthentication("Bearer")
             // 添加JwtBearer服务
             .AddJwtBearer(o =>
             {
                 o.TokenValidationParameters = tokenValidationParameters;
                 o.Events = new JwtBearerEvents
                 {
                     OnAuthenticationFailed = context =>
                     {
                         // 如果过期,则把<是否过期>添加到,返回头信息中
                         if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                         {
                             context.Response.Headers.Add("Token-Expired", "true");
                         }
                         return Task.CompletedTask;
                     }
                 };
             });
        }
    }

在Program.cs中注册验证服务
官网文档ASP.NET Core 身份验证概述

//注册身份验证服务
builder.Services.AddAuthorizationSetup();

.Net Core 6 WebApi 项目搭建_第22张图片注册中间件
ASP.NET Core 中间件顺序

app.UseRouting();
//身份验证
app.UseAuthentication();

app.UseAuthorization();

.Net Core 6 WebApi 项目搭建_第23张图片

API接口授权策略

对接口进行授权的方式有两种:

直接对需要进行授权验证的接口 [Authorize] 加上这个配置信息
注意需要引入这个包Microsoft.AspNetCore.Authorization

[HttpGet("Hello")]
[Authorize]
public string Hello()
{
   return "你好世界";
}

第二种则是对整个控制器加上 [Authorize] 标识那么该控制器对于的所有接口都需要进行授权才能进行访问。
使用 **[AllowAnonymous]**可以取消授权验证

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using webapi.core.model;
using Webapi.Core.Common.Helper;

namespace WebApplication1.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    [Authorize]
    public class UserController : ControllerBase
    {
        
        [HttpGet("Hello")]
        public string Hello()
        {
            return "你好世界";
        }
        
        [HttpGet("Login")]
        [AllowAnonymous]
        public IActionResult Login(string role)
        {
            string jwtStr = string.Empty;
            bool suc = false;

            if (role != null)
            {
                // 将用户id和角色名,作为单独的自定义变量封装进 token 字符串中。
                TokenModel tokenModel = new TokenModel { Uid = "abcde", Role = role };
                jwtStr = JwtHelper.IssueJwt(tokenModel);//登录,获取到一定规则的 Token 令牌
                suc = true;
            }
            else
            {
                jwtStr = "login fail!!!";
            }

            return Ok(new
            {
                success = suc,
                token = jwtStr
            });
        }
    }
}

解析Token

主要是调用JwtHelper下的SerializeJwt方法

/// 
/// 解析Token
/// 
/// 
[HttpGet]
[Authorize]
public IActionResult ParseToken()
{
    //需要截取Bearer 
    var tokenHeader = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
    var user = JwtHelper.SerializeJwt(tokenHeader);
    return Ok(user);
}

在这里我在记录一下如何获取payload的信息,因为有时候需要获取里面的信息进行返回

#region 获取payload信息
var handler = new JwtSecurityTokenHandler();
var payload = handler.ReadJwtToken(jwtStr).Payload;
var claims = payload.Claims;
var expireTime = claims.First(claim => claim.Type == "exp").Value;
#endregion

基于角色进行接口的授权,请查看文章Net core 3 JWT授权方法都是一样的所以我就不过多阐述,有问题可以直接私我

补充说明

问题:启动服务后,已经对接口注释,但是swagger页面不显示注释。
解决方案:
1.在Program.cs文件中找到方法体

builder.Services.AddSwaggerGen(option =>{})

2.在原有的基础上继续增加配置。具体我不赘述,网上有更详细的说明,直接贴出我的配置代码。

builder.Services.AddSwaggerGen(option =>
{
    option.SwaggerDoc("v1", new OpenApiInfo
    {
        Title = "后台接口",
    });
    var file = Path.Combine(AppContext.BaseDirectory, "LabApi.xml");  // xml⽂档绝对路径
    var path = Path.Combine(AppContext.BaseDirectory, file); // xml⽂档绝对路径
    option.IncludeXmlComments(path, true); // true : 显⽰控制器层注释
    option.OrderActionsBy(o => o.RelativePath); // 对action的名称进⾏排序,如果有多个,就可以看见效果了。

    // 在header中添加token,传递到后台
    //安装包 Swashbuckle.AspNetCore.Filters
    option.OperationFilter<SecurityRequirementsOperationFilter>();
    #region Token绑定到ConfigureServices
    option.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
    {
        Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"",
        Name = "Authorization",//jwt默认的参数名称
        In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
        Type = SecuritySchemeType.ApiKey
    });
    #endregion
});

3.在项目上右键→项目属性→生成→输出,把文档文件一栏勾选上
.Net Core 6 WebApi 项目搭建_第24张图片


五、.NET Core 6中使用Code First

推荐文章
EF 6 Code-First系列文章

EF Core有两种数据库设计模式
DBfirst (数据库优先):一般设计是先添加数据库表信息,然后将数据库的信息更新到项目实体中。这种做法就是我们的DBfirst模式。
Codefirst (代码优先):先创建表实体,添加字段限制,建立DbContxt,完事后进行代码迁移
代码迁移:Add-Migration
数据库更新:update-database

官方文档Entity Framework Core
使用Code First 其实就是分为以下三步:建立实体类、建立上下文池、执行迁移。
注意:需要引入以下包,因为我主要用的是SQLServer所以这里引入了SQL的包,反正记住缺少啥包就安装啥包就行
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Relational
Microsoft.EntityFrameworkCore.SqlServer

建立实体类

建立文件夹Model,然后新建一个Student.cs类

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

namespace webapi.core.model.SQLModel
{
    public class Student
    {
        /// 
        /// 学生ID
        /// 
        public int StudentID { get; set; }

        /// 
        /// 学生姓名
        /// 
        public string StudentName { get; set; }

        /// 
        /// 出生日期
        /// 
        public DateTime? DateOfBirth { get; set; }

        /// 
        /// 图片
        /// 
        public byte[] Photo { get; set; }

        /// 
        /// 身高
        /// 
        public decimal Height { get; set; }
    }
}

.Net Core 6 WebApi 项目搭建_第25张图片

建立上下文

新建一个类,EFDbContext.cs (命名由你)
但是必须继承DbContext

public class EFDbContext:DbContext
    {
        public EFDbContext(DbContextOptions options) : base(options)
        {

        }
        public DbSet<Student> Students { get; set; }
    }

这里注意了这行代码,DbSet这里面的Student是你刚刚创建的类名,而Students是数据库的表名。

public DbSet<Student> Students { get; set; }

当需要生成多个表,有多个类时,只需要在后面加入就行

 public class EFDbContext:DbContext
    {
        public EFDbContext(DbContextOptions options) : base(options)
        {

        }
        public DbSet<Student> Students { get; set; }
        public DbSet<Grade> Grades { get; set; }
    }

.Net Core 6 WebApi 项目搭建_第26张图片

迁移

详细的阅读官方文档迁移概述

-建立数据库连接
既然我们需要通过代码生成数据库表,那么我们是不是应该建立对应数据库的连接呢?

1.找到Program.cs文件
2.插入以下代码,注意:安装包 Microsoft.EntityFrameworkCore.SqlServer

//Connection通过读取配置文件得到,其实就是数据库连接字符串,如何读取前面讲过
builder.Services.AddDbContext<EFDbContext>(options =>
  options.UseSqlServer(Connection));

.Net Core 6 WebApi 项目搭建_第27张图片

- 安装工具 Microsoft.EntityFrameworkCore.Tools 官方文档
我这里采用程序包管理器控制台工具进行迁移,所以安装使用程序包管理器控制台工具
在“包管理器控制台”中运行以下命令,安装包管理器控制台工具,当然也可以项目右键Nuget包管理工具进行可视化管理(安装、更新、删除)

Install-Package Microsoft.EntityFrameworkCore.Tools
  1. 创建迁移
    指示 EF Core 创建名为 InitialCreate 的迁移,在包管理器控制台输入以下命令行
Add-Migration InitialCreate

EF Core 将在项目中创建一个名为“Migrations”的目录,并生成一些文件。
2. 创建数据库和架构
在包管理器控制台输入以下命令行

Update-Database

此操作会将模型映射到数据库中建立对应的表以及关系。后期更新表也是使用该命令。执行到这以后你打开数据库就会发现多了一张表。更多细节就去看官网文档吧,我只是记录大概怎么使用。
.Net Core 6 WebApi 项目搭建_第28张图片

六、构造数据库逆向工程

在前面第五点讲了通过代码生成数据库的表,但是在很多情况下都是已经设计好了数据库,然后在开发时直接连接上数据库生成数据库实体。
首先生成数据库的逆向工程同样的可以通过控制台输入指令来完成这里我直接推荐一篇文章 我就不重复去写了.net core 连接数据库(通过数据库生成Modell)
第二种方法的话是一种可视化的构建方法,更适合向我这种记不住那些命令行的人。
1、安装EF Core Power Tools:打开Vs开发工具→扩展→管理扩展
.Net Core 6 WebApi 项目搭建_第29张图片2、(切记执行这步之前确保自己的代码不存在编写或者编译错误!)安装完成后在你需要创建数据库实体的项目文件夹上面单击右键,找到EF Core 工具(必须安装扩展之和才会有)→反向工程
.Net Core 6 WebApi 项目搭建_第30张图片
3、点击之和如果是第一次连接需要进行数据库的连接配置,也很简单就是直接把你需要创建实体的数据地址以及登录账号密码输入即可
.Net Core 6 WebApi 项目搭建_第31张图片//.切记根据自己的版本进行选择((ef core的版本))如上图!!
//.还有一点需要注意!!!如果是SQL Server的数据库你直接点击添加按钮即可弹出连接SQL Server的弹窗,如下图
.Net Core 6 WebApi 项目搭建_第32张图片
接上面,但是!!!!!!!如果不是SQL Server的数据库你需要点击添加按钮旁边的小箭头进行其他数据库的配置,配置方法很简单,不明白直接私信我或者评论我看见就回复。
.Net Core 6 WebApi 项目搭建_第33张图片
3、以上的数据库连接配置完成后会跳到如下所示的界面,到这一步你就可以选择你需要生成实体的表或者视图了
.Net Core 6 WebApi 项目搭建_第34张图片4、点击确认之后会来到如下的界面,在这里你就可以根据自己的需求进行配置,但是如果是第一次生成实体,我建议把我箭头指向的哪个ef core包给安装上。
.Net Core 6 WebApi 项目搭建_第35张图片

5、到这部其实数据库实体以及实体的上下文已经生成完成,你只需要在Program.cs中配置数据库的连接即可,读取配置文件的方法我在前面有写噢

//读取配置文件
builder.Services.AddSingleton(new Appsettings(configuration));
var Connection = Appsettings.App(new string[] { "AppSettings", "Connection" });

//数据库连接
builder.Services.AddDbContext<这里是你的上下文对象名称>(options =>
    options.UseSqlServer(Connection));

6、在需要使用的地方进行上下文的实例化即可

public class demoController : Controller
    {
        private readonly 你的上下文对象名称_context;

        /// 
        /// 实例化上下文
        /// 
        /// 
        public demoController(你的上下文对象名称 context) => _context = context;
        public JsonResult demo()
        {
        //随便写的
        var result = from a in _context.T_User select a;
        return Json(result)
			}
    }

七、.Net Core 6 中使用腾讯云COS对象存储服务

官网地址
第一步:添加 腾讯云对象存储服务SDK
通过项目右键→属性→管理Nuget程序包,然后搜索 Tencent.QCloud.Cos.Sdk 选择合适的版本进行安装.Net Core 6 WebApi 项目搭建_第36张图片.Net Core 6 WebApi 项目搭建_第37张图片

如果您是使用 .NET CLI,请使用如下命令安装:
dotnet add package Tencent.QCloud.Cos.Sdk

第二步:初始化 COS 服务以及使用,详细的初始化方法查看上面我给出的官网文档,我这里直接贴出我自己的代码。过多的配置方法在官网文档也给出了,我这里将上传配置单独取出作为一个方法类,有问题直接留言,看到第一时间解决。

using COSXML;
using COSXML.Auth;
using COSXML.Model.Object;
using COSXML.Model.Bucket;
using COSXML.CosException;
using COSXML.Model.Service;
using COSXML.Model.Tag;
using COSXML.Transfer;
namespace Lab.Tool
{
    public class COS
    {
        public async Task<string> COSXml(string localFilePath,string fileName)
        {

            //初始化 CosXmlConfig 
            string appid = "**********";//设置腾讯云账户的账户标识 APPID
            string region = "ap-*****"; //设置一个默认的存储桶地域
            CosXmlConfig config = new CosXmlConfig.Builder()
              .IsHttps(true)  //设置默认 HTTPS 请求
              .SetRegion(region)  //设置一个默认的存储桶地域
              .SetDebugLog(true)  //显示日志
              .Build();  //创建 CosXmlConfig 对象
            //提供访问凭证
            string secretId = "*****"; //"云 API 密钥 SecretId";
            string secretKey = "******"; //"云 API 密钥 SecretKey";
            long durationSecond = 600;  //每次请求签名有效时长,单位为秒
            QCloudCredentialProvider cosCredentialProvider = new DefaultQCloudCredentialProvider(
              secretId, secretKey, durationSecond);

            //初始化 CosXmlServer
            CosXml cosXml = new CosXmlServer(config, cosCredentialProvider);

            //访问 COS 服务
            // 初始化 TransferConfig
            TransferConfig transferConfig = new TransferConfig();

            // 初始化 TransferManager
            TransferManager transferManager = new TransferManager(cosXml, transferConfig);

            string bucket = "info-130****435"; //存储桶,格式:BucketName-APPID
            //获取当前年加月
            string key = DateTime.Now.ToString("yyyyMM");
            //获取当前年月日时分秒
            string key1 = DateTime.Now.ToString("yyyyMMddHHmmss");
            //生成上传文件随机名
            string key2 = key1 + "-" + Guid.NewGuid().ToString("N");
            //从fileName取出文件类型
            string fileType = fileName.Substring(fileName.LastIndexOf("."));
            //生成新的文件名
            string newFileName = key2 + fileType;

            string cosPath = @"uploads/"+key+"/"+ newFileName; //对象在存储桶中的位置标识符,即称对象键
            string srcPath = localFilePath;//本地文件绝对路径

            //返回文件信息
            string url = "";
            // 上传对象
            COSXMLUploadTask uploadTask = new COSXMLUploadTask(bucket, cosPath);
            uploadTask.SetSrcPath(srcPath);

            uploadTask.progressCallback = delegate (long completed, long total)
            {

                Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
            };

            try
            {
                COSXML.Transfer.COSXMLUploadTask.UploadTaskResult result = await
                  transferManager.UploadAsync(uploadTask);
                Console.WriteLine(result.GetResultInfo());
                if (result.httpCode == 200)
                {
                    //获取返回的地址
                    url = "https://"+bucket +".cos."+region+".myqcloud.com/" + cosPath;
                }
                
                Console.WriteLine(url);

                string eTag = result.eTag;
                Console.WriteLine(eTag);
                return url;
            }
            catch (Exception e)
            {
                Console.WriteLine("CosException: " + e);
                return e.ToString();
            }
            
        }
    }
}

八、EF6记录

1.扩展执行原生SQL

官方文档

首先添加以下方法;

/// 
        /// 执行SQL
        /// 
        /// 返回的对象
        /// 上下文
        /// 原生SQL
        /// 参数
        /// 
        public List<TResult> SqlQuery<TResult>(DbContext context, string sql, params object[] parameters) where TResult : class, new()
        {
            List<TResult> list = new List<TResult>();
            var conn = context.Database.GetDbConnection();
            using (var comm = conn.CreateCommand())
            {
                try
                {
                    conn.Open();
                    comm.CommandText = sql;
                    if (parameters != null)
                        comm.Parameters.AddRange(parameters);
                    //CommandBehavior.CloseConnection当SqlDataReader释放的时候,顺便把SqlConnection对象也释放掉
                    var dr = comm.ExecuteReader(CommandBehavior.Default);

                    while (dr.Read())
                    {
                        TResult t = new TResult();
                        for (var i = 0; i < dr.FieldCount; i++)
                        {

                            //类型mapper,有同名的字段或属性赋值否则丢弃
                            var columnName = dr.GetName(i);
                            var colDataType = dr.GetFieldType(i);
                            var val = dr.GetFieldValue<object>(i);

                            var field = t.GetType().GetField(columnName);
                            field?.SetValue(t, val);

                            var property = t.GetType().GetProperty(columnName);
                            property?.SetValue(t, val);
                        }
                        list.Add(t);
                    }
                    dr.Dispose();//调用Dispose之后,该连接会关闭并被销毁,打上回收标记
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    Dispose 适合只在方法中调用一次 SqlConnection 对象,而 Close 更适合 SqlConnection 在关闭后可能需要再次打开的情况
                    //if (conn != null && conn.State != ConnectionState.Closed)
                    //{
                    //    //conn.Close();
                    //}
                }
            }
            return list;
        }

其次 调用如下:

var params = "小明"
var sql = "select * from demo where name='{params}'"
var tempDate = SqlQuery<ResultModel>(_context, Sql).ToList();

由于返回的是一个 泛型List,所以可以直接对结果ToList();

九、其他

1、封装一个统一的简单返回结果

public class ApiResponse<T>
    {
        public bool Success { get; set; }
        public T? Data { get; set; }
        public string? Message { get; set; }

        public ApiResponse(bool success, T? data, string errorMessage = "")
        {
            Success = success;
            Data = data;
            Message = errorMessage;
        }
    }

调用

        //引入数据库上下文
        private readonly everydaytodoContext _context;
        public TestController(everydaytodoContext context)
        {
            _context = context;//实例化数据库上下文
        }


        [HttpGet("Hello")]
        public async Task<IActionResult> GetTest()
        {
            var result = await _context.Test.Where(x => x.Name == "11").ToListAsync();//LINQ 语法

            //throw new Exception("测试异常");

            //return new JsonResult(new { code = 200, msg = "获取成功", data = result });
            // 封装响应结果
            var response = new ApiResponse<List<Models.Test>>(true, result);
            return Ok(response);
        }
    }

备注
return Ok(response); 是一个.NET Core Web API中的返回类型,用于返回HTTP 200 OK状态码以及包含在 response 变量中的数据作为响应主体。

在ASP.NET Core中,控制器方法可以返回不同类型的ActionResult对象,这些对象表示不同的HTTP响应。Ok 是其中之一,它表示HTTP 200 OK状态码。通过将 response 对象作为参数传递给 Ok 方法,您可以将该对象作为JSON响应返回给客户端。

当您调用 return Ok(response); 时,ASP.NET Core会自动将 response 对象序列化为JSON,并将其作为HTTP响应的主体返回给客户端。客户端将收到带有HTTP 200状态码和包含在 response 对象中的数据的响应。

除了 Ok,ASP.NET Core还提供了其他不同的返回类型,如 BadRequest、NotFound、InternalServerError 等,您可以根据需要选择适合的返回类型来表示不同的HTTP状态码和响应。

2、全局异常处理
以下是一种实现全局异常处理的方法:

①、创建一个自定义的异常处理中间件类,用于捕获和处理应用程序中的异常。可以在 Startup.cs 文件中创建一个新的类,例如 ExceptionHandlerMiddleware。

public class ExceptionHandlerMiddleware
{
    private readonly RequestDelegate _next;

    public ExceptionHandlerMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            // 执行下一个中间件
            await _next(context);
        }
        catch (Exception ex)
        {
            // 处理异常并返回自定义的错误响应
            await HandleExceptionAsync(context, ex);
        }
    }

    private static Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        // 根据异常类型进行适当的处理和日志记录
        // 可以根据需要自定义异常处理逻辑

        // 创建自定义的错误响应  下面这里返回可以根据实际情况自己设置
        //var errorResponse = new ApiResponse(false, null, "An error occurred.");
		var errorResponse = new ApiResponse<string>(false, null, exception.Message);
        // 将错误响应转换为JSON字符串
        var json = JsonConvert.SerializeObject(errorResponse, Formatting.None);

        // 设置响应的内容类型为application/json
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        // 将错误响应写入响应主体
        return context.Response.WriteAsync(json);
    }
}

②、在 Program方法中将自定义的异常处理中间件添加到请求管道中。

// 将自定义的异常处理中间件添加到管道中
    app.UseMiddleware<ExceptionHandlerMiddleware>();

.Net Core 6 WebApi 项目搭建_第38张图片

Ⅰ.发布常见问题汇总

标题问题:本地运行,swagger页面正常打开,但是发布以后一直 404
解决方案:
1.找到开发文件 Program.cs
2.找到如下代码

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

3.去除if判断,因为该判断只允许在开发环境显示。但是作为纯接口,有没有页面无所谓,只是方便前端开发人员调用测试。

app.UseSwagger();
app.UseSwaggerUI();

其他解决方案


参考链接

  • .Net Core3.0 WebApi 项目框架搭建
  • ASP.NET Core 中间件
  • ASP.NET Core 中的配置
  • 在 ASP.NET Core 中启用跨源请求 (CORS)
  • 迁移到 ASP.NET Core 6.0
  • Entity Framework Core

你可能感兴趣的:(笔记,.net,core,c#)