服务器部署测试~~~

This commit is contained in:
heiye111
2025-10-10 16:02:38 +08:00
parent 8ab52738c0
commit 5c186aa446
87 changed files with 5062 additions and 167 deletions

View File

@@ -0,0 +1,10 @@
// 此文件包含按正则表达式对文档选项卡进行着色的规则。每行都包含一个正则表达式,该表达式将针对文件的完整路径进行测试。与正则表达式匹配的所有文件都将共享一种颜色。
// 可以通过右键单击选项卡并选择“设置制表符颜色”来自定义分配给任何文件组的颜色。
// 正则表达式将按照它们在此文件中的显示顺序进行匹配。有关语法,请参阅 https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expressions。
// 正则表达式匹配为不区分大小写。可以使用捕获组选项(如"(?-i:expression)")重写此行为。
// 编辑此文件并保存更改以立即查看应用的更改。分析或计算表达式期间遇到的任何错误都将出现在名为 "按正则表达式显示颜色" 的窗格的输出窗口中。
^.*\.cs$
^.*\.fs$
^.*\.vb$
^.*\.cp?p?$
^.*\.hp?p?$

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
{
"Version": 1,
"ColorMap": {
"-1429170308": {
"GroupId": -1429170308,
"ColorIndex": 6
}
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,123 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\code\\SimpleTodoApiWithPg\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|c:\\code\\simpletodoapiwithpg\\endpoints\\userendpoints.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|solutionrelative:endpoints\\userendpoints.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|c:\\code\\simpletodoapiwithpg\\userservice\\userservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|solutionrelative:userservice\\userservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|c:\\code\\simpletodoapiwithpg\\validators\\registerrequestvalidator.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|solutionrelative:validators\\registerrequestvalidator.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|c:\\code\\simpletodoapiwithpg\\models\\requestmodels.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|solutionrelative:models\\requestmodels.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|c:\\code\\simpletodoapiwithpg\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|c:\\code\\simpletodoapiwithpg\\filters\\validationfilter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|solutionrelative:filters\\validationfilter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 5,
"Children": [
{
"$type": "Bookmark",
"Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "ValidationFilter.cs",
"DocumentMoniker": "C:\\code\\SimpleTodoApiWithPg\\Filters\\ValidationFilter.cs",
"RelativeDocumentMoniker": "Filters\\ValidationFilter.cs",
"ToolTip": "C:\\code\\SimpleTodoApiWithPg\\Filters\\ValidationFilter.cs",
"RelativeToolTip": "Filters\\ValidationFilter.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAACAAAABQAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-10T03:34:07.652Z"
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "RegisterRequestValidator.cs",
"DocumentMoniker": "C:\\code\\SimpleTodoApiWithPg\\Validators\\RegisterRequestValidator.cs",
"RelativeDocumentMoniker": "Validators\\RegisterRequestValidator.cs",
"ToolTip": "C:\\code\\SimpleTodoApiWithPg\\Validators\\RegisterRequestValidator.cs",
"RelativeToolTip": "Validators\\RegisterRequestValidator.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAYAAAAlAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-09T14:31:43.048Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "Program.cs",
"DocumentMoniker": "C:\\code\\SimpleTodoApiWithPg\\Program.cs",
"RelativeDocumentMoniker": "Program.cs",
"ToolTip": "C:\\code\\SimpleTodoApiWithPg\\Program.cs",
"RelativeToolTip": "Program.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABIAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-09T13:19:43.049Z"
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "RequestModels.cs",
"DocumentMoniker": "C:\\code\\SimpleTodoApiWithPg\\Models\\RequestModels.cs",
"RelativeDocumentMoniker": "Models\\RequestModels.cs",
"ToolTip": "C:\\code\\SimpleTodoApiWithPg\\Models\\RequestModels.cs",
"RelativeToolTip": "Models\\RequestModels.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAywCYAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-09T07:39:50.184Z"
},
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "UserEndpoints.cs",
"DocumentMoniker": "C:\\code\\SimpleTodoApiWithPg\\Endpoints\\UserEndpoints.cs",
"RelativeDocumentMoniker": "Endpoints\\UserEndpoints.cs",
"ToolTip": "C:\\code\\SimpleTodoApiWithPg\\Endpoints\\UserEndpoints.cs",
"RelativeToolTip": "Endpoints\\UserEndpoints.cs",
"ViewState": "AgIAACEAAAAAAAAAAAAAADUAAAANAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-08T14:40:19.751Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "UserService.cs",
"DocumentMoniker": "C:\\code\\SimpleTodoApiWithPg\\UserService\\UserService.cs",
"RelativeDocumentMoniker": "UserService\\UserService.cs",
"ToolTip": "C:\\code\\SimpleTodoApiWithPg\\UserService\\UserService.cs",
"RelativeToolTip": "UserService\\UserService.cs",
"ViewState": "AgIAAGgAAAAAAAAAAAAAAHcAAAAlAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-08T06:47:44.742Z",
"EditorCaption": ""
}
]
}
]
}
]
}

View File

@@ -0,0 +1,140 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\code\\SimpleTodoApiWithPg\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|c:\\code\\simpletodoapiwithpg\\appsettings.development.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}",
"RelativeMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|solutionrelative:appsettings.development.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}"
},
{
"AbsoluteMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|c:\\code\\simpletodoapiwithpg\\endpoints\\userendpoints.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|solutionrelative:endpoints\\userendpoints.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|c:\\code\\simpletodoapiwithpg\\userservice\\userservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|solutionrelative:userservice\\userservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|c:\\code\\simpletodoapiwithpg\\validators\\registerrequestvalidator.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|solutionrelative:validators\\registerrequestvalidator.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|c:\\code\\simpletodoapiwithpg\\models\\requestmodels.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|solutionrelative:models\\requestmodels.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|c:\\code\\simpletodoapiwithpg\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|c:\\code\\simpletodoapiwithpg\\filters\\validationfilter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{B05B3AC1-7A56-9B3F-B9E1-F21523CC0473}|SimpleTodoApiWithPg.csproj|solutionrelative:filters\\validationfilter.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "appsettings.Development.json",
"DocumentMoniker": "C:\\code\\SimpleTodoApiWithPg\\appsettings.Development.json",
"RelativeDocumentMoniker": "appsettings.Development.json",
"ToolTip": "C:\\code\\SimpleTodoApiWithPg\\appsettings.Development.json",
"RelativeToolTip": "appsettings.Development.json",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAsAAAABAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
"WhenOpened": "2025-10-10T07:56:22.375Z",
"EditorCaption": ""
},
{
"$type": "Bookmark",
"Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "ValidationFilter.cs",
"DocumentMoniker": "C:\\code\\SimpleTodoApiWithPg\\Filters\\ValidationFilter.cs",
"RelativeDocumentMoniker": "Filters\\ValidationFilter.cs",
"ToolTip": "C:\\code\\SimpleTodoApiWithPg\\Filters\\ValidationFilter.cs",
"RelativeToolTip": "Filters\\ValidationFilter.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAACAAAABQAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-10T03:34:07.652Z"
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "RegisterRequestValidator.cs",
"DocumentMoniker": "C:\\code\\SimpleTodoApiWithPg\\Validators\\RegisterRequestValidator.cs",
"RelativeDocumentMoniker": "Validators\\RegisterRequestValidator.cs",
"ToolTip": "C:\\code\\SimpleTodoApiWithPg\\Validators\\RegisterRequestValidator.cs",
"RelativeToolTip": "Validators\\RegisterRequestValidator.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAYAAAAlAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-09T14:31:43.048Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "Program.cs",
"DocumentMoniker": "C:\\code\\SimpleTodoApiWithPg\\Program.cs",
"RelativeDocumentMoniker": "Program.cs",
"ToolTip": "C:\\code\\SimpleTodoApiWithPg\\Program.cs",
"RelativeToolTip": "Program.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABIAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-09T13:19:43.049Z"
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "RequestModels.cs",
"DocumentMoniker": "C:\\code\\SimpleTodoApiWithPg\\Models\\RequestModels.cs",
"RelativeDocumentMoniker": "Models\\RequestModels.cs",
"ToolTip": "C:\\code\\SimpleTodoApiWithPg\\Models\\RequestModels.cs",
"RelativeToolTip": "Models\\RequestModels.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAywCYAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-09T07:39:50.184Z"
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "UserEndpoints.cs",
"DocumentMoniker": "C:\\code\\SimpleTodoApiWithPg\\Endpoints\\UserEndpoints.cs",
"RelativeDocumentMoniker": "Endpoints\\UserEndpoints.cs",
"ToolTip": "C:\\code\\SimpleTodoApiWithPg\\Endpoints\\UserEndpoints.cs",
"RelativeToolTip": "Endpoints\\UserEndpoints.cs",
"ViewState": "AgIAACEAAAAAAAAAAAAAADUAAAANAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-08T14:40:19.751Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "UserService.cs",
"DocumentMoniker": "C:\\code\\SimpleTodoApiWithPg\\UserService\\UserService.cs",
"RelativeDocumentMoniker": "UserService\\UserService.cs",
"ToolTip": "C:\\code\\SimpleTodoApiWithPg\\UserService\\UserService.cs",
"RelativeToolTip": "UserService\\UserService.cs",
"ViewState": "AgIAAGgAAAAAAAAAAAAAAHcAAAAlAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-08T06:47:44.742Z",
"EditorCaption": ""
}
]
}
]
}
]
}

View File

@@ -11,5 +11,7 @@ namespace SimpleTodoApiWithPg.Data
// 定义一个 DbSet 属性,对应数据库中的 Todos 表
public DbSet<Todo> Todos { get; set; } = default!;
public DbSet<User> Users { get; set; } = default!;
public DbSet<RefreshToken> RefreshTokens { get; set; } = default!;
}
}

119
Endpoints/UserEndpoints.cs Normal file
View File

@@ -0,0 +1,119 @@
using FluentValidation;
using Microsoft.EntityFrameworkCore;
using SimpleTodoApiWithPg.Data;
using SimpleTodoApiWithPg.Models;
using SimpleTodoApiWithPg.UserService;
using System.ComponentModel.DataAnnotations;
namespace SimpleTodoApiWithPg.Endpoints
{
public static class UserEndpoints
{
public static void MapUserEndpoints ( this WebApplication app)
{
var usersApi = app.MapGroup("/users")
.CacheOutput()
.RequireAuthorization()
.WithTags("Users");
usersApi.MapGet("/", async (UserServices userService) =>
{
return await userService.GetUsersAsync();
}).WithTags("获取所有用户");
usersApi.MapGet("/{id}", async (Guid id, UserServices userService) =>
{
return await userService.GetoneUserAsync(id);
}).WithTags("根据id获取对应的用户信息");
usersApi.MapPost("/", async (RegisterRequest request, UserServices userService) =>
{
var response = await userService.RegisterAsync(request);
if (!response.Success)
{
return Results.BadRequest(response);
}
return Results.Ok(response);
}).WithTags("用户注册接口")
.AllowAnonymous()
.AddEndpointFilter<ValidationFilter<RegisterRequest>>()
.ProducesValidationProblem();
usersApi.MapPatch("/{id}", async (int id, UpdateUserRequest updateUser, UserServices userService) =>
{
return await userService.UpdateUserAsync(id, updateUser);
}).WithTags("用户信息更新接口");
usersApi.MapDelete("/{id}", async (Guid id,UserServices userService) =>
{
return await userService.DeleteUserAsync(id);
}).WithTags("删除用户接口");
var loginauthApi = app.MapGroup("/api/auth")
.CacheOutput()
.WithTags("登录认证接口!");
loginauthApi.MapPost("/", async (UserServices userService, LoginRequest loginRequest) =>
{
var response = await userService.LoginAuthAsync(loginRequest);
// 如果登录失败,返回一个带有错误码和错误信息的 BadRequest
if (!response.Success)
{
return Results.BadRequest(response);
}
return Results.Ok(response);
}).WithTags("登录认证授权接口!");
// --- 新增刷新令牌端点 ---
loginauthApi.MapPost("/refresh-token", async (
/* 这里可以定义一个DTO来接收RefreshToken */
RefreshTokenRequest refreshToken,
AppDbContext dbContext,
UserServices userServices /* 注入UserServices来复用逻辑 */
) =>
{
// 通过传入的 refreshToken 查找数据库中对应的记录
var storedToken = await dbContext.RefreshTokens
.Include(rt => rt.User) // 同时加载关联的用户信息
.FirstOrDefaultAsync(rt => rt.Token == refreshToken.RefreshToken);
// 检查令牌是否存在、是否有效
if (storedToken == null || !storedToken.IsActive)
{
return Results.BadRequest("无效的刷新令牌。");
}
// (安全增强) 使旧的刷新令牌失效
storedToken.Revoked = DateTime.UtcNow;
// 生成新的访问令牌
var newAccessTokenExpiration = DateTime.UtcNow.AddMinutes(1);
var newAccessToken = userServices.GenerateJwtToken(storedToken.User, newAccessTokenExpiration); // 需要将 GenerateJwtToken 访问修饰符改为 public 或 internal
// 生成新的刷新令牌
var newRefreshToken = userServices.GenerateRefreshToken(); // GenerateRefreshToken 也需要 public/internal
newRefreshToken.UserId = storedToken.UserId;
await dbContext.RefreshTokens.AddAsync(newRefreshToken);
await dbContext.SaveChangesAsync();
return Results.Ok(new AuthResponse
{
AccessToken = newAccessToken,
RefreshToken = newRefreshToken.Token,
AccessTokenExpiration = newAccessTokenExpiration
});
})
.WithTags("刷新令牌接口");
}
}
}

View File

@@ -0,0 +1,45 @@
// Filters/ValidationFilter.cs
using FluentValidation;
// 这是一个可复用的通用过滤器T 是我们要验证的模型类型
public class ValidationFilter<T> : IEndpointFilter where T : class
{
private readonly IValidator<T> _validator;
// 过滤器可以通过构造函数注入它需要的服务,这里我们注入对应的验证器
public ValidationFilter(IValidator<T> validator)
{
_validator = validator;
}
public async ValueTask<object?> InvokeAsync(
EndpointFilterInvocationContext context,
EndpointFilterDelegate next)
{
// 1. 从端点参数中找到我们需要验证的对象
// 我们假设它总是第一个参数,如果不是,可以修改这里的逻辑
var validationTarget = context.Arguments.FirstOrDefault(a => a?.GetType() == typeof(T)) as T;
// 如果在参数中找不到该类型的对象,直接跳过验证
if (validationTarget is null)
{
// 或者可以返回一个错误,这取决于你的业务需求
// return Results.BadRequest("Could not find validation target in request.");
return await next(context);
}
// 2. 使用从DI容器注入的验证器进行验证
var validationResult = await _validator.ValidateAsync(validationTarget);
// 3. 如果验证失败立即中断请求并返回一个标准的400 ValidationProblem
if (!validationResult.IsValid)
{
// 将 FluentValidation 的错误结果转换为 ASP.NET Core 标准的错误响应
return Results.ValidationProblem(validationResult.ToDictionary());
}
// 4. 如果验证成功,则继续执行后续的过滤器或端点本身
return await next(context);
}
}

581
HTML/idexe.html Normal file
View File

@@ -0,0 +1,581 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ASP.NET Core Minimal API CRUD Test</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f4f4f4;
color: #333;
}
h1, h2, h3 {
color: #0056b3;
}
.container {
display: flex;
gap: 20px;
flex-wrap: wrap;
}
.entity-section {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
padding: 20px;
flex: 1;
min-width: 450px;
box-sizing: border-box;
}
.operation-section {
padding: 15px;
border: 1px solid #eee;
border-radius: 5px;
margin-bottom: 15px;
background-color: #f9f9f9;
}
.operation-section h4 {
margin-top: 0;
color: #333;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="text"],
input[type="number"],
input[type="email"],
input[type="password"],
input[type="checkbox"],
textarea {
width: calc(100% - 22px);
padding: 8px;
margin-bottom: 10px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
input[type="checkbox"] {
width: auto;
margin-right: 5px;
}
button {
background-color: #007bff;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.2s ease;
margin-right: 10px;
}
button:hover {
background-color: #0056b3;
}
.result-box {
background-color: #e9ecef;
border: 1px solid #ced4da;
padding: 15px;
margin-top: 15px;
border-radius: 5px;
white-space: pre-wrap;
font-family: monospace;
max-height: 300px;
overflow-y: auto;
}
.error {
color: red;
font-weight: bold;
}
.success {
color: green;
font-weight: bold;
}
.loading {
color: gray;
font-style: italic;
}
ul {
list-style-type: none;
padding: 0;
}
li {
background-color: #f0f0f0;
margin-bottom: 5px;
padding: 8px;
border-radius: 3px;
border-left: 5px solid #007bff;
}
</style>
</head>
<body>
<h1>ASP.NET Core Minimal API CRUD 测试</h1>
<p>确保您的 ASP.NET Core 应用正在运行,并监听以下基准 URL。</</p>
<div class="container">
<!-- Todo Section -->
<div class="entity-section">
<h2>待办事项 (Todos) CRUD</h2>
<!-- 获取所有 Todo -->
<div class="operation-section">
<h4>获取所有待办事项</h4>
<button onclick="getAllTodos()">获取所有 Todo</button>
<div id="allTodosResult" class="result-box"></div>
</div>
<!-- 根据 ID 获取 Todo -->
<div class="operation-section">
<h4>根据 ID 获取待办事项</h4>
<label for="getTodoId">待办事项 ID:</label>
<input type="number" id="getTodoId" value="1">
<button onclick="getTodoById()">获取 Todo</button>
<div id="singleTodoResult" class="result-box"></div>
</div>
<!-- 创建 Todo -->
<div class="operation-section">
<h4>创建待办事项</h4>
<label for="createTodoTitle">标题:</label>
<input type="text" id="createTodoTitle" placeholder="新的待办事项标题">
<label for="createTodoIsCompleted">已完成:</label>
<input type="checkbox" id="createTodoIsCompleted">
<label for="createTodoUserId">用户ID (关联的用户):</label>
<input type="number" id="createTodoUserId" value="1" placeholder="例如: 1">
<button onclick="createTodo()">创建 Todo</button>
<div id="createTodoResult" class="result-box"></div>
</div>
<!-- 更新 Todo -->
<div class="operation-section">
<h4>更新待办事项</h4>
<label for="updateTodoId">待办事项 ID:</label>
<input type="number" id="updateTodoId" value="1">
<label for="updateTodoTitle">新标题:</label>
<input type="text" id="updateTodoTitle" placeholder="更新后的待办事项标题">
<label for="updateTodoIsCompleted">已完成:</label>
<input type="checkbox" id="updateTodoIsCompleted">
<label for="updateTodoUserId">用户ID (关联的用户):</label>
<input type="number" id="updateTodoUserId" value="1" placeholder="例如: 1">
<button onclick="updateTodo()">更新 Todo</button>
<div id="updateTodoResult" class="result-box"></div>
</div>
<!-- 删除 Todo -->
<div class="operation-section">
<h4>删除待办事项</h4>
<label for="deleteTodoId">待办事项 ID:</label>
<input type="number" id="deleteTodoId" value="1">
<button onclick="deleteTodo()">删除 Todo</button>
<div id="deleteTodoResult" class="result-box"></div>
</div>
</div>
<!-- User Section -->
<div class="entity-section">
<h2>用户 (Users) CRUD</h2>
<!-- 获取所有 User -->
<div class="operation-section">
<h4>获取所有用户</h4>
<button onclick="getAllUsers()">获取所有 User</button>
<div id="allUsersResult" class="result-box"></div>
</div>
<!-- 根据 ID 获取 User -->
<div class="operation-section">
<h4>根据 ID 获取用户</h4>
<label for="getUserId">用户 ID:</label>
<input type="number" id="getUserId" value="1">
<button onclick="getUserById()">获取 User</button>
<div id="singleUserResult" class="result-box"></div>
</div>
<!-- 用户验证/登录 (使用 PATCH 方法) -->
<div class="operation-section">
<h4>用户验证 (Check User Credentials)</h4>
<label for="verifyUsername">用户名:</label>
<input type="text" id="verifyUsername" placeholder="要验证的用户名">
<label for="verifyPasswordHash">密码哈希:</label>
<input type="password" id="verifyPasswordHash" placeholder="对应用户的密码哈希">
<button onclick="verifyUserCredentials()">验证用户</button>
<div id="verifyUserResult" class="result-box"></div>
</div>
<!-- 创建 User -->
<div class="operation-section">
<h4>创建用户</h4>
<label for="createUsername">用户名:</label>
<input type="text" id="createUsername" placeholder="新用户名">
<label for="createUserEmail">邮箱:</label>
<input type="email" id="createUserEmail" placeholder="user@example.com">
<label for="createUserPasswordHash">密码哈希 (例如: plainTextPassword的哈希值):</label>
<input type="password" id="createUserPasswordHash" placeholder="PasswordHash">
<button onclick="createUser()">创建 User</button>
<div id="createUserResult" class="result-box"></div>
</div>
<!-- 更新 User -->
<div class="operation-section">
<h4>更新用户</h4>
<label for="updateUserId">用户 ID:</label>
<input type="number" id="updateUserId" value="1">
<label for="updateUsername">新用户名:</label>
<input type="text" id="updateUsername" placeholder="更新后的用户名">
<label for="updateUserEmail">新邮箱:</label>
<input type="email" id="updateUserEmail" placeholder="updated@example.com">
<label for="updateUserPasswordHash">新密码哈希:</label>
<input type="password" id="updateUserPasswordHash" placeholder="UpdatedPasswordHash">
<button onclick="updateUser()">更新 User</button>
<div id="updateUserResult" class="result-box"></div>
</div>
<!-- 删除 User -->
<div class="operation-section">
<h4>删除用户</h4>
<label for="deleteUserId">用户 ID:</label>
<input type="number" id="deleteUserId" value="1">
<button onclick="deleteUser()">删除 User</button>
<div id="deleteUserResult" class="result-box"></div>
</div>
</div>
</div>
<script>
// === 配置您的 API 基础 URL ===
// 如果您的 API 运行在其他端口或地址,请修改此变量
const BASE_URL = 'http://localhost:5071';
// 对于 HTTPS可能需要改为 'https://localhost:5001'
// === 辅助函数 ===
async function fetchData(url, method = 'GET', data = null) {
const options = {
method: method,
headers: {
'Content-Type': 'application/json',
},
};
if (data) {
options.body = JSON.stringify(data);
}
try {
const response = await fetch(url, options);
let result;
// 尝试解析JSON响应但对于204 No Content等情况可能没有响应体
if (response.headers.get("content-type")?.includes("application/json")) {
result = await response.json();
} else {
result = await response.text(); // 如果不是 JSON尝试获取文本
}
if (!response.ok) {
throw new Error(`HTTP 错误! Status: ${response.status}, Message: ${result}`);
}
return result;
} catch (error) {
console.error('Fetch error:', error);
throw error;
}
}
function displayResult(elementId, data, isError = false) {
const resultBox = document.getElementById(elementId);
resultBox.innerHTML = '';
if (isError) {
resultBox.classList.add('error');
resultBox.textContent = `Error: ${data}`;
} else {
resultBox.classList.remove('error');
resultBox.classList.add('success');
if (typeof data === 'object') {
resultBox.textContent = JSON.stringify(data, null, 2);
} else {
resultBox.textContent = data;
}
}
resultBox.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
// === Todo Functions ===
async function getAllTodos() {
const resultBox = document.getElementById('allTodosResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '加载中...';
try {
const todos = await fetchData(`${BASE_URL}/todos`);
displayResult('allTodosResult', todos);
} catch (error) {
displayResult('allTodosResult', error.message, true);
}
}
async function getTodoById() {
const id = document.getElementById('getTodoId').value;
if (!id) {
displayResult('singleTodoResult', '请输入待办事项 ID。', true);
return;
}
const resultBox = document.getElementById('singleTodoResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '加载中...';
try {
const todo = await fetchData(`${BASE_URL}/todos/${id}`);
displayResult('singleTodoResult', todo);
} catch (error) {
displayResult('singleTodoResult', error.message, true);
}
}
async function createTodo() {
const title = document.getElementById('createTodoTitle').value;
const isCompleted = document.getElementById('createTodoIsCompleted').checked;
const userId = parseInt(document.getElementById('createTodoUserId').value);
if (!title) {
displayResult('createTodoResult', '标题不能为空。', true);
return;
}
if (isNaN(userId)) {
displayResult('createTodoResult', '用户ID必须是数字。', true);
return;
}
const newTodo = {
title: title,
isCompleted: isCompleted,
userId: userId
};
const resultBox = document.getElementById('createTodoResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '创建中...';
try {
const createdTodo = await fetchData(`${BASE_URL}/todos`, 'POST', newTodo);
displayResult('createTodoResult', createdTodo);
// 刷新所有 Todo 列表
getAllTodos();
} catch (error) {
displayResult('createTodoResult', error.message, true);
}
}
async function updateTodo() {
const id = document.getElementById('updateTodoId').value;
const title = document.getElementById('updateTodoTitle').value;
const isCompleted = document.getElementById('updateTodoIsCompleted').checked;
const userId = parseInt(document.getElementById('updateTodoUserId').value);
if (!id) {
displayResult('updateTodoResult', '请输入待办事项 ID。', true);
return;
}
if (!title) {
displayResult('updateTodoResult', '标题不能为空。', true);
return;
}
if (isNaN(userId)) {
displayResult('updateTodoResult', '用户ID必须是数字。', true);
return;
}
const updatedTodo = {
id: parseInt(id), // ID 也需要包含在 PUT 请求体中
title: title,
isCompleted: isCompleted,
userId: userId
};
const resultBox = document.getElementById('updateTodoResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '更新中...';
try {
await fetchData(`${BASE_URL}/todos/${id}`, 'PUT', updatedTodo);
displayResult('updateTodoResult', `待办事项 (ID: ${id}) 更新成功。`);
getTodoById(); // 刷新单个Todo
getAllTodos(); // 刷新所有Todo
} catch (error) {
displayResult('updateTodoResult', error.message, true);
}
}
async function deleteTodo() {
const id = document.getElementById('deleteTodoId').value;
if (!id) {
displayResult('deleteTodoResult', '请输入待办事项 ID。', true);
return;
}
const resultBox = document.getElementById('deleteTodoResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '删除中...';
try {
const response = await fetchData(`${BASE_URL}/todos/${id}`, 'DELETE');
displayResult('deleteTodoResult', response);
getAllTodos(); // 刷新所有Todo
} catch (error) {
displayResult('deleteTodoResult', error.message, true);
}
}
// === User Functions ===
async function getAllUsers() {
const resultBox = document.getElementById('allUsersResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '加载中...';
try {
const users = await fetchData(`${BASE_URL}/users`);
displayResult('allUsersResult', users);
} catch (error) {
displayResult('allUsersResult', error.message, true);
}
}
async function getUserById() {
const id = document.getElementById('getUserId').value;
if (!id) {
displayResult('singleUserResult', '请输入用户 ID。', true);
return;
}
const resultBox = document.getElementById('singleUserResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '加载中...';
try {
const user = await fetchData(`${BASE_URL}/users/${id}`);
displayResult('singleUserResult', user);
} catch (error) {
displayResult('singleUserResult', error.message, true);
}
}
async function createUser() {
const username = document.getElementById('createUsername').value;
const email = document.getElementById('createUserEmail').value;
const passwordHash = document.getElementById('createUserPasswordHash').value;
if (!username || !email || !passwordHash) {
displayResult('createUserResult', '用户名、邮箱和密码哈希不能为空。', true);
return;
}
const newUser = {
username: username,
email: email,
passwordHash: passwordHash
};
const resultBox = document.getElementById('createUserResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '创建中...';
try {
const createdUser = await fetchData(`${BASE_URL}/users`, 'POST', newUser);
displayResult('createUserResult', createdUser);
getAllUsers(); // 刷新所有用户列表
} catch (error) {
displayResult('createUserResult', error.message, true);
}
}
// PACTH /users - 验证用户凭据
async function verifyUserCredentials() {
const username = document.getElementById('verifyUsername').value;
const passwordHash = document.getElementById('verifyPasswordHash').value;
if (!username || !passwordHash) {
displayResult('verifyUserResult', '用户名和密码哈希不能为空。', true);
return;
}
const userToVerify = {
// PATCH 请求体中通常不包含 ID因为您的 API 是通过 Username 来查找
// 但如果需要,也可以写上 Id: 0 或其他占位符
username: username,
passwordHash: passwordHash
};
const resultBox = document.getElementById('verifyUserResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '验证中...';
try {
// 使用 PATCH 方法发送请求
const response = await fetchData(`${BASE_URL}/users`, 'PATCH', userToVerify);
displayResult('verifyUserResult', response);
} catch (error) {
// 如果 API 返回的是 BadRequest (400)fetchData 会抛出异常
// 异常的 message 应该包含 API 返回的错误信息
displayResult('verifyUserResult', error.message, true);
}
}
async function updateUser() {
const id = document.getElementById('updateUserId').value;
const username = document.getElementById('updateUsername').value;
const email = document.getElementById('updateUserEmail').value;
const passwordHash = document.getElementById('updateUserPasswordHash').value;
if (!id) {
displayResult('updateUserResult', '请输入用户 ID。', true);
return;
}
if (!username || !email || !passwordHash) {
displayResult('updateUserResult', '用户名、邮箱和密码哈希不能为空。', true);
return;
}
const updatedUser = {
id: parseInt(id), // ID 也需要包含在 PUT 请求体中
username: username,
email: email,
passwordHash: passwordHash
};
const resultBox = document.getElementById('updateUserResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '更新中...';
try {
await fetchData(`${BASE_URL}/users/${id}`, 'PUT', updatedUser);
displayResult('updateUserResult', `用户 (ID: ${id}) 更新成功。`);
getUserById(); // 刷新单个用户
getAllUsers(); // 刷新所有用户
} catch (error) {
displayResult('updateUserResult', error.message, true);
}
}
async function deleteUser() {
const id = document.getElementById('deleteUserId').value;
if (!id) {
displayResult('deleteUserResult', '请输入用户 ID。', true);
return;
}
const resultBox = document.getElementById('deleteUserResult');
resultBox.classList.remove('success', 'error');
resultBox.classList.add('loading');
resultBox.textContent = '删除中...';
try {
const response = await fetchData(`${BASE_URL}/users/${id}`, 'DELETE');
displayResult('deleteUserResult', response);
getAllUsers(); // 刷新所有用户列表
} catch (error) {
displayResult('deleteUserResult', error.message, true);
}
}
// 页面加载完成后自动获取所有待办事项和用户
document.addEventListener('DOMContentLoaded', () => {
getAllTodos();
getAllUsers();
});
</script>
</body>
</html>

View File

@@ -1,49 +0,0 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using SimpleTodoApiWithPg.Data;
#nullable disable
namespace SimpleTodoApiWithPg.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20250922140100_InitialCreate")]
partial class InitialCreate
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.9")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("SimpleTodoApiWithPg.Models.Todo", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<bool>("IsCompleted")
.HasColumnType("boolean");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Todos");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,36 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace SimpleTodoApiWithPg.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Todos",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Title = table.Column<string>(type: "text", nullable: false),
IsCompleted = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Todos", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Todos");
}
}
}

View File

@@ -0,0 +1,117 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using SimpleTodoApiWithPg.Data;
#nullable disable
namespace SimpleTodoApiWithPg.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20251009024853_InitialCreateWithGuidIds")]
partial class InitialCreateWithGuidIds
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.9")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("SimpleTodoApiWithPg.Models.RefreshToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("Created")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("Expires")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("Revoked")
.HasColumnType("timestamp with time zone");
b.Property<string>("Token")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("RefreshTokens");
});
modelBuilder.Entity("SimpleTodoApiWithPg.Models.Todo", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsCompleted")
.HasColumnType("boolean");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Todos");
});
modelBuilder.Entity("SimpleTodoApiWithPg.Models.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("PasswordHash")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("Username")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.HasKey("Id");
b.ToTable("Users");
});
modelBuilder.Entity("SimpleTodoApiWithPg.Models.RefreshToken", b =>
{
b.HasOne("SimpleTodoApiWithPg.Models.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,83 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SimpleTodoApiWithPg.Migrations
{
/// <inheritdoc />
public partial class InitialCreateWithGuidIds : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Todos",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Title = table.Column<string>(type: "text", nullable: false),
IsCompleted = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Todos", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Username = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
Email = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
PasswordHash = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.Id);
});
migrationBuilder.CreateTable(
name: "RefreshTokens",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Token = table.Column<string>(type: "text", nullable: false),
Expires = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Created = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Revoked = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
UserId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_RefreshTokens", x => x.Id);
table.ForeignKey(
name: "FK_RefreshTokens_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_RefreshTokens_UserId",
table: "RefreshTokens",
column: "UserId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "RefreshTokens");
migrationBuilder.DropTable(
name: "Todos");
migrationBuilder.DropTable(
name: "Users");
}
}
}

View File

@@ -0,0 +1,117 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using SimpleTodoApiWithPg.Data;
#nullable disable
namespace SimpleTodoApiWithPg.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20251009035553_Initial3")]
partial class Initial3
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "9.0.9")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("SimpleTodoApiWithPg.Models.RefreshToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("Created")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("Expires")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("Revoked")
.HasColumnType("timestamp with time zone");
b.Property<string>("Token")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("RefreshTokens");
});
modelBuilder.Entity("SimpleTodoApiWithPg.Models.Todo", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsCompleted")
.HasColumnType("boolean");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Todos");
});
modelBuilder.Entity("SimpleTodoApiWithPg.Models.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("PasswordHash")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("Username")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.HasKey("Id");
b.ToTable("Users");
});
modelBuilder.Entity("SimpleTodoApiWithPg.Models.RefreshToken", b =>
{
b.HasOne("SimpleTodoApiWithPg.Models.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,38 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SimpleTodoApiWithPg.Migrations
{
/// <inheritdoc />
public partial class Initial3 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Email",
table: "Users",
type: "character varying(50)",
maxLength: 50,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(100)",
oldMaxLength: 100);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Email",
table: "Users",
type: "character varying(100)",
maxLength: 100,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(50)",
oldMaxLength: 50);
}
}
}

View File

@@ -1,4 +1,5 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
@@ -21,13 +22,40 @@ namespace SimpleTodoApiWithPg.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("SimpleTodoApiWithPg.Models.RefreshToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("Created")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("Expires")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("Revoked")
.HasColumnType("timestamp with time zone");
b.Property<string>("Token")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("RefreshTokens");
});
modelBuilder.Entity("SimpleTodoApiWithPg.Models.Todo", b =>
{
b.Property<int>("Id")
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
.HasColumnType("uuid");
b.Property<bool>("IsCompleted")
.HasColumnType("boolean");
@@ -40,6 +68,46 @@ namespace SimpleTodoApiWithPg.Migrations
b.ToTable("Todos");
});
modelBuilder.Entity("SimpleTodoApiWithPg.Models.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.Property<string>("PasswordHash")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("Username")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.HasKey("Id");
b.ToTable("Users");
});
modelBuilder.Entity("SimpleTodoApiWithPg.Models.RefreshToken", b =>
{
b.HasOne("SimpleTodoApiWithPg.Models.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
#pragma warning restore 612, 618
}
}

44
Models/RequestModels.cs Normal file
View File

@@ -0,0 +1,44 @@
using System.ComponentModel.DataAnnotations;
namespace SimpleTodoApiWithPg.Models
{
public class UpdateUserRequest
{
// 设为可空类型,表示这些字段可以选择性更新
[MaxLength(50)]
public string? Username { get; set; }
[MaxLength(100)]
[EmailAddress] // 仍然应用验证
public string? Email { get; set; }
// 密码更新处理:提供一个用于接收新明文密码的字段
// 注意:不应该有 PasswordHash 字段!
[MaxLength(50)]
public string? NewPassword { get; set; }
}
public class LoginRequest
{
[Required(ErrorMessage = "用户名不能为空")]
[MaxLength(50, ErrorMessage = "用户名长度不能超过50个字符")]
public string Username { get; set; } = null!; // null! 表示编译器知道它不会是null
[Required(ErrorMessage = "密码不能为空")]
[MaxLength(50,ErrorMessage = "密码长度不能超过50个字符!")]
// 可以添加 MinLength/MaxLength 验证
public string Password { get; set; } = null!; // 明文密码
}
public class RegisterRequest()
{
public required string Username { get; set; }
public required string Email { get; set; }
}
public record RefreshTokenRequest(string RefreshToken);
}

50
Models/ResponseModels.cs Normal file
View File

@@ -0,0 +1,50 @@
namespace SimpleTodoApiWithPg.Models
{
// 这是一个泛型记录 (generic record),用于包装所有 API 的返回数据
public record ApiResponse<T>(
bool Success,
string Message,
T? Data,
int Code = 200
);
// 提供一个静态类,方便快速创建标准响应
public static class ApiResponse
{
public static ApiResponse<T> Ok<T>(T data, string message = "操作成功")
{
return new ApiResponse<T>(true, message, data);
}
// **** 关键修改在这里:让 Fail 方法也变为泛型 ****
// 它接受一个类型参数 T并返回 ApiResponse<T>
// default(T) 对于引用类型(如 AuthResponse会返回 null
public static ApiResponse<T> Fail<T>(string message, int code = 400)
{
return new ApiResponse<T>(false, message, default(T), code);
}
// 您可以保留一个非泛型版本的 Fail 方便在某些无需特定 Data 类型的地方使用
// 但在需要特定返回类型的地方,请使用泛型版本
public static ApiResponse<object> Fail(string message, int code = 400)
{
return new ApiResponse<object>(false, message, null, code);
}
}
// 更新登录成功后返回的 DTO
public class AuthResponse
{
public string AccessToken { get; set; } = null!;
public string RefreshToken { get; set; } = null!;
public DateTime AccessTokenExpiration { get; set; }
}
public class RegisterResponse
{
public string? Username { get; set; }
public string? Email { get; set; }
public string? Password { get; set; }
public Guid UserId { get; set; }
}
}

View File

@@ -2,7 +2,7 @@ namespace SimpleTodoApiWithPg.Models
{
public class Todo
{
public int Id { get; set; }
public Guid Id { get; set; } = Guid.CreateVersion7();
public string Title { get; set; } = string.Empty; // 待办事项标题
public bool IsCompleted { get; set; } // 是否已完成
}

56
Models/User.cs Normal file
View File

@@ -0,0 +1,56 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace SimpleTodoApiWithPg.Models
{
public class User
{
[Key] // 标识 Id 为主键
//[DatabaseGenerated(DatabaseGeneratedOption.Identity)] // 数据库自动生成(例如 PostgreSQL 的 SERIAL 类型)
public Guid Id { get; set; } = Guid.CreateVersion7();
[Required] // 标识为非空字段
[MaxLength(50)] // 限制字符串最大长度
public string Username { get; set; } = null!;
[Required(ErrorMessage = "邮箱是必填项。")]
[EmailAddress(ErrorMessage = "邮箱格式不正确。")] //
[StringLength(50, MinimumLength = 5, ErrorMessage = "邮箱长度必须在 {2} 到 {1} 个字符之间。")] //
public string Email { get; set; } = null!;
// 密码通常会存储哈希值,而不是明文
[Required]
[MaxLength(100)]
public string PasswordHash { get; set; } = null!;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
// 如果需要,可以添加导航属性,例如,一个用户可以有多个 Todo
// public ICollection<Todo> Todos { get; set; } = new List<Todo>();
}
public class RefreshToken
{
[Key]
public Guid Id { get; set; } = Guid.CreateVersion7();
[Required]
public string Token { get; set; } = null!; // 存储 refresh token 的字符串
[Required]
public DateTime Expires { get; set; } // 过期时间
public bool IsExpired => DateTime.UtcNow >= Expires; // 计算属性,判断是否已过期
public DateTime Created { get; set; } // 创建时间
public DateTime? Revoked { get; set; } // 撤销时间 (可空)
public bool IsActive => Revoked == null && !IsExpired; // 计算属性,判断是否有效
// 外键关联到 User 表
public Guid UserId { get; set; }
[ForeignKey("UserId")]
public User User { get; set; } = null!;
}
}

View File

@@ -1,11 +1,119 @@
using FluentValidation; // <--- 关键!这是现在唯一需要的 using
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using SimpleTodoApiWithPg.Data;
using SimpleTodoApiWithPg.Models;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using SimpleTodoApiWithPg.Endpoints;
using SimpleTodoApiWithPg.UserService;
using System.Security.Cryptography.X509Certificates;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddConsole(); //日志服务
builder.Services.AddScoped<UserServices>(); //注册用户服务
// 1. 添加OpenAPI/Swagger生成器服务到容器
builder.Services.AddEndpointsApiExplorer(); // 这个服务负责发现和描述API端点
builder.Services.AddSwaggerGen(); // 这个服务负责根据端点描述生成OpenAPI JSON文档
// 1. 扫描并注册你项目里的所有验证器
builder.Services.AddValidatorsFromAssemblyContaining<Program>(includeInternalTypes: true);
// 注册所有 validator按包含类型或指定程序集
var certPath = builder.Configuration["Jwt:CertificatePath"];
var certPassword = builder.Configuration["Jwt:CertificatePassword"];
var certificate = X509CertificateLoader.LoadPkcs12FromFile(certPath!, certPassword);
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
// 使用证书的公钥进行验证
IssuerSigningKey = new ECDsaSecurityKey(certificate.GetECDsaPublicKey()!),
// 确保指定正确的签名算法
// 对于 ECDSA P-256应该是 "ES256"
ValidAlgorithms = [SecurityAlgorithms.EcdsaSha256] // 可选,增加安全性
};
// 新增:配置认证事件
options.Events = new JwtBearerEvents
{
// 当认证失败需要向客户端发起质询Challenge时触发
OnChallenge = context =>
{
// 阻止默认的响应行为,我们将来完全自定义响应
context.HandleResponse();
context.Response.StatusCode = 401;
context.Response.ContentType = "application/json";
// 默认的错误信息
var message = "身份验证失败,请检查您的 Token。";
// 检查具体的失败原因,如果是 Token 过期,就给出更明确的提示
// AuthenticateFailure 属性包含了认证失败时的异常信息
if (context.AuthenticateFailure is SecurityTokenExpiredException)
{
message = "您的 Token 已过期,请重新登录或刷新 Token。";
}
// 您也可以在这里记录日志,方便排查问题
// logger.LogError(context.AuthenticateFailure, "An authentication error occurred.");
var response = new
{
success = false,
message = message
};
// 将自定义的响应内容写入 Response Body
return context.Response.WriteAsJsonAsync(response);
}
};
});
builder.Services.AddAuthorization();
// === 配置 CORS ===
// 定义一个 CORS 策略名称
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
// 添加 CORS 服务到依赖注入容器
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
// 允许所有来源进行访问。
// 注意:这在生产环境中是极度不安全的,仅用于本地开发和测试。
// 在生产环境中,您应该明确指定允许的源:
// policy.WithOrigins("http://localhost:8080", "https://yourfrontend.com")
// 或者如果您直接打开HTML文件其来源是'null',您可以明确允许它:
// policy.WithOrigins("null") // 在此测试场景下这是一个选项但AllowAnyOrigin更通用
policy.AllowAnyOrigin() // 允许任何来源的请求
.AllowAnyHeader() // 允许任何请求头
.AllowAnyMethod(); // 允许任何 HTTP 方法 (GET, POST, PUT, DELETE)
});
});
// === 配置 EF Core 连接 PostgreSQL ===
// 从配置中获取连接字符串
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
@@ -14,8 +122,19 @@ var connectionString = builder.Configuration.GetConnectionString("DefaultConnect
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(connectionString)); // 使用 Npgsql 作为 PostgreSQL 提供者
var app = builder.Build();
// 2. 在管道中启用中间件 (通常只在开发环境中启用)
if (app.Environment.IsDevelopment())
{
app.UseSwagger(); // 这个中间件负责提供生成的 swagger.json 文件
app.UseSwaggerUI(); // 这个中间件负责提供交互式的Swagger UI界面
}
// === CORS 中间件必须放在其他中间件之前 (例如路由,授权,认证等) ===
// 启用 CORS
app.UseCors(MyAllowSpecificOrigins);
// === 应用数据库迁移 (仅在开发环境中推荐) ===
// 在应用启动时自动应用所有挂起的数据库迁移
using (var scope = app.Services.CreateScope())
@@ -26,68 +145,144 @@ using (var scope = app.Services.CreateScope())
// === 定义 API 端点 (Endpoints) ===
// GET /todos - 获取所有待办事项
app.MapGet("/todos", async (AppDbContext dbContext) =>
{
var todos = await dbContext.Todos.ToListAsync();
return TypedResults.Ok(todos);
});
// GET /todos/{id} - 根据 ID 获取单个待办事项
app.MapGet("/todos/{id}", async (int id, AppDbContext dbContext) =>
{
var todo = await dbContext.Todos.FindAsync(id);
return todo is not null
? TypedResults.Ok(todo)
: Results.NotFound($"待办事项 (ID: {id}) 不存在。");
});
// GET / - 根路径,返回一个简单的消息
app.MapGet("/", () => "Hello World!");
app.MapUserEndpoints();
app.UseAuthentication();
app.UseAuthorization();
// POST /todos - 新增一个待办事项
app.MapPost("/todos", async (Todo todo, AppDbContext dbContext) =>
{
// EF Core 会自动处理 ID 的生成(如果是自增主键)
dbContext.Todos.Add(todo);
await dbContext.SaveChangesAsync(); // 保存更改到数据库
//app.MapPatch("/users", async (User user, UserService userService) =>
//{
// return await userService.PatchUserAsync(user);
//});
//// GET /todos - 获取所有待办事项
//app.MapGet("/todos", async (AppDbContext dbContext) =>
//{
// var todos = await dbContext.Todos.ToListAsync();
// return TypedResults.Ok(todos);
//});
// 回传 201 Created 并提供新资源的位置
return Results.Created($"/todos/{todo.Id}", todo);
});
//// GET /users - 获取所有用户
//app.MapGet("/users", async (AppDbContext dbContext) =>
//{
// var users = await dbContext.Users.ToListAsync();
// return TypedResults.Ok(users);
//});
// PUT /todos/{id} - 更新指定的待办事项
app.MapPut("/todos/{id}", async (int id, Todo inputTodo, AppDbContext dbContext) =>
{
// 查找现有待办事项
var existingTodo = await dbContext.Todos.FindAsync(id);
//// GET /todos/{id} - 根据 ID 获取单个待办事项
//app.MapGet("/todos/{id}", async (int id, AppDbContext dbContext) =>
//{
// var todo = await dbContext.Todos.FindAsync(id);
// return todo is not null
// ? TypedResults.Ok(todo)
// : Results.NotFound($"待办事项 (ID: {id}) 不存在。");
//});
if (existingTodo is null)
{
return Results.NotFound($"待办事项 (ID: {id}) 不存在。");
}
// GET /users/{id} - 根据 ID 获取单个用户
//app.MapGet("/users/{id}", async (int id, AppDbContext dbContext) =>
//{
// var user = await dbContext.Users.FindAsync(id);
// return user is not null
// ? TypedResults.Ok(user)
// : Results.NotFound($"用户 (ID: {id}) 不存在。");
//});
// 更新属性
existingTodo.Title = inputTodo.Title;
existingTodo.IsCompleted = inputTodo.IsCompleted;
//// POST /todos - 新增一个待办事项
//app.MapPost("/todos", async (Todo todo, AppDbContext dbContext) =>
//{
// // EF Core 会自动处理 ID 的生成(如果是自增主键)
// dbContext.Todos.Add(todo);
// await dbContext.SaveChangesAsync(); // 保存更改到数据库
await dbContext.SaveChangesAsync(); // 保存更改到数据库
// // 回传 201 Created 并提供新资源的位置
// return Results.Created($"/todos/{todo.Id}", todo);
//});
return Results.NoContent(); // 回传 204 No Content 表示成功但无内容回传
});
// DELETE /todos/{id} - 删除指定的待办事项
app.MapDelete("/todos/{id}", async (int id, AppDbContext dbContext) =>
{
var todoToDelete = await dbContext.Todos.FindAsync(id);
//// POST /users - 新增一个用户
//app.MapPost("/users", async (User user, AppDbContext dbContext) =>
//{
// user.PasswordHash = RandomNumberGenerator.GetString("0123456789",22);
// Console.WriteLine(user.PasswordHash);
// user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(user.PasswordHash,10,true); // 哈希密码
// // EF Core 会自动处理 ID 的生成(如果是自增主键)
// dbContext.Users.Add(user);
// await dbContext.SaveChangesAsync(); // 保存更改到数据库
if (todoToDelete is null)
{
return Results.NotFound($"待办事项 (ID: {id}) 不存在。");
}
// // 回传 201 Created 并提供新资源的位置
// return Results.Created($"/users/{user.Id}", user);
//});
dbContext.Todos.Remove(todoToDelete);
await dbContext.SaveChangesAsync(); // 保存更改到数据库
return TypedResults.Ok($"待办事项 (ID: {id}) 已成功删除。");
});
//// PUT /todos/{id} - 更新指定的待办事项
//app.MapPut("/todos/{id}", async (int id, Todo inputTodo, AppDbContext dbContext) =>
//{
// // 查找现有待办事项
// var existingTodo = await dbContext.Todos.FindAsync(id);
// if (existingTodo is null)
// {
// return Results.NotFound($"待办事项 (ID: {id}) 不存在。");
// }
// // 更新属性
// existingTodo.Title = inputTodo.Title;
// existingTodo.IsCompleted = inputTodo.IsCompleted;
// await dbContext.SaveChangesAsync(); // 保存更改到数据库
// return Results.NoContent(); // 回传 204 No Content 表示成功但无内容回传
//});
//// PUT /users/{id} - 更新指定的用户
//app.MapPut("/users/{id}", async (int id, User inputUser, AppDbContext dbContext) =>
//{
// // 查找现有用户
// var existingUser = await dbContext.Users.FindAsync(id);
// if (existingUser is null)
// {
// return Results.NotFound($"用户 (ID: {id}) 不存在。");
// }
// // 更新属性
// existingUser.Username = inputUser.Username;
// existingUser.Email = inputUser.Email;
// existingUser.PasswordHash = BCrypt.Net.BCrypt.HashPassword(inputUser.PasswordHash,10,true); // 哈希密码
// await dbContext.SaveChangesAsync();
// return Results.NoContent();
//});
//// DELETE /todos/{id} - 删除指定的待办事项
//app.MapDelete("/todos/{id}", async (int id, AppDbContext dbContext) =>
//{
// var todoToDelete = await dbContext.Todos.FindAsync(id);
// if (todoToDelete is null)
// {
// return Results.NotFound($"待办事项 (ID: {id}) 不存在。");
// }
// dbContext.Todos.Remove(todoToDelete);
// await dbContext.SaveChangesAsync(); // 保存更改到数据库
// return TypedResults.Ok($"待办事项 (ID: {id}) 已成功删除。");
//});
//// DELETE /users/{id} - 删除指定的用户
//app.MapDelete("/users/{id}", async (int id, AppDbContext dbContext) =>
//{
// var userToDelete = await dbContext.Users.FindAsync(id);
// if (userToDelete is null) return Results.NotFound("用户不存在");
// {
// dbContext.Users.Remove(userToDelete);
// await dbContext.SaveChangesAsync(); // 保存更改到数据库
// return TypedResults.Ok("用户已成功删除");
// }
//});
// 运行应用程式
app.Run();

View File

@@ -5,7 +5,7 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5071",
"applicationUrl": "http://localhost:5562",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
@@ -14,7 +14,7 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7256;http://localhost:5071",
"applicationUrl": "https://localhost:7256;http://localhost:5562",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}

View File

@@ -7,11 +7,22 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.9">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.6" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" />
</ItemGroup>
<ItemGroup>
<None Update="ecc-certificate.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ActiveDebugProfile>https</ActiveDebugProfile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>

1
SimpleTodoApiWithPg.http Normal file
View File

@@ -0,0 +1 @@


207
UserService/UserService.cs Normal file
View File

@@ -0,0 +1,207 @@
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using SimpleTodoApiWithPg.Data;
using SimpleTodoApiWithPg.Models;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace SimpleTodoApiWithPg.UserService
{
// Services/UserService.cs
public class UserServices
{
private readonly AppDbContext _dbContext;
private readonly ILogger<UserServices> _logger; // 在服务构造函数中注入
private readonly IConfiguration _configuration;
public UserServices(AppDbContext dbContext, IConfiguration configuration, ILogger<UserServices> logger)
{
_dbContext = dbContext;
_logger = logger;
_configuration = configuration;
}
//前更新用户接口,暂时未使用
public async Task<Results<Ok<User>, BadRequest<string>>> PatchUserAsync(User user)
{
_logger.LogInformation("Attempting to patch user in UserService: {Username}", user.Username);
var existingUser = await _dbContext.Users.FirstOrDefaultAsync(u => u.Username == user.Username);
if (existingUser == null)
{
_logger.LogWarning("User '{Username}' not found during patch.", user.Username);
return TypedResults.BadRequest("用户名不存在,登录失败!。");
}
if (!BCrypt.Net.BCrypt.Verify(user.PasswordHash, existingUser.PasswordHash, true))
{
_logger.LogWarning("Incorrect password for user '{Username}' during patch.", user.Username);
return TypedResults.BadRequest("密码错误,请重新输入。");
}
// 假设这里执行更新逻辑
// existingUser.SomeProperty = user.SomeProperty;
// await _dbContext.SaveChangesAsync();
_logger.LogInformation("User '{Username}' patched successfully.", user.Username);
return TypedResults.Ok(existingUser);
}
//获取所有用户接口
public async Task<Results<Ok<List<User>>, BadRequest<string>>> GetUsersAsync()
{
var users = await _dbContext.Users.ToListAsync();
return TypedResults.Ok(users);
}
//根据id获取对应用户接口
public async Task<Results<Ok<User>, NotFound<string>>> GetoneUserAsync(Guid id)
{
var user = await _dbContext.Users.FindAsync(id);
if (user == null) { return TypedResults.NotFound($"要查询的id:{id}不存在"); }
return TypedResults.Ok(user);
}
//用户注册接口
public async Task<ApiResponse<RegisterResponse>> RegisterAsync(RegisterRequest request)
{
var exuser = await _dbContext.Users.AnyAsync(u => u.Username == request.Username);
if (exuser) { return ApiResponse.Fail<RegisterResponse>($"用户名:{request.Username}已存在,注册失败!", 400); };
//if (request.Username.Length <5 || request.Email.Length < 5 ) { return ApiResponse.Fail<RegisterResponse>($"用户名或邮箱不符合规范,注册失败!", 400);};
var password = RandomNumberGenerator.GetString("0123456789",15);
var user = new User();
user.Username = request.Username;
user.Email = request.Email;
user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(password, 10, true);
_dbContext.Users.Add(user);
await _dbContext.SaveChangesAsync();
return ApiResponse.Ok<RegisterResponse>(new RegisterResponse
{
Username = user.Username,
Email = user.Email,
Password = password,
UserId = user.Id
});
}
//更新用户接口
public async Task<Results<Ok<User>, NotFound<string>>> UpdateUserAsync(int id, UpdateUserRequest updateUser)
{
var existingUser = await _dbContext.Users.FindAsync(id);
if (existingUser == null) { return TypedResults.NotFound($"要更新的用户id:{id}不存在!"); };
if (updateUser.Username != null)
{
existingUser.Username = updateUser.Username;
}
if (!string.IsNullOrEmpty(updateUser.NewPassword))
{
existingUser.PasswordHash = BCrypt.Net.BCrypt.HashPassword(updateUser.NewPassword,10,true);
}
if (updateUser.Email != null)
{
existingUser.Email = updateUser.Email;
}
await _dbContext.SaveChangesAsync();
return TypedResults.Ok(existingUser);
}
//删除指定用户接口
public async Task<Results<Ok<string>, NotFound<string>>> DeleteUserAsync(Guid id)
{
var existingUser = await _dbContext.Users.FindAsync(id);
if (existingUser == null)
{
return TypedResults.NotFound($"指定要删除的用户:{id}不存在!");
}
_dbContext.Users.Remove(existingUser);
await _dbContext.SaveChangesAsync();
return TypedResults.Ok($"指定的用户:{existingUser.Username}删除成功!");
}
//登录认证接口
public async Task<ApiResponse<AuthResponse>> LoginAuthAsync(LoginRequest loginRequest)
{
var existingUser = await _dbContext.Users.FirstOrDefaultAsync(u => u.Username == loginRequest.Username);
if (existingUser == null || !BCrypt.Net.BCrypt.Verify(loginRequest.Password, existingUser.PasswordHash, true))
{
_logger.LogError("用户登录失败!{request}"," ---用户名: "+loginRequest.Username+" ---密码: "+loginRequest.Password);
return ApiResponse.Fail<AuthResponse>("用户名或密码错误!",400);
}
// 1. 生成 JWT (Access Token)
var accessTokenExpiration = DateTime.UtcNow.AddMinutes(1); // 访问令牌有效期15分钟
var accessToken = GenerateJwtToken(existingUser, accessTokenExpiration);
// 2. 生成刷新令牌
var refreshToken = GenerateRefreshToken();
refreshToken.UserId = existingUser.Id;
await _dbContext.RefreshTokens.AddAsync(refreshToken);
// (可选但推荐) 清理该用户旧的、无效的刷新令牌
var oldRefreshTokens = await _dbContext.RefreshTokens
.Where(rt => rt.UserId == existingUser.Id && (rt.Revoked != null || rt.Expires <= DateTime.UtcNow))
.ToListAsync();
_dbContext.RefreshTokens.RemoveRange(oldRefreshTokens);
await _dbContext.SaveChangesAsync();
// 3. 返回令牌对
return ApiResponse.Ok(new AuthResponse
{
AccessToken = accessToken,
RefreshToken = refreshToken.Token,
AccessTokenExpiration = accessTokenExpiration
});
}
//创建令牌接口
public string GenerateJwtToken(User user, DateTime expires)
{
// 加载证书以获取私钥进行签名
var certPath = _configuration["Jwt:CertificatePath"]!;
var certPassword = _configuration["Jwt:CertificatePassword"]!;
var certificate = X509CertificateLoader.LoadPkcs12FromFile(certPath, certPassword,X509KeyStorageFlags.EphemeralKeySet);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Username),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString())
};
var token = new JwtSecurityToken(
issuer: _configuration["Jwt:Issuer"],
audience: _configuration["Jwt:Audience"],
claims: claims,
expires: expires,
// 使用证书的私钥通过 ECDSA-SHA256 算法进行签名
signingCredentials: new SigningCredentials(new ECDsaSecurityKey(certificate.GetECDsaPrivateKey()!), SecurityAlgorithms.EcdsaSha256)
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
//创建刷新令牌接口
public RefreshToken GenerateRefreshToken()
{
var randomNumber = new byte[64];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomNumber);
return new RefreshToken
{
Token = Convert.ToBase64String(randomNumber),
Expires = DateTime.UtcNow.AddDays(1), // 刷新令牌有效期7天
Created = DateTime.UtcNow
};
}
}
}

View File

@@ -0,0 +1,18 @@
using FluentValidation;
using SimpleTodoApiWithPg.Models;
public class RegisterRequestValidator : AbstractValidator<RegisterRequest>
{
public RegisterRequestValidator()
{
RuleFor(x => x.Username)
.NotEmpty().WithMessage("用户名是必填的。")
.Length(3, 20).WithMessage("用户名长度必须在 {MinLength} 到 {MaxLength} 之间。");
RuleFor(x => x.Email)
.NotEmpty().WithMessage("邮箱是必填的。")
.EmailAddress().WithMessage("请输入有效的邮箱地址。");
}
}

View File

@@ -7,6 +7,6 @@
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Port=5555;Database=aspdb;Username=postgres;Password=123456"
"DefaultConnection": "Host=localhost;Port=5432;Database=aspnetcoredb;Username=aspnetcoredb;Password=2rRN26JTrFp4edGF"
}
}

View File

@@ -5,5 +5,11 @@
"Microsoft.AspNetCore": "Warning"
}
},
"jwt": {
"Issuer": "baidu.com",
"Audience": "baidu.com",
"CertificatePath": "ecc-certificate.pfx", // 证书文件名 (相对于应用根目录)
"CertificatePassword": "UpRTXjaHdJaPCAjgjTTt" // 您在生成证书时设置的密码
},
"AllowedHosts": "*"
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -8,13 +8,46 @@
".NETCoreApp,Version=v9.0": {
"SimpleTodoApiWithPg/1.0.0": {
"dependencies": {
"BCrypt.Net-Next": "4.0.3",
"FluentValidation.DependencyInjectionExtensions": "12.0.0",
"Microsoft.AspNetCore.Authentication.JwtBearer": "9.0.9",
"Microsoft.EntityFrameworkCore.Design": "9.0.9",
"Npgsql.EntityFrameworkCore.PostgreSQL": "9.0.4"
"Npgsql.EntityFrameworkCore.PostgreSQL": "9.0.4",
"Swashbuckle.AspNetCore": "9.0.6",
"System.IdentityModel.Tokens.Jwt": "8.14.0"
},
"runtime": {
"SimpleTodoApiWithPg.dll": {}
}
},
"BCrypt.Net-Next/4.0.3": {
"runtime": {
"lib/net6.0/BCrypt.Net-Next.dll": {
"assemblyVersion": "4.0.3.0",
"fileVersion": "4.0.3.0"
}
}
},
"FluentValidation/12.0.0": {
"runtime": {
"lib/net8.0/FluentValidation.dll": {
"assemblyVersion": "12.0.0.0",
"fileVersion": "12.0.0.0"
}
}
},
"FluentValidation.DependencyInjectionExtensions/12.0.0": {
"dependencies": {
"FluentValidation": "12.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9"
},
"runtime": {
"lib/net8.0/FluentValidation.DependencyInjectionExtensions.dll": {
"assemblyVersion": "12.0.0.0",
"fileVersion": "12.0.0.0"
}
}
},
"Humanizer.Core/2.14.1": {
"runtime": {
"lib/net6.0/Humanizer.dll": {
@@ -23,6 +56,17 @@
}
}
},
"Microsoft.AspNetCore.Authentication.JwtBearer/9.0.9": {
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "8.0.1"
},
"runtime": {
"lib/net9.0/Microsoft.AspNetCore.Authentication.JwtBearer.dll": {
"assemblyVersion": "9.0.9.0",
"fileVersion": "9.0.925.42003"
}
}
},
"Microsoft.Bcl.AsyncInterfaces/7.0.0": {
"runtime": {
"lib/netstandard2.1/Microsoft.Bcl.AsyncInterfaces.dll": {
@@ -379,6 +423,7 @@
}
}
},
"Microsoft.Extensions.ApiDescription.Server/9.0.0": {},
"Microsoft.Extensions.Caching.Abstractions/9.0.9": {
"dependencies": {
"Microsoft.Extensions.Primitives": "9.0.9"
@@ -487,6 +532,79 @@
}
}
},
"Microsoft.IdentityModel.Abstractions/8.14.0": {
"runtime": {
"lib/net9.0/Microsoft.IdentityModel.Abstractions.dll": {
"assemblyVersion": "8.14.0.0",
"fileVersion": "8.14.0.60815"
}
}
},
"Microsoft.IdentityModel.JsonWebTokens/8.14.0": {
"dependencies": {
"Microsoft.IdentityModel.Tokens": "8.14.0"
},
"runtime": {
"lib/net9.0/Microsoft.IdentityModel.JsonWebTokens.dll": {
"assemblyVersion": "8.14.0.0",
"fileVersion": "8.14.0.60815"
}
}
},
"Microsoft.IdentityModel.Logging/8.14.0": {
"dependencies": {
"Microsoft.IdentityModel.Abstractions": "8.14.0"
},
"runtime": {
"lib/net9.0/Microsoft.IdentityModel.Logging.dll": {
"assemblyVersion": "8.14.0.0",
"fileVersion": "8.14.0.60815"
}
}
},
"Microsoft.IdentityModel.Protocols/8.0.1": {
"dependencies": {
"Microsoft.IdentityModel.Tokens": "8.14.0"
},
"runtime": {
"lib/net9.0/Microsoft.IdentityModel.Protocols.dll": {
"assemblyVersion": "8.0.1.0",
"fileVersion": "8.0.1.50722"
}
}
},
"Microsoft.IdentityModel.Protocols.OpenIdConnect/8.0.1": {
"dependencies": {
"Microsoft.IdentityModel.Protocols": "8.0.1",
"System.IdentityModel.Tokens.Jwt": "8.14.0"
},
"runtime": {
"lib/net9.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll": {
"assemblyVersion": "8.0.1.0",
"fileVersion": "8.0.1.50722"
}
}
},
"Microsoft.IdentityModel.Tokens/8.14.0": {
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "9.0.9",
"Microsoft.IdentityModel.Logging": "8.14.0"
},
"runtime": {
"lib/net9.0/Microsoft.IdentityModel.Tokens.dll": {
"assemblyVersion": "8.14.0.0",
"fileVersion": "8.14.0.60815"
}
}
},
"Microsoft.OpenApi/1.6.25": {
"runtime": {
"lib/netstandard2.0/Microsoft.OpenApi.dll": {
"assemblyVersion": "1.6.25.0",
"fileVersion": "1.6.25.0"
}
}
},
"Mono.TextTemplating/3.0.0": {
"dependencies": {
"System.CodeDom": "6.0.0"
@@ -522,6 +640,44 @@
}
}
},
"Swashbuckle.AspNetCore/9.0.6": {
"dependencies": {
"Microsoft.Extensions.ApiDescription.Server": "9.0.0",
"Swashbuckle.AspNetCore.Swagger": "9.0.6",
"Swashbuckle.AspNetCore.SwaggerGen": "9.0.6",
"Swashbuckle.AspNetCore.SwaggerUI": "9.0.6"
}
},
"Swashbuckle.AspNetCore.Swagger/9.0.6": {
"dependencies": {
"Microsoft.OpenApi": "1.6.25"
},
"runtime": {
"lib/net9.0/Swashbuckle.AspNetCore.Swagger.dll": {
"assemblyVersion": "9.0.6.0",
"fileVersion": "9.0.6.1840"
}
}
},
"Swashbuckle.AspNetCore.SwaggerGen/9.0.6": {
"dependencies": {
"Swashbuckle.AspNetCore.Swagger": "9.0.6"
},
"runtime": {
"lib/net9.0/Swashbuckle.AspNetCore.SwaggerGen.dll": {
"assemblyVersion": "9.0.6.0",
"fileVersion": "9.0.6.1840"
}
}
},
"Swashbuckle.AspNetCore.SwaggerUI/9.0.6": {
"runtime": {
"lib/net9.0/Swashbuckle.AspNetCore.SwaggerUI.dll": {
"assemblyVersion": "9.0.6.0",
"fileVersion": "9.0.6.1840"
}
}
},
"System.CodeDom/6.0.0": {
"runtime": {
"lib/net6.0/System.CodeDom.dll": {
@@ -591,6 +747,18 @@
}
}
},
"System.IdentityModel.Tokens.Jwt/8.14.0": {
"dependencies": {
"Microsoft.IdentityModel.JsonWebTokens": "8.14.0",
"Microsoft.IdentityModel.Tokens": "8.14.0"
},
"runtime": {
"lib/net9.0/System.IdentityModel.Tokens.Jwt.dll": {
"assemblyVersion": "8.14.0.0",
"fileVersion": "8.14.0.60815"
}
}
},
"System.IO.Pipelines/7.0.0": {},
"System.Reflection.Metadata/7.0.0": {
"dependencies": {
@@ -615,6 +783,27 @@
"serviceable": false,
"sha512": ""
},
"BCrypt.Net-Next/4.0.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-W+U9WvmZQgi5cX6FS5GDtDoPzUCV4LkBLkywq/kRZhuDwcbavOzcDAr3LXJFqHUi952Yj3LEYoWW0jbEUQChsA==",
"path": "bcrypt.net-next/4.0.3",
"hashPath": "bcrypt.net-next.4.0.3.nupkg.sha512"
},
"FluentValidation/12.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-8NVLxtMUXynRHJIX3Hn1ACovaqZIJASufXIIFkD0EUbcd5PmMsL1xUD5h548gCezJ5BzlITaR9CAMrGe29aWpA==",
"path": "fluentvalidation/12.0.0",
"hashPath": "fluentvalidation.12.0.0.nupkg.sha512"
},
"FluentValidation.DependencyInjectionExtensions/12.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-B28fBRL1UjhGsBC8fwV6YBZosh+SiU1FxdD7l7p5dGPgRlVI7UnM+Lgzmg+unZtV1Zxzpaw96UY2MYfMaAd8cg==",
"path": "fluentvalidation.dependencyinjectionextensions/12.0.0",
"hashPath": "fluentvalidation.dependencyinjectionextensions.12.0.0.nupkg.sha512"
},
"Humanizer.Core/2.14.1": {
"type": "package",
"serviceable": true,
@@ -622,6 +811,13 @@
"path": "humanizer.core/2.14.1",
"hashPath": "humanizer.core.2.14.1.nupkg.sha512"
},
"Microsoft.AspNetCore.Authentication.JwtBearer/9.0.9": {
"type": "package",
"serviceable": true,
"sha512": "sha512-U5gW2DS/yAE9X0Ko63/O2lNApAzI/jhx4IT1Th6W0RShKv6XAVVgLGN3zqnmcd6DtAnp5FYs+4HZrxsTl0anLA==",
"path": "microsoft.aspnetcore.authentication.jwtbearer/9.0.9",
"hashPath": "microsoft.aspnetcore.authentication.jwtbearer.9.0.9.nupkg.sha512"
},
"Microsoft.Bcl.AsyncInterfaces/7.0.0": {
"type": "package",
"serviceable": true,
@@ -720,6 +916,13 @@
"path": "microsoft.entityframeworkcore.relational/9.0.9",
"hashPath": "microsoft.entityframeworkcore.relational.9.0.9.nupkg.sha512"
},
"Microsoft.Extensions.ApiDescription.Server/9.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-1Kzzf7pRey40VaUkHN9/uWxrKVkLu2AQjt+GVeeKLLpiEHAJ1xZRsLSh4ZZYEnyS7Kt2OBOPmsXNdU+wbcOl5w==",
"path": "microsoft.extensions.apidescription.server/9.0.0",
"hashPath": "microsoft.extensions.apidescription.server.9.0.0.nupkg.sha512"
},
"Microsoft.Extensions.Caching.Abstractions/9.0.9": {
"type": "package",
"serviceable": true,
@@ -790,6 +993,55 @@
"path": "microsoft.extensions.primitives/9.0.9",
"hashPath": "microsoft.extensions.primitives.9.0.9.nupkg.sha512"
},
"Microsoft.IdentityModel.Abstractions/8.14.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-iwbCpSjD3ehfTwBhtSNEtKPK0ICun6ov7Ibx6ISNA9bfwIyzI2Siwyi9eJFCJBwxowK9xcA1mj+jBWiigeqgcQ==",
"path": "microsoft.identitymodel.abstractions/8.14.0",
"hashPath": "microsoft.identitymodel.abstractions.8.14.0.nupkg.sha512"
},
"Microsoft.IdentityModel.JsonWebTokens/8.14.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-4jOpiA4THdtpLyMdAb24dtj7+6GmvhOhxf5XHLYWmPKF8ApEnApal1UnJsKO4HxUWRXDA6C4WQVfYyqsRhpNpQ==",
"path": "microsoft.identitymodel.jsonwebtokens/8.14.0",
"hashPath": "microsoft.identitymodel.jsonwebtokens.8.14.0.nupkg.sha512"
},
"Microsoft.IdentityModel.Logging/8.14.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-eqqnemdW38CKZEHS6diA50BV94QICozDZEvSrsvN3SJXUFwVB9gy+/oz76gldP7nZliA16IglXjXTCTdmU/Ejg==",
"path": "microsoft.identitymodel.logging/8.14.0",
"hashPath": "microsoft.identitymodel.logging.8.14.0.nupkg.sha512"
},
"Microsoft.IdentityModel.Protocols/8.0.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-uA2vpKqU3I2mBBEaeJAWPTjT9v1TZrGWKdgK6G5qJd03CLx83kdiqO9cmiK8/n1erkHzFBwU/RphP83aAe3i3g==",
"path": "microsoft.identitymodel.protocols/8.0.1",
"hashPath": "microsoft.identitymodel.protocols.8.0.1.nupkg.sha512"
},
"Microsoft.IdentityModel.Protocols.OpenIdConnect/8.0.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-AQDbfpL+yzuuGhO/mQhKNsp44pm5Jv8/BI4KiFXR7beVGZoSH35zMV3PrmcfvSTsyI6qrcR898NzUauD6SRigg==",
"path": "microsoft.identitymodel.protocols.openidconnect/8.0.1",
"hashPath": "microsoft.identitymodel.protocols.openidconnect.8.0.1.nupkg.sha512"
},
"Microsoft.IdentityModel.Tokens/8.14.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-lKIZiBiGd36k02TCdMHp1KlNWisyIvQxcYJvIkz7P4gSQ9zi8dgh6S5Grj8NNG7HWYIPfQymGyoZ6JB5d1Lo1g==",
"path": "microsoft.identitymodel.tokens/8.14.0",
"hashPath": "microsoft.identitymodel.tokens.8.14.0.nupkg.sha512"
},
"Microsoft.OpenApi/1.6.25": {
"type": "package",
"serviceable": true,
"sha512": "sha512-ZahSqNGtNV7N0JBYS/IYXPkLVexL/AZFxo6pqxv6A7Uli7Q7zfitNjkaqIcsV73Ukzxi4IlJdyDgcQiMXiH8cw==",
"path": "microsoft.openapi/1.6.25",
"hashPath": "microsoft.openapi.1.6.25.nupkg.sha512"
},
"Mono.TextTemplating/3.0.0": {
"type": "package",
"serviceable": true,
@@ -811,6 +1063,34 @@
"path": "npgsql.entityframeworkcore.postgresql/9.0.4",
"hashPath": "npgsql.entityframeworkcore.postgresql.9.0.4.nupkg.sha512"
},
"Swashbuckle.AspNetCore/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-q/UfEAgrk6qQyjHXgsW9ILw0YZLfmPtWUY4wYijliX6supozC+TkzU0G6FTnn/dPYxnChjM8g8lHjWHF6VKy+A==",
"path": "swashbuckle.aspnetcore/9.0.6",
"hashPath": "swashbuckle.aspnetcore.9.0.6.nupkg.sha512"
},
"Swashbuckle.AspNetCore.Swagger/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-Bgyc8rWRAYwDrzjVHGbavvNE38G1Dfgf1McHYm+WUr4TxkvEAXv8F8B1z3Kmz4BkDCKv9A/1COa2t7+Ri5+pLg==",
"path": "swashbuckle.aspnetcore.swagger/9.0.6",
"hashPath": "swashbuckle.aspnetcore.swagger.9.0.6.nupkg.sha512"
},
"Swashbuckle.AspNetCore.SwaggerGen/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-yYrDs5qpIa4UXP+a02X0ZLQs6HSd1C8t6hF6J1fnxoawi3PslJg1yUpLBS89HCbrDACzmwEGG25il+8aa0zdnw==",
"path": "swashbuckle.aspnetcore.swaggergen/9.0.6",
"hashPath": "swashbuckle.aspnetcore.swaggergen.9.0.6.nupkg.sha512"
},
"Swashbuckle.AspNetCore.SwaggerUI/9.0.6": {
"type": "package",
"serviceable": true,
"sha512": "sha512-WGsw/Yop9b16miq8TQd4THxuEgkP5cH3+DX93BrX9m0OdPcKNtg2nNm77WQSAsA+Se+M0bTiu8bUyrruRSeS5g==",
"path": "swashbuckle.aspnetcore.swaggerui/9.0.6",
"hashPath": "swashbuckle.aspnetcore.swaggerui.9.0.6.nupkg.sha512"
},
"System.CodeDom/6.0.0": {
"type": "package",
"serviceable": true,
@@ -867,6 +1147,13 @@
"path": "system.composition.typedparts/7.0.0",
"hashPath": "system.composition.typedparts.7.0.0.nupkg.sha512"
},
"System.IdentityModel.Tokens.Jwt/8.14.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-EYGgN/S+HK7S6F3GaaPLFAfK0UzMrkXFyWCvXpQWFYmZln3dqtbyIO7VuTM/iIIPMzkelg8ZLlBPvMhxj6nOAA==",
"path": "system.identitymodel.tokens.jwt/8.14.0",
"hashPath": "system.identitymodel.tokens.jwt.8.14.0.nupkg.sha512"
},
"System.IO.Pipelines/7.0.0": {
"type": "package",
"serviceable": true,

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -5,5 +5,11 @@
"Microsoft.AspNetCore": "Warning"
}
},
"jwt": {
"Issuer": "baidu.com",
"Audience": "baidu.com",
"CertificatePath": "ecc-certificate.pfx", // 证书文件名 (相对于应用根目录)
"CertificatePassword": "UpRTXjaHdJaPCAjgjTTt" // 您在生成证书时设置的密码
},
"AllowedHosts": "*"
}

Binary file not shown.

View File

@@ -0,0 +1,6 @@
{
"sdk": {
"version": "9.0.203",
"rollForward": "latestFeature"
}
}

BIN
ecc-certificate.pfx Normal file

Binary file not shown.

6
global.json Normal file
View File

@@ -0,0 +1,6 @@
{
"sdk": {
"version": "9.0.203",
"rollForward": "latestFeature"
}
}

View File

@@ -0,0 +1,232 @@
[
{
"ContainingType": "Program\u002B\u003C\u003Ec",
"Method": "\u003C\u003CMain\u003E$\u003Eb__0_4",
"RelativePath": "",
"HttpMethod": "GET",
"IsController": false,
"Order": 0,
"Parameters": [],
"ReturnTypes": [
{
"Type": "System.String",
"MediaTypes": [
"text/plain"
],
"StatusCode": 200
}
]
},
{
"ContainingType": "SimpleTodoApiWithPg.Endpoints.UserEndpoints\u002B\u003C\u003Ec",
"Method": "\u003CMapUserEndpoints\u003Eb__0_5",
"RelativePath": "api/auth/",
"HttpMethod": "POST",
"IsController": false,
"Order": 0,
"Parameters": [
{
"Name": "loginRequest",
"Type": "SimpleTodoApiWithPg.Models.LoginRequest",
"IsRequired": true
}
],
"ReturnTypes": [
{
"Type": "System.Void",
"MediaTypes": [],
"StatusCode": 200
}
],
"Tags": [
"\u767B\u5F55\u8BA4\u8BC1\u6388\u6743\u63A5\u53E3!"
]
},
{
"ContainingType": "SimpleTodoApiWithPg.Endpoints.UserEndpoints\u002B\u003C\u003Ec",
"Method": "\u003CMapUserEndpoints\u003Eb__0_6",
"RelativePath": "api/auth/refresh-token",
"HttpMethod": "POST",
"IsController": false,
"Order": 0,
"Parameters": [
{
"Name": "refreshToken",
"Type": "SimpleTodoApiWithPg.Models.RefreshTokenRequest",
"IsRequired": true
}
],
"ReturnTypes": [
{
"Type": "System.Void",
"MediaTypes": [],
"StatusCode": 200
}
],
"Tags": [
"\u5237\u65B0\u4EE4\u724C\u63A5\u53E3"
]
},
{
"ContainingType": "SimpleTodoApiWithPg.Endpoints.UserEndpoints\u002B\u003C\u003Ec",
"Method": "\u003CMapUserEndpoints\u003Eb__0_0",
"RelativePath": "users/",
"HttpMethod": "GET",
"IsController": false,
"Order": 0,
"Parameters": [],
"ReturnTypes": [
{
"Type": "System.Collections.Generic.List\u00601[[SimpleTodoApiWithPg.Models.User, SimpleTodoApiWithPg, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]",
"MediaTypes": [
"application/json"
],
"StatusCode": 200
},
{
"Type": "System.String",
"MediaTypes": [
"application/json"
],
"StatusCode": 400
}
],
"Tags": [
"\u83B7\u53D6\u6240\u6709\u7528\u6237"
]
},
{
"ContainingType": "SimpleTodoApiWithPg.Endpoints.UserEndpoints\u002B\u003C\u003Ec",
"Method": "\u003CMapUserEndpoints\u003Eb__0_2",
"RelativePath": "users/",
"HttpMethod": "POST",
"IsController": false,
"Order": 0,
"Parameters": [
{
"Name": "request",
"Type": "SimpleTodoApiWithPg.Models.RegisterRequest",
"IsRequired": true
}
],
"ReturnTypes": [
{
"Type": "Microsoft.AspNetCore.Http.HttpValidationProblemDetails",
"MediaTypes": [
"application/problem\u002Bjson"
],
"StatusCode": 400
}
],
"Tags": [
"\u7528\u6237\u6CE8\u518C\u63A5\u53E3"
]
},
{
"ContainingType": "SimpleTodoApiWithPg.Endpoints.UserEndpoints\u002B\u003C\u003Ec",
"Method": "\u003CMapUserEndpoints\u003Eb__0_1",
"RelativePath": "users/{id}",
"HttpMethod": "GET",
"IsController": false,
"Order": 0,
"Parameters": [
{
"Name": "id",
"Type": "System.Guid",
"IsRequired": true
}
],
"ReturnTypes": [
{
"Type": "SimpleTodoApiWithPg.Models.User",
"MediaTypes": [
"application/json"
],
"StatusCode": 200
},
{
"Type": "System.String",
"MediaTypes": [
"application/json"
],
"StatusCode": 404
}
],
"Tags": [
"\u6839\u636Eid\u83B7\u53D6\u5BF9\u5E94\u7684\u7528\u6237\u4FE1\u606F"
]
},
{
"ContainingType": "SimpleTodoApiWithPg.Endpoints.UserEndpoints\u002B\u003C\u003Ec",
"Method": "\u003CMapUserEndpoints\u003Eb__0_3",
"RelativePath": "users/{id}",
"HttpMethod": "PATCH",
"IsController": false,
"Order": 0,
"Parameters": [
{
"Name": "id",
"Type": "System.Int32",
"IsRequired": true
},
{
"Name": "updateUser",
"Type": "SimpleTodoApiWithPg.Models.UpdateUserRequest",
"IsRequired": true
}
],
"ReturnTypes": [
{
"Type": "SimpleTodoApiWithPg.Models.User",
"MediaTypes": [
"application/json"
],
"StatusCode": 200
},
{
"Type": "System.String",
"MediaTypes": [
"application/json"
],
"StatusCode": 404
}
],
"Tags": [
"\u7528\u6237\u4FE1\u606F\u66F4\u65B0\u63A5\u53E3"
]
},
{
"ContainingType": "SimpleTodoApiWithPg.Endpoints.UserEndpoints\u002B\u003C\u003Ec",
"Method": "\u003CMapUserEndpoints\u003Eb__0_4",
"RelativePath": "users/{id}",
"HttpMethod": "DELETE",
"IsController": false,
"Order": 0,
"Parameters": [
{
"Name": "id",
"Type": "System.Guid",
"IsRequired": true
}
],
"ReturnTypes": [
{
"Type": "System.String",
"MediaTypes": [
"application/json"
],
"StatusCode": 200
},
{
"Type": "System.String",
"MediaTypes": [
"application/json"
],
"StatusCode": 404
}
],
"Tags": [
"\u5220\u9664\u7528\u6237\u63A5\u53E3"
]
}
]

View File

@@ -0,0 +1 @@
SimpleTodoApiWithPg.json

View File

@@ -0,0 +1,403 @@
{
"openapi": "3.0.4",
"info": {
"title": "SimpleTodoApiWithPg",
"version": "1.0"
},
"paths": {
"/api/auth": {
"post": {
"tags": [
"登录认证授权接口!"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/users/{id}": {
"get": {
"tags": [
"根据id获取对应的用户信息"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
},
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
},
"delete": {
"tags": [
"删除用户接口"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
},
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
},
"patch": {
"tags": [
"用户信息更新接口"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateUserRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
},
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/users": {
"get": {
"tags": [
"获取所有用户"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/User"
}
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
}
}
}
},
"post": {
"tags": [
"用户注册接口"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RegisterRequest"
}
}
},
"required": true
},
"responses": {
"400": {
"description": "Bad Request",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/HttpValidationProblemDetails"
}
}
}
}
}
}
},
"/api/auth/refresh-token": {
"post": {
"tags": [
"刷新令牌接口"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RefreshTokenRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/": {
"get": {
"tags": [
"SimpleTodoApiWithPg"
],
"responses": {
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"HttpValidationProblemDetails": {
"type": "object",
"properties": {
"type": {
"type": "string",
"nullable": true
},
"title": {
"type": "string",
"nullable": true
},
"status": {
"type": "integer",
"format": "int32",
"nullable": true
},
"detail": {
"type": "string",
"nullable": true
},
"instance": {
"type": "string",
"nullable": true
},
"errors": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
},
"nullable": true
}
},
"additionalProperties": { }
},
"LoginRequest": {
"required": [
"password",
"username"
],
"type": "object",
"properties": {
"username": {
"maxLength": 50,
"minLength": 1,
"type": "string"
},
"password": {
"maxLength": 50,
"minLength": 1,
"type": "string"
}
},
"additionalProperties": false
},
"RefreshTokenRequest": {
"type": "object",
"properties": {
"refreshToken": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"RegisterRequest": {
"required": [
"email",
"username"
],
"type": "object",
"properties": {
"username": {
"type": "string",
"nullable": true
},
"email": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"UpdateUserRequest": {
"type": "object",
"properties": {
"username": {
"maxLength": 50,
"type": "string",
"nullable": true
},
"email": {
"maxLength": 100,
"type": "string",
"format": "email",
"nullable": true
},
"newPassword": {
"maxLength": 50,
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"User": {
"required": [
"email",
"passwordHash",
"username"
],
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"username": {
"maxLength": 50,
"minLength": 1,
"type": "string"
},
"email": {
"maxLength": 50,
"minLength": 5,
"type": "string",
"format": "email"
},
"passwordHash": {
"maxLength": 100,
"minLength": 1,
"type": "string"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
}
}
}
}

View File

@@ -1,9 +1,10 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
@@ -13,7 +14,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("SimpleTodoApiWithPg")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+8ab52738c086cb1a3aa894122cfb801985cf1b9b")]
[assembly: System.Reflection.AssemblyProductAttribute("SimpleTodoApiWithPg")]
[assembly: System.Reflection.AssemblyTitleAttribute("SimpleTodoApiWithPg")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@@ -1 +1 @@
e0a450d7f7ecf2071ba072fc6f6c15983dfaa6fea6288c9b6a218625a530e48f
bc56e06accd466e2627943e8dc62f6bb1f983bfa111ed39fecd5b88f6b089ded

View File

@@ -0,0 +1,17 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartAttribute("Swashbuckle.AspNetCore.SwaggerGen")]
// 由 MSBuild WriteCodeFragment 类生成。

View File

@@ -1 +1 @@
2bce65f69d2c68eb81bc3d1d692a255f9f87885472ee7fbdc1d07c93d722e3a8
0effd9d609e1d00c69ee989d814ac6a47d1f1ea54efb5cc3ae49700f1991fab2

View File

@@ -1,12 +1,22 @@
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.csproj.AssemblyReference.cache
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.GeneratedMSBuildEditorConfig.editorconfig
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.AssemblyInfoInputs.cache
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.AssemblyInfo.cs
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.csproj.CoreCompileInputs.cache
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.MvcApplicationPartsAssemblyInfo.cache
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\appsettings.Development.json
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\appsettings.json
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\global.json
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\SimpleTodoApiWithPg.staticwebassets.endpoints.json
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\ecc-certificate.pfx
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\SimpleTodoApiWithPg.exe
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\SimpleTodoApiWithPg.deps.json
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\SimpleTodoApiWithPg.runtimeconfig.json
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\SimpleTodoApiWithPg.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\SimpleTodoApiWithPg.pdb
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\BCrypt.Net-Next.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Humanizer.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.AspNetCore.Authentication.JwtBearer.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.Bcl.AsyncInterfaces.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.Build.Locator.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.CodeAnalysis.dll
@@ -29,6 +39,12 @@ C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.Extensions.Logging.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.Extensions.Logging.Abstractions.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.Extensions.Options.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.Extensions.Primitives.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.IdentityModel.Abstractions.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.IdentityModel.JsonWebTokens.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.IdentityModel.Logging.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.IdentityModel.Protocols.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.IdentityModel.Tokens.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Mono.TextTemplating.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Npgsql.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Npgsql.EntityFrameworkCore.PostgreSQL.dll
@@ -38,6 +54,7 @@ C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\System.Composition.Convention.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\System.Composition.Hosting.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\System.Composition.Runtime.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\System.Composition.TypedParts.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\System.IdentityModel.Tokens.Jwt.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\System.Text.Json.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\cs\Microsoft.CodeAnalysis.resources.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\de\Microsoft.CodeAnalysis.resources.dll
@@ -104,12 +121,6 @@ C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\ru\Microsoft.CodeAnalysis.Workspace
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\tr\Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\zh-Hans\Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\zh-Hant\Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.resources.dll
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.csproj.AssemblyReference.cache
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.GeneratedMSBuildEditorConfig.editorconfig
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.AssemblyInfoInputs.cache
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.AssemblyInfo.cs
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.csproj.CoreCompileInputs.cache
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.MvcApplicationPartsAssemblyInfo.cache
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\scopedcss\bundle\SimpleTodoApiWithPg.styles.css
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\staticwebassets.build.json
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\staticwebassets.development.json
@@ -120,9 +131,17 @@ C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\staticwebassets\msbuild.build.Simpl
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\staticwebassets\msbuild.buildMultiTargeting.SimpleTodoApiWithPg.props
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\staticwebassets\msbuild.buildTransitive.SimpleTodoApiWithPg.props
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\staticwebassets.pack.json
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\staticwebassets.upToDateCheck.txt
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTo.008CF47A.Up2Date
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.dll
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\refint\SimpleTodoApiWithPg.dll
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.pdb
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.genruntimeconfig.cache
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\ref\SimpleTodoApiWithPg.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Microsoft.OpenApi.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Swashbuckle.AspNetCore.Swagger.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Swashbuckle.AspNetCore.SwaggerGen.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\Swashbuckle.AspNetCore.SwaggerUI.dll
C:\code\SimpleTodoApiWithPg\obj\Debug\net9.0\SimpleTodoApiWithPg.MvcApplicationPartsAssemblyInfo.cs
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\FluentValidation.dll
C:\code\SimpleTodoApiWithPg\bin\Debug\net9.0\FluentValidation.DependencyInjectionExtensions.dll

Binary file not shown.

View File

@@ -13,13 +13,19 @@
"packagesPath": "C:\\Users\\heiye\\.nuget\\packages\\",
"outputPath": "C:\\code\\SimpleTodoApiWithPg\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\heiye\\AppData\\Roaming\\NuGet\\NuGet.Config"
"C:\\Users\\heiye\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net9.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
@@ -44,6 +50,18 @@
"net9.0": {
"targetAlias": "net9.0",
"dependencies": {
"BCrypt.Net-Next": {
"target": "Package",
"version": "[4.0.3, )"
},
"FluentValidation.DependencyInjectionExtensions": {
"target": "Package",
"version": "[12.0.0, )"
},
"Microsoft.AspNetCore.Authentication.JwtBearer": {
"target": "Package",
"version": "[9.0.9, )"
},
"Microsoft.EntityFrameworkCore.Design": {
"include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive",
"suppressParent": "All",
@@ -53,6 +71,14 @@
"Npgsql.EntityFrameworkCore.PostgreSQL": {
"target": "Package",
"version": "[9.0.4, )"
},
"Swashbuckle.AspNetCore": {
"target": "Package",
"version": "[9.0.6, )"
},
"System.IdentityModel.Tokens.Jwt": {
"target": "Package",
"version": "[8.14.0, )"
}
},
"imports": [

View File

@@ -5,19 +5,23 @@
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\heiye\.nuget\packages\</NuGetPackageFolders>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\heiye\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.2</NuGetToolVersion>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="C:\Users\heiye\.nuget\packages\" />
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
</ItemGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)microsoft.extensions.apidescription.server\9.0.0\build\Microsoft.Extensions.ApiDescription.Server.props" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.apidescription.server\9.0.0\build\Microsoft.Extensions.ApiDescription.Server.props')" />
<Import Project="$(NuGetPackageRoot)swashbuckle.aspnetcore\9.0.6\build\Swashbuckle.AspNetCore.props" Condition="Exists('$(NuGetPackageRoot)swashbuckle.aspnetcore\9.0.6\build\Swashbuckle.AspNetCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore\9.0.9\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore\9.0.9\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.codeanalysis.analyzers\3.3.4\buildTransitive\Microsoft.CodeAnalysis.Analyzers.props" Condition="Exists('$(NuGetPackageRoot)microsoft.codeanalysis.analyzers\3.3.4\buildTransitive\Microsoft.CodeAnalysis.Analyzers.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore.design\9.0.9\build\net8.0\Microsoft.EntityFrameworkCore.Design.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore.design\9.0.9\build\net8.0\Microsoft.EntityFrameworkCore.Design.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<PkgMicrosoft_Extensions_ApiDescription_Server Condition=" '$(PkgMicrosoft_Extensions_ApiDescription_Server)' == '' ">C:\Users\heiye\.nuget\packages\microsoft.extensions.apidescription.server\9.0.0</PkgMicrosoft_Extensions_ApiDescription_Server>
<PkgMicrosoft_CodeAnalysis_Analyzers Condition=" '$(PkgMicrosoft_CodeAnalysis_Analyzers)' == '' ">C:\Users\heiye\.nuget\packages\microsoft.codeanalysis.analyzers\3.3.4</PkgMicrosoft_CodeAnalysis_Analyzers>
</PropertyGroup>
</Project>

View File

@@ -3,6 +3,7 @@
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)system.text.json\9.0.9\buildTransitive\net8.0\System.Text.Json.targets" Condition="Exists('$(NuGetPackageRoot)system.text.json\9.0.9\buildTransitive\net8.0\System.Text.Json.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\9.0.9\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\9.0.9\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.apidescription.server\9.0.0\build\Microsoft.Extensions.ApiDescription.Server.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.apidescription.server\9.0.0\build\Microsoft.Extensions.ApiDescription.Server.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\9.0.9\buildTransitive\net8.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\9.0.9\buildTransitive\net8.0\Microsoft.Extensions.Options.targets')" />
<Import Project="$(NuGetPackageRoot)mono.texttemplating\3.0.0\buildTransitive\Mono.TextTemplating.targets" Condition="Exists('$(NuGetPackageRoot)mono.texttemplating\3.0.0\buildTransitive\Mono.TextTemplating.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.codeanalysis.analyzers\3.3.4\buildTransitive\Microsoft.CodeAnalysis.Analyzers.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.codeanalysis.analyzers\3.3.4\buildTransitive\Microsoft.CodeAnalysis.Analyzers.targets')" />

View File

@@ -2,6 +2,49 @@
"version": 3,
"targets": {
"net9.0": {
"BCrypt.Net-Next/4.0.3": {
"type": "package",
"compile": {
"lib/net6.0/BCrypt.Net-Next.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net6.0/BCrypt.Net-Next.dll": {
"related": ".xml"
}
}
},
"FluentValidation/12.0.0": {
"type": "package",
"compile": {
"lib/net8.0/FluentValidation.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net8.0/FluentValidation.dll": {
"related": ".xml"
}
}
},
"FluentValidation.DependencyInjectionExtensions/12.0.0": {
"type": "package",
"dependencies": {
"FluentValidation": "12.0.0",
"Microsoft.Extensions.Dependencyinjection.Abstractions": "2.1.0"
},
"compile": {
"lib/net8.0/FluentValidation.DependencyInjectionExtensions.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net8.0/FluentValidation.DependencyInjectionExtensions.dll": {
"related": ".xml"
}
}
},
"Humanizer.Core/2.14.1": {
"type": "package",
"compile": {
@@ -15,6 +58,25 @@
}
}
},
"Microsoft.AspNetCore.Authentication.JwtBearer/9.0.9": {
"type": "package",
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "8.0.1"
},
"compile": {
"lib/net9.0/Microsoft.AspNetCore.Authentication.JwtBearer.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net9.0/Microsoft.AspNetCore.Authentication.JwtBearer.dll": {
"related": ".xml"
}
},
"frameworkReferences": [
"Microsoft.AspNetCore.App"
]
},
"Microsoft.Bcl.AsyncInterfaces/7.0.0": {
"type": "package",
"compile": {
@@ -450,6 +512,17 @@
}
}
},
"Microsoft.Extensions.ApiDescription.Server/9.0.0": {
"type": "package",
"build": {
"build/Microsoft.Extensions.ApiDescription.Server.props": {},
"build/Microsoft.Extensions.ApiDescription.Server.targets": {}
},
"buildMultiTargeting": {
"buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.props": {},
"buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.targets": {}
}
},
"Microsoft.Extensions.Caching.Abstractions/9.0.9": {
"type": "package",
"dependencies": {
@@ -638,6 +711,114 @@
"buildTransitive/net8.0/_._": {}
}
},
"Microsoft.IdentityModel.Abstractions/8.14.0": {
"type": "package",
"compile": {
"lib/net9.0/Microsoft.IdentityModel.Abstractions.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net9.0/Microsoft.IdentityModel.Abstractions.dll": {
"related": ".xml"
}
}
},
"Microsoft.IdentityModel.JsonWebTokens/8.14.0": {
"type": "package",
"dependencies": {
"Microsoft.IdentityModel.Tokens": "8.14.0"
},
"compile": {
"lib/net9.0/Microsoft.IdentityModel.JsonWebTokens.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net9.0/Microsoft.IdentityModel.JsonWebTokens.dll": {
"related": ".xml"
}
}
},
"Microsoft.IdentityModel.Logging/8.14.0": {
"type": "package",
"dependencies": {
"Microsoft.IdentityModel.Abstractions": "8.14.0"
},
"compile": {
"lib/net9.0/Microsoft.IdentityModel.Logging.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net9.0/Microsoft.IdentityModel.Logging.dll": {
"related": ".xml"
}
}
},
"Microsoft.IdentityModel.Protocols/8.0.1": {
"type": "package",
"dependencies": {
"Microsoft.IdentityModel.Tokens": "8.0.1"
},
"compile": {
"lib/net9.0/Microsoft.IdentityModel.Protocols.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net9.0/Microsoft.IdentityModel.Protocols.dll": {
"related": ".xml"
}
}
},
"Microsoft.IdentityModel.Protocols.OpenIdConnect/8.0.1": {
"type": "package",
"dependencies": {
"Microsoft.IdentityModel.Protocols": "8.0.1",
"System.IdentityModel.Tokens.Jwt": "8.0.1"
},
"compile": {
"lib/net9.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net9.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll": {
"related": ".xml"
}
}
},
"Microsoft.IdentityModel.Tokens/8.14.0": {
"type": "package",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "8.0.0",
"Microsoft.IdentityModel.Logging": "8.14.0"
},
"compile": {
"lib/net9.0/Microsoft.IdentityModel.Tokens.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net9.0/Microsoft.IdentityModel.Tokens.dll": {
"related": ".xml"
}
}
},
"Microsoft.OpenApi/1.6.25": {
"type": "package",
"compile": {
"lib/netstandard2.0/Microsoft.OpenApi.dll": {
"related": ".pdb;.xml"
}
},
"runtime": {
"lib/netstandard2.0/Microsoft.OpenApi.dll": {
"related": ".pdb;.xml"
}
}
},
"Mono.TextTemplating/3.0.0": {
"type": "package",
"dependencies": {
@@ -687,6 +868,72 @@
}
}
},
"Swashbuckle.AspNetCore/9.0.6": {
"type": "package",
"dependencies": {
"Microsoft.Extensions.ApiDescription.Server": "9.0.0",
"Swashbuckle.AspNetCore.Swagger": "9.0.6",
"Swashbuckle.AspNetCore.SwaggerGen": "9.0.6",
"Swashbuckle.AspNetCore.SwaggerUI": "9.0.6"
},
"build": {
"build/Swashbuckle.AspNetCore.props": {}
},
"buildMultiTargeting": {
"buildMultiTargeting/Swashbuckle.AspNetCore.props": {}
}
},
"Swashbuckle.AspNetCore.Swagger/9.0.6": {
"type": "package",
"dependencies": {
"Microsoft.OpenApi": "1.6.25"
},
"compile": {
"lib/net9.0/Swashbuckle.AspNetCore.Swagger.dll": {
"related": ".pdb;.xml"
}
},
"runtime": {
"lib/net9.0/Swashbuckle.AspNetCore.Swagger.dll": {
"related": ".pdb;.xml"
}
},
"frameworkReferences": [
"Microsoft.AspNetCore.App"
]
},
"Swashbuckle.AspNetCore.SwaggerGen/9.0.6": {
"type": "package",
"dependencies": {
"Swashbuckle.AspNetCore.Swagger": "9.0.6"
},
"compile": {
"lib/net9.0/Swashbuckle.AspNetCore.SwaggerGen.dll": {
"related": ".pdb;.xml"
}
},
"runtime": {
"lib/net9.0/Swashbuckle.AspNetCore.SwaggerGen.dll": {
"related": ".pdb;.xml"
}
}
},
"Swashbuckle.AspNetCore.SwaggerUI/9.0.6": {
"type": "package",
"compile": {
"lib/net9.0/Swashbuckle.AspNetCore.SwaggerUI.dll": {
"related": ".pdb;.xml"
}
},
"runtime": {
"lib/net9.0/Swashbuckle.AspNetCore.SwaggerUI.dll": {
"related": ".pdb;.xml"
}
},
"frameworkReferences": [
"Microsoft.AspNetCore.App"
]
},
"System.CodeDom/6.0.0": {
"type": "package",
"compile": {
@@ -829,6 +1076,23 @@
"buildTransitive/net6.0/_._": {}
}
},
"System.IdentityModel.Tokens.Jwt/8.14.0": {
"type": "package",
"dependencies": {
"Microsoft.IdentityModel.JsonWebTokens": "8.14.0",
"Microsoft.IdentityModel.Tokens": "8.14.0"
},
"compile": {
"lib/net9.0/System.IdentityModel.Tokens.Jwt.dll": {
"related": ".xml"
}
},
"runtime": {
"lib/net9.0/System.IdentityModel.Tokens.Jwt.dll": {
"related": ".xml"
}
}
},
"System.IO.Pipelines/7.0.0": {
"type": "package",
"compile": {
@@ -915,6 +1179,67 @@
}
},
"libraries": {
"BCrypt.Net-Next/4.0.3": {
"sha512": "W+U9WvmZQgi5cX6FS5GDtDoPzUCV4LkBLkywq/kRZhuDwcbavOzcDAr3LXJFqHUi952Yj3LEYoWW0jbEUQChsA==",
"type": "package",
"path": "bcrypt.net-next/4.0.3",
"files": [
".nupkg.metadata",
".signature.p7s",
"bcrypt.net-next.4.0.3.nupkg.sha512",
"bcrypt.net-next.nuspec",
"ico.png",
"lib/net20/BCrypt.Net-Next.dll",
"lib/net20/BCrypt.Net-Next.xml",
"lib/net35/BCrypt.Net-Next.dll",
"lib/net35/BCrypt.Net-Next.xml",
"lib/net462/BCrypt.Net-Next.dll",
"lib/net462/BCrypt.Net-Next.xml",
"lib/net472/BCrypt.Net-Next.dll",
"lib/net472/BCrypt.Net-Next.xml",
"lib/net48/BCrypt.Net-Next.dll",
"lib/net48/BCrypt.Net-Next.xml",
"lib/net5.0/BCrypt.Net-Next.dll",
"lib/net5.0/BCrypt.Net-Next.xml",
"lib/net6.0/BCrypt.Net-Next.dll",
"lib/net6.0/BCrypt.Net-Next.xml",
"lib/netstandard2.0/BCrypt.Net-Next.dll",
"lib/netstandard2.0/BCrypt.Net-Next.xml",
"lib/netstandard2.1/BCrypt.Net-Next.dll",
"lib/netstandard2.1/BCrypt.Net-Next.xml",
"readme.md"
]
},
"FluentValidation/12.0.0": {
"sha512": "8NVLxtMUXynRHJIX3Hn1ACovaqZIJASufXIIFkD0EUbcd5PmMsL1xUD5h548gCezJ5BzlITaR9CAMrGe29aWpA==",
"type": "package",
"path": "fluentvalidation/12.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"fluent-validation-icon.png",
"fluentvalidation.12.0.0.nupkg.sha512",
"fluentvalidation.nuspec",
"lib/net8.0/FluentValidation.dll",
"lib/net8.0/FluentValidation.xml"
]
},
"FluentValidation.DependencyInjectionExtensions/12.0.0": {
"sha512": "B28fBRL1UjhGsBC8fwV6YBZosh+SiU1FxdD7l7p5dGPgRlVI7UnM+Lgzmg+unZtV1Zxzpaw96UY2MYfMaAd8cg==",
"type": "package",
"path": "fluentvalidation.dependencyinjectionextensions/12.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"fluent-validation-icon.png",
"fluentvalidation.dependencyinjectionextensions.12.0.0.nupkg.sha512",
"fluentvalidation.dependencyinjectionextensions.nuspec",
"lib/net8.0/FluentValidation.DependencyInjectionExtensions.dll",
"lib/net8.0/FluentValidation.DependencyInjectionExtensions.xml"
]
},
"Humanizer.Core/2.14.1": {
"sha512": "lQKvtaTDOXnoVJ20ibTuSIOf2i0uO0MPbDhd1jm238I+U/2ZnRENj0cktKZhtchBMtCUSRQ5v4xBCUbKNmyVMw==",
"type": "package",
@@ -933,6 +1258,22 @@
"logo.png"
]
},
"Microsoft.AspNetCore.Authentication.JwtBearer/9.0.9": {
"sha512": "U5gW2DS/yAE9X0Ko63/O2lNApAzI/jhx4IT1Th6W0RShKv6XAVVgLGN3zqnmcd6DtAnp5FYs+4HZrxsTl0anLA==",
"type": "package",
"path": "microsoft.aspnetcore.authentication.jwtbearer/9.0.9",
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"PACKAGE.md",
"THIRD-PARTY-NOTICES.TXT",
"lib/net9.0/Microsoft.AspNetCore.Authentication.JwtBearer.dll",
"lib/net9.0/Microsoft.AspNetCore.Authentication.JwtBearer.xml",
"microsoft.aspnetcore.authentication.jwtbearer.9.0.9.nupkg.sha512",
"microsoft.aspnetcore.authentication.jwtbearer.nuspec"
]
},
"Microsoft.Bcl.AsyncInterfaces/7.0.0": {
"sha512": "3aeMZ1N0lJoSyzqiP03hqemtb1BijhsJADdobn/4nsMJ8V1H+CrpuduUe4hlRdx+ikBQju1VGjMD1GJ3Sk05Eg==",
"type": "package",
@@ -1991,6 +2332,263 @@
"microsoft.entityframeworkcore.relational.nuspec"
]
},
"Microsoft.Extensions.ApiDescription.Server/9.0.0": {
"sha512": "1Kzzf7pRey40VaUkHN9/uWxrKVkLu2AQjt+GVeeKLLpiEHAJ1xZRsLSh4ZZYEnyS7Kt2OBOPmsXNdU+wbcOl5w==",
"type": "package",
"path": "microsoft.extensions.apidescription.server/9.0.0",
"hasTools": true,
"files": [
".nupkg.metadata",
".signature.p7s",
"Icon.png",
"build/Microsoft.Extensions.ApiDescription.Server.props",
"build/Microsoft.Extensions.ApiDescription.Server.targets",
"buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.props",
"buildMultiTargeting/Microsoft.Extensions.ApiDescription.Server.targets",
"microsoft.extensions.apidescription.server.9.0.0.nupkg.sha512",
"microsoft.extensions.apidescription.server.nuspec",
"tools/Newtonsoft.Json.dll",
"tools/dotnet-getdocument.deps.json",
"tools/dotnet-getdocument.dll",
"tools/dotnet-getdocument.runtimeconfig.json",
"tools/net462-x86/GetDocument.Insider.exe",
"tools/net462-x86/GetDocument.Insider.exe.config",
"tools/net462-x86/Microsoft.OpenApi.dll",
"tools/net462-x86/Microsoft.Win32.Primitives.dll",
"tools/net462-x86/System.AppContext.dll",
"tools/net462-x86/System.Buffers.dll",
"tools/net462-x86/System.Collections.Concurrent.dll",
"tools/net462-x86/System.Collections.NonGeneric.dll",
"tools/net462-x86/System.Collections.Specialized.dll",
"tools/net462-x86/System.Collections.dll",
"tools/net462-x86/System.ComponentModel.EventBasedAsync.dll",
"tools/net462-x86/System.ComponentModel.Primitives.dll",
"tools/net462-x86/System.ComponentModel.TypeConverter.dll",
"tools/net462-x86/System.ComponentModel.dll",
"tools/net462-x86/System.Console.dll",
"tools/net462-x86/System.Data.Common.dll",
"tools/net462-x86/System.Diagnostics.Contracts.dll",
"tools/net462-x86/System.Diagnostics.Debug.dll",
"tools/net462-x86/System.Diagnostics.DiagnosticSource.dll",
"tools/net462-x86/System.Diagnostics.FileVersionInfo.dll",
"tools/net462-x86/System.Diagnostics.Process.dll",
"tools/net462-x86/System.Diagnostics.StackTrace.dll",
"tools/net462-x86/System.Diagnostics.TextWriterTraceListener.dll",
"tools/net462-x86/System.Diagnostics.Tools.dll",
"tools/net462-x86/System.Diagnostics.TraceSource.dll",
"tools/net462-x86/System.Diagnostics.Tracing.dll",
"tools/net462-x86/System.Drawing.Primitives.dll",
"tools/net462-x86/System.Dynamic.Runtime.dll",
"tools/net462-x86/System.Globalization.Calendars.dll",
"tools/net462-x86/System.Globalization.Extensions.dll",
"tools/net462-x86/System.Globalization.dll",
"tools/net462-x86/System.IO.Compression.ZipFile.dll",
"tools/net462-x86/System.IO.Compression.dll",
"tools/net462-x86/System.IO.FileSystem.DriveInfo.dll",
"tools/net462-x86/System.IO.FileSystem.Primitives.dll",
"tools/net462-x86/System.IO.FileSystem.Watcher.dll",
"tools/net462-x86/System.IO.FileSystem.dll",
"tools/net462-x86/System.IO.IsolatedStorage.dll",
"tools/net462-x86/System.IO.MemoryMappedFiles.dll",
"tools/net462-x86/System.IO.Pipes.dll",
"tools/net462-x86/System.IO.UnmanagedMemoryStream.dll",
"tools/net462-x86/System.IO.dll",
"tools/net462-x86/System.Linq.Expressions.dll",
"tools/net462-x86/System.Linq.Parallel.dll",
"tools/net462-x86/System.Linq.Queryable.dll",
"tools/net462-x86/System.Linq.dll",
"tools/net462-x86/System.Memory.dll",
"tools/net462-x86/System.Net.Http.dll",
"tools/net462-x86/System.Net.NameResolution.dll",
"tools/net462-x86/System.Net.NetworkInformation.dll",
"tools/net462-x86/System.Net.Ping.dll",
"tools/net462-x86/System.Net.Primitives.dll",
"tools/net462-x86/System.Net.Requests.dll",
"tools/net462-x86/System.Net.Security.dll",
"tools/net462-x86/System.Net.Sockets.dll",
"tools/net462-x86/System.Net.WebHeaderCollection.dll",
"tools/net462-x86/System.Net.WebSockets.Client.dll",
"tools/net462-x86/System.Net.WebSockets.dll",
"tools/net462-x86/System.Numerics.Vectors.dll",
"tools/net462-x86/System.ObjectModel.dll",
"tools/net462-x86/System.Reflection.Extensions.dll",
"tools/net462-x86/System.Reflection.Primitives.dll",
"tools/net462-x86/System.Reflection.dll",
"tools/net462-x86/System.Resources.Reader.dll",
"tools/net462-x86/System.Resources.ResourceManager.dll",
"tools/net462-x86/System.Resources.Writer.dll",
"tools/net462-x86/System.Runtime.CompilerServices.Unsafe.dll",
"tools/net462-x86/System.Runtime.CompilerServices.VisualC.dll",
"tools/net462-x86/System.Runtime.Extensions.dll",
"tools/net462-x86/System.Runtime.Handles.dll",
"tools/net462-x86/System.Runtime.InteropServices.RuntimeInformation.dll",
"tools/net462-x86/System.Runtime.InteropServices.dll",
"tools/net462-x86/System.Runtime.Numerics.dll",
"tools/net462-x86/System.Runtime.Serialization.Formatters.dll",
"tools/net462-x86/System.Runtime.Serialization.Json.dll",
"tools/net462-x86/System.Runtime.Serialization.Primitives.dll",
"tools/net462-x86/System.Runtime.Serialization.Xml.dll",
"tools/net462-x86/System.Runtime.dll",
"tools/net462-x86/System.Security.Claims.dll",
"tools/net462-x86/System.Security.Cryptography.Algorithms.dll",
"tools/net462-x86/System.Security.Cryptography.Csp.dll",
"tools/net462-x86/System.Security.Cryptography.Encoding.dll",
"tools/net462-x86/System.Security.Cryptography.Primitives.dll",
"tools/net462-x86/System.Security.Cryptography.X509Certificates.dll",
"tools/net462-x86/System.Security.Principal.dll",
"tools/net462-x86/System.Security.SecureString.dll",
"tools/net462-x86/System.Text.Encoding.Extensions.dll",
"tools/net462-x86/System.Text.Encoding.dll",
"tools/net462-x86/System.Text.RegularExpressions.dll",
"tools/net462-x86/System.Threading.Overlapped.dll",
"tools/net462-x86/System.Threading.Tasks.Parallel.dll",
"tools/net462-x86/System.Threading.Tasks.dll",
"tools/net462-x86/System.Threading.Thread.dll",
"tools/net462-x86/System.Threading.ThreadPool.dll",
"tools/net462-x86/System.Threading.Timer.dll",
"tools/net462-x86/System.Threading.dll",
"tools/net462-x86/System.ValueTuple.dll",
"tools/net462-x86/System.Xml.ReaderWriter.dll",
"tools/net462-x86/System.Xml.XDocument.dll",
"tools/net462-x86/System.Xml.XPath.XDocument.dll",
"tools/net462-x86/System.Xml.XPath.dll",
"tools/net462-x86/System.Xml.XmlDocument.dll",
"tools/net462-x86/System.Xml.XmlSerializer.dll",
"tools/net462-x86/netstandard.dll",
"tools/net462/GetDocument.Insider.exe",
"tools/net462/GetDocument.Insider.exe.config",
"tools/net462/Microsoft.OpenApi.dll",
"tools/net462/Microsoft.Win32.Primitives.dll",
"tools/net462/System.AppContext.dll",
"tools/net462/System.Buffers.dll",
"tools/net462/System.Collections.Concurrent.dll",
"tools/net462/System.Collections.NonGeneric.dll",
"tools/net462/System.Collections.Specialized.dll",
"tools/net462/System.Collections.dll",
"tools/net462/System.ComponentModel.EventBasedAsync.dll",
"tools/net462/System.ComponentModel.Primitives.dll",
"tools/net462/System.ComponentModel.TypeConverter.dll",
"tools/net462/System.ComponentModel.dll",
"tools/net462/System.Console.dll",
"tools/net462/System.Data.Common.dll",
"tools/net462/System.Diagnostics.Contracts.dll",
"tools/net462/System.Diagnostics.Debug.dll",
"tools/net462/System.Diagnostics.DiagnosticSource.dll",
"tools/net462/System.Diagnostics.FileVersionInfo.dll",
"tools/net462/System.Diagnostics.Process.dll",
"tools/net462/System.Diagnostics.StackTrace.dll",
"tools/net462/System.Diagnostics.TextWriterTraceListener.dll",
"tools/net462/System.Diagnostics.Tools.dll",
"tools/net462/System.Diagnostics.TraceSource.dll",
"tools/net462/System.Diagnostics.Tracing.dll",
"tools/net462/System.Drawing.Primitives.dll",
"tools/net462/System.Dynamic.Runtime.dll",
"tools/net462/System.Globalization.Calendars.dll",
"tools/net462/System.Globalization.Extensions.dll",
"tools/net462/System.Globalization.dll",
"tools/net462/System.IO.Compression.ZipFile.dll",
"tools/net462/System.IO.Compression.dll",
"tools/net462/System.IO.FileSystem.DriveInfo.dll",
"tools/net462/System.IO.FileSystem.Primitives.dll",
"tools/net462/System.IO.FileSystem.Watcher.dll",
"tools/net462/System.IO.FileSystem.dll",
"tools/net462/System.IO.IsolatedStorage.dll",
"tools/net462/System.IO.MemoryMappedFiles.dll",
"tools/net462/System.IO.Pipes.dll",
"tools/net462/System.IO.UnmanagedMemoryStream.dll",
"tools/net462/System.IO.dll",
"tools/net462/System.Linq.Expressions.dll",
"tools/net462/System.Linq.Parallel.dll",
"tools/net462/System.Linq.Queryable.dll",
"tools/net462/System.Linq.dll",
"tools/net462/System.Memory.dll",
"tools/net462/System.Net.Http.dll",
"tools/net462/System.Net.NameResolution.dll",
"tools/net462/System.Net.NetworkInformation.dll",
"tools/net462/System.Net.Ping.dll",
"tools/net462/System.Net.Primitives.dll",
"tools/net462/System.Net.Requests.dll",
"tools/net462/System.Net.Security.dll",
"tools/net462/System.Net.Sockets.dll",
"tools/net462/System.Net.WebHeaderCollection.dll",
"tools/net462/System.Net.WebSockets.Client.dll",
"tools/net462/System.Net.WebSockets.dll",
"tools/net462/System.Numerics.Vectors.dll",
"tools/net462/System.ObjectModel.dll",
"tools/net462/System.Reflection.Extensions.dll",
"tools/net462/System.Reflection.Primitives.dll",
"tools/net462/System.Reflection.dll",
"tools/net462/System.Resources.Reader.dll",
"tools/net462/System.Resources.ResourceManager.dll",
"tools/net462/System.Resources.Writer.dll",
"tools/net462/System.Runtime.CompilerServices.Unsafe.dll",
"tools/net462/System.Runtime.CompilerServices.VisualC.dll",
"tools/net462/System.Runtime.Extensions.dll",
"tools/net462/System.Runtime.Handles.dll",
"tools/net462/System.Runtime.InteropServices.RuntimeInformation.dll",
"tools/net462/System.Runtime.InteropServices.dll",
"tools/net462/System.Runtime.Numerics.dll",
"tools/net462/System.Runtime.Serialization.Formatters.dll",
"tools/net462/System.Runtime.Serialization.Json.dll",
"tools/net462/System.Runtime.Serialization.Primitives.dll",
"tools/net462/System.Runtime.Serialization.Xml.dll",
"tools/net462/System.Runtime.dll",
"tools/net462/System.Security.Claims.dll",
"tools/net462/System.Security.Cryptography.Algorithms.dll",
"tools/net462/System.Security.Cryptography.Csp.dll",
"tools/net462/System.Security.Cryptography.Encoding.dll",
"tools/net462/System.Security.Cryptography.Primitives.dll",
"tools/net462/System.Security.Cryptography.X509Certificates.dll",
"tools/net462/System.Security.Principal.dll",
"tools/net462/System.Security.SecureString.dll",
"tools/net462/System.Text.Encoding.Extensions.dll",
"tools/net462/System.Text.Encoding.dll",
"tools/net462/System.Text.RegularExpressions.dll",
"tools/net462/System.Threading.Overlapped.dll",
"tools/net462/System.Threading.Tasks.Parallel.dll",
"tools/net462/System.Threading.Tasks.dll",
"tools/net462/System.Threading.Thread.dll",
"tools/net462/System.Threading.ThreadPool.dll",
"tools/net462/System.Threading.Timer.dll",
"tools/net462/System.Threading.dll",
"tools/net462/System.ValueTuple.dll",
"tools/net462/System.Xml.ReaderWriter.dll",
"tools/net462/System.Xml.XDocument.dll",
"tools/net462/System.Xml.XPath.XDocument.dll",
"tools/net462/System.Xml.XPath.dll",
"tools/net462/System.Xml.XmlDocument.dll",
"tools/net462/System.Xml.XmlSerializer.dll",
"tools/net462/netstandard.dll",
"tools/net9.0/GetDocument.Insider.deps.json",
"tools/net9.0/GetDocument.Insider.dll",
"tools/net9.0/GetDocument.Insider.exe",
"tools/net9.0/GetDocument.Insider.runtimeconfig.json",
"tools/net9.0/Microsoft.AspNetCore.Connections.Abstractions.dll",
"tools/net9.0/Microsoft.AspNetCore.Connections.Abstractions.xml",
"tools/net9.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.dll",
"tools/net9.0/Microsoft.AspNetCore.Hosting.Server.Abstractions.xml",
"tools/net9.0/Microsoft.AspNetCore.Http.Features.dll",
"tools/net9.0/Microsoft.AspNetCore.Http.Features.xml",
"tools/net9.0/Microsoft.Extensions.Configuration.Abstractions.dll",
"tools/net9.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"tools/net9.0/Microsoft.Extensions.Diagnostics.Abstractions.dll",
"tools/net9.0/Microsoft.Extensions.Features.dll",
"tools/net9.0/Microsoft.Extensions.Features.xml",
"tools/net9.0/Microsoft.Extensions.FileProviders.Abstractions.dll",
"tools/net9.0/Microsoft.Extensions.Hosting.Abstractions.dll",
"tools/net9.0/Microsoft.Extensions.Logging.Abstractions.dll",
"tools/net9.0/Microsoft.Extensions.Options.dll",
"tools/net9.0/Microsoft.Extensions.Primitives.dll",
"tools/net9.0/Microsoft.Net.Http.Headers.dll",
"tools/net9.0/Microsoft.Net.Http.Headers.xml",
"tools/net9.0/Microsoft.OpenApi.dll",
"tools/netcoreapp2.1/GetDocument.Insider.deps.json",
"tools/netcoreapp2.1/GetDocument.Insider.dll",
"tools/netcoreapp2.1/GetDocument.Insider.runtimeconfig.json",
"tools/netcoreapp2.1/Microsoft.OpenApi.dll",
"tools/netcoreapp2.1/System.Diagnostics.DiagnosticSource.dll"
]
},
"Microsoft.Extensions.Caching.Abstractions/9.0.9": {
"sha512": "NgtRHOdPrAEacfjXLSrH/SRrSqGf6Vaa6d16mW2yoyJdg7AJr0BnBvxkv7PkCm/CHVyzojTK7Y+oUDEulqY1Qw==",
"type": "package",
@@ -2337,6 +2935,163 @@
"useSharedDesignerContext.txt"
]
},
"Microsoft.IdentityModel.Abstractions/8.14.0": {
"sha512": "iwbCpSjD3ehfTwBhtSNEtKPK0ICun6ov7Ibx6ISNA9bfwIyzI2Siwyi9eJFCJBwxowK9xcA1mj+jBWiigeqgcQ==",
"type": "package",
"path": "microsoft.identitymodel.abstractions/8.14.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"lib/net462/Microsoft.IdentityModel.Abstractions.dll",
"lib/net462/Microsoft.IdentityModel.Abstractions.xml",
"lib/net472/Microsoft.IdentityModel.Abstractions.dll",
"lib/net472/Microsoft.IdentityModel.Abstractions.xml",
"lib/net6.0/Microsoft.IdentityModel.Abstractions.dll",
"lib/net6.0/Microsoft.IdentityModel.Abstractions.xml",
"lib/net8.0/Microsoft.IdentityModel.Abstractions.dll",
"lib/net8.0/Microsoft.IdentityModel.Abstractions.xml",
"lib/net9.0/Microsoft.IdentityModel.Abstractions.dll",
"lib/net9.0/Microsoft.IdentityModel.Abstractions.xml",
"lib/netstandard2.0/Microsoft.IdentityModel.Abstractions.dll",
"lib/netstandard2.0/Microsoft.IdentityModel.Abstractions.xml",
"microsoft.identitymodel.abstractions.8.14.0.nupkg.sha512",
"microsoft.identitymodel.abstractions.nuspec"
]
},
"Microsoft.IdentityModel.JsonWebTokens/8.14.0": {
"sha512": "4jOpiA4THdtpLyMdAb24dtj7+6GmvhOhxf5XHLYWmPKF8ApEnApal1UnJsKO4HxUWRXDA6C4WQVfYyqsRhpNpQ==",
"type": "package",
"path": "microsoft.identitymodel.jsonwebtokens/8.14.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"lib/net462/Microsoft.IdentityModel.JsonWebTokens.dll",
"lib/net462/Microsoft.IdentityModel.JsonWebTokens.xml",
"lib/net472/Microsoft.IdentityModel.JsonWebTokens.dll",
"lib/net472/Microsoft.IdentityModel.JsonWebTokens.xml",
"lib/net6.0/Microsoft.IdentityModel.JsonWebTokens.dll",
"lib/net6.0/Microsoft.IdentityModel.JsonWebTokens.xml",
"lib/net8.0/Microsoft.IdentityModel.JsonWebTokens.dll",
"lib/net8.0/Microsoft.IdentityModel.JsonWebTokens.xml",
"lib/net9.0/Microsoft.IdentityModel.JsonWebTokens.dll",
"lib/net9.0/Microsoft.IdentityModel.JsonWebTokens.xml",
"lib/netstandard2.0/Microsoft.IdentityModel.JsonWebTokens.dll",
"lib/netstandard2.0/Microsoft.IdentityModel.JsonWebTokens.xml",
"microsoft.identitymodel.jsonwebtokens.8.14.0.nupkg.sha512",
"microsoft.identitymodel.jsonwebtokens.nuspec"
]
},
"Microsoft.IdentityModel.Logging/8.14.0": {
"sha512": "eqqnemdW38CKZEHS6diA50BV94QICozDZEvSrsvN3SJXUFwVB9gy+/oz76gldP7nZliA16IglXjXTCTdmU/Ejg==",
"type": "package",
"path": "microsoft.identitymodel.logging/8.14.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"lib/net462/Microsoft.IdentityModel.Logging.dll",
"lib/net462/Microsoft.IdentityModel.Logging.xml",
"lib/net472/Microsoft.IdentityModel.Logging.dll",
"lib/net472/Microsoft.IdentityModel.Logging.xml",
"lib/net6.0/Microsoft.IdentityModel.Logging.dll",
"lib/net6.0/Microsoft.IdentityModel.Logging.xml",
"lib/net8.0/Microsoft.IdentityModel.Logging.dll",
"lib/net8.0/Microsoft.IdentityModel.Logging.xml",
"lib/net9.0/Microsoft.IdentityModel.Logging.dll",
"lib/net9.0/Microsoft.IdentityModel.Logging.xml",
"lib/netstandard2.0/Microsoft.IdentityModel.Logging.dll",
"lib/netstandard2.0/Microsoft.IdentityModel.Logging.xml",
"microsoft.identitymodel.logging.8.14.0.nupkg.sha512",
"microsoft.identitymodel.logging.nuspec"
]
},
"Microsoft.IdentityModel.Protocols/8.0.1": {
"sha512": "uA2vpKqU3I2mBBEaeJAWPTjT9v1TZrGWKdgK6G5qJd03CLx83kdiqO9cmiK8/n1erkHzFBwU/RphP83aAe3i3g==",
"type": "package",
"path": "microsoft.identitymodel.protocols/8.0.1",
"files": [
".nupkg.metadata",
".signature.p7s",
"lib/net462/Microsoft.IdentityModel.Protocols.dll",
"lib/net462/Microsoft.IdentityModel.Protocols.xml",
"lib/net472/Microsoft.IdentityModel.Protocols.dll",
"lib/net472/Microsoft.IdentityModel.Protocols.xml",
"lib/net6.0/Microsoft.IdentityModel.Protocols.dll",
"lib/net6.0/Microsoft.IdentityModel.Protocols.xml",
"lib/net8.0/Microsoft.IdentityModel.Protocols.dll",
"lib/net8.0/Microsoft.IdentityModel.Protocols.xml",
"lib/net9.0/Microsoft.IdentityModel.Protocols.dll",
"lib/net9.0/Microsoft.IdentityModel.Protocols.xml",
"lib/netstandard2.0/Microsoft.IdentityModel.Protocols.dll",
"lib/netstandard2.0/Microsoft.IdentityModel.Protocols.xml",
"microsoft.identitymodel.protocols.8.0.1.nupkg.sha512",
"microsoft.identitymodel.protocols.nuspec"
]
},
"Microsoft.IdentityModel.Protocols.OpenIdConnect/8.0.1": {
"sha512": "AQDbfpL+yzuuGhO/mQhKNsp44pm5Jv8/BI4KiFXR7beVGZoSH35zMV3PrmcfvSTsyI6qrcR898NzUauD6SRigg==",
"type": "package",
"path": "microsoft.identitymodel.protocols.openidconnect/8.0.1",
"files": [
".nupkg.metadata",
".signature.p7s",
"lib/net462/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll",
"lib/net462/Microsoft.IdentityModel.Protocols.OpenIdConnect.xml",
"lib/net472/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll",
"lib/net472/Microsoft.IdentityModel.Protocols.OpenIdConnect.xml",
"lib/net6.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll",
"lib/net6.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.xml",
"lib/net8.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll",
"lib/net8.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.xml",
"lib/net9.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll",
"lib/net9.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.xml",
"lib/netstandard2.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll",
"lib/netstandard2.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.xml",
"microsoft.identitymodel.protocols.openidconnect.8.0.1.nupkg.sha512",
"microsoft.identitymodel.protocols.openidconnect.nuspec"
]
},
"Microsoft.IdentityModel.Tokens/8.14.0": {
"sha512": "lKIZiBiGd36k02TCdMHp1KlNWisyIvQxcYJvIkz7P4gSQ9zi8dgh6S5Grj8NNG7HWYIPfQymGyoZ6JB5d1Lo1g==",
"type": "package",
"path": "microsoft.identitymodel.tokens/8.14.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"lib/net462/Microsoft.IdentityModel.Tokens.dll",
"lib/net462/Microsoft.IdentityModel.Tokens.xml",
"lib/net472/Microsoft.IdentityModel.Tokens.dll",
"lib/net472/Microsoft.IdentityModel.Tokens.xml",
"lib/net6.0/Microsoft.IdentityModel.Tokens.dll",
"lib/net6.0/Microsoft.IdentityModel.Tokens.xml",
"lib/net8.0/Microsoft.IdentityModel.Tokens.dll",
"lib/net8.0/Microsoft.IdentityModel.Tokens.xml",
"lib/net9.0/Microsoft.IdentityModel.Tokens.dll",
"lib/net9.0/Microsoft.IdentityModel.Tokens.xml",
"lib/netstandard2.0/Microsoft.IdentityModel.Tokens.dll",
"lib/netstandard2.0/Microsoft.IdentityModel.Tokens.xml",
"microsoft.identitymodel.tokens.8.14.0.nupkg.sha512",
"microsoft.identitymodel.tokens.nuspec"
]
},
"Microsoft.OpenApi/1.6.25": {
"sha512": "ZahSqNGtNV7N0JBYS/IYXPkLVexL/AZFxo6pqxv6A7Uli7Q7zfitNjkaqIcsV73Ukzxi4IlJdyDgcQiMXiH8cw==",
"type": "package",
"path": "microsoft.openapi/1.6.25",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"lib/netstandard2.0/Microsoft.OpenApi.dll",
"lib/netstandard2.0/Microsoft.OpenApi.pdb",
"lib/netstandard2.0/Microsoft.OpenApi.xml",
"microsoft.openapi.1.6.25.nupkg.sha512",
"microsoft.openapi.nuspec"
]
},
"Mono.TextTemplating/3.0.0": {
"sha512": "YqueG52R/Xej4VVbKuRIodjiAhV0HR/XVbLbNrJhCZnzjnSjgMJ/dCdV0akQQxavX6hp/LC6rqLGLcXeQYU7XA==",
"type": "package",
@@ -2386,6 +3141,74 @@
"postgresql.png"
]
},
"Swashbuckle.AspNetCore/9.0.6": {
"sha512": "q/UfEAgrk6qQyjHXgsW9ILw0YZLfmPtWUY4wYijliX6supozC+TkzU0G6FTnn/dPYxnChjM8g8lHjWHF6VKy+A==",
"type": "package",
"path": "swashbuckle.aspnetcore/9.0.6",
"files": [
".nupkg.metadata",
".signature.p7s",
"build/Swashbuckle.AspNetCore.props",
"buildMultiTargeting/Swashbuckle.AspNetCore.props",
"docs/package-readme.md",
"swashbuckle.aspnetcore.9.0.6.nupkg.sha512",
"swashbuckle.aspnetcore.nuspec"
]
},
"Swashbuckle.AspNetCore.Swagger/9.0.6": {
"sha512": "Bgyc8rWRAYwDrzjVHGbavvNE38G1Dfgf1McHYm+WUr4TxkvEAXv8F8B1z3Kmz4BkDCKv9A/1COa2t7+Ri5+pLg==",
"type": "package",
"path": "swashbuckle.aspnetcore.swagger/9.0.6",
"files": [
".nupkg.metadata",
".signature.p7s",
"lib/net8.0/Swashbuckle.AspNetCore.Swagger.dll",
"lib/net8.0/Swashbuckle.AspNetCore.Swagger.pdb",
"lib/net8.0/Swashbuckle.AspNetCore.Swagger.xml",
"lib/net9.0/Swashbuckle.AspNetCore.Swagger.dll",
"lib/net9.0/Swashbuckle.AspNetCore.Swagger.pdb",
"lib/net9.0/Swashbuckle.AspNetCore.Swagger.xml",
"package-readme.md",
"swashbuckle.aspnetcore.swagger.9.0.6.nupkg.sha512",
"swashbuckle.aspnetcore.swagger.nuspec"
]
},
"Swashbuckle.AspNetCore.SwaggerGen/9.0.6": {
"sha512": "yYrDs5qpIa4UXP+a02X0ZLQs6HSd1C8t6hF6J1fnxoawi3PslJg1yUpLBS89HCbrDACzmwEGG25il+8aa0zdnw==",
"type": "package",
"path": "swashbuckle.aspnetcore.swaggergen/9.0.6",
"files": [
".nupkg.metadata",
".signature.p7s",
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerGen.dll",
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerGen.pdb",
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerGen.xml",
"lib/net9.0/Swashbuckle.AspNetCore.SwaggerGen.dll",
"lib/net9.0/Swashbuckle.AspNetCore.SwaggerGen.pdb",
"lib/net9.0/Swashbuckle.AspNetCore.SwaggerGen.xml",
"package-readme.md",
"swashbuckle.aspnetcore.swaggergen.9.0.6.nupkg.sha512",
"swashbuckle.aspnetcore.swaggergen.nuspec"
]
},
"Swashbuckle.AspNetCore.SwaggerUI/9.0.6": {
"sha512": "WGsw/Yop9b16miq8TQd4THxuEgkP5cH3+DX93BrX9m0OdPcKNtg2nNm77WQSAsA+Se+M0bTiu8bUyrruRSeS5g==",
"type": "package",
"path": "swashbuckle.aspnetcore.swaggerui/9.0.6",
"files": [
".nupkg.metadata",
".signature.p7s",
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerUI.dll",
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerUI.pdb",
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerUI.xml",
"lib/net9.0/Swashbuckle.AspNetCore.SwaggerUI.dll",
"lib/net9.0/Swashbuckle.AspNetCore.SwaggerUI.pdb",
"lib/net9.0/Swashbuckle.AspNetCore.SwaggerUI.xml",
"package-readme.md",
"swashbuckle.aspnetcore.swaggerui.9.0.6.nupkg.sha512",
"swashbuckle.aspnetcore.swaggerui.nuspec"
]
},
"System.CodeDom/6.0.0": {
"sha512": "CPc6tWO1LAer3IzfZufDBRL+UZQcj5uS207NHALQzP84Vp/z6wF0Aa0YZImOQY8iStY0A2zI/e3ihKNPfUm8XA==",
"type": "package",
@@ -2594,6 +3417,30 @@
"useSharedDesignerContext.txt"
]
},
"System.IdentityModel.Tokens.Jwt/8.14.0": {
"sha512": "EYGgN/S+HK7S6F3GaaPLFAfK0UzMrkXFyWCvXpQWFYmZln3dqtbyIO7VuTM/iIIPMzkelg8ZLlBPvMhxj6nOAA==",
"type": "package",
"path": "system.identitymodel.tokens.jwt/8.14.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"lib/net462/System.IdentityModel.Tokens.Jwt.dll",
"lib/net462/System.IdentityModel.Tokens.Jwt.xml",
"lib/net472/System.IdentityModel.Tokens.Jwt.dll",
"lib/net472/System.IdentityModel.Tokens.Jwt.xml",
"lib/net6.0/System.IdentityModel.Tokens.Jwt.dll",
"lib/net6.0/System.IdentityModel.Tokens.Jwt.xml",
"lib/net8.0/System.IdentityModel.Tokens.Jwt.dll",
"lib/net8.0/System.IdentityModel.Tokens.Jwt.xml",
"lib/net9.0/System.IdentityModel.Tokens.Jwt.dll",
"lib/net9.0/System.IdentityModel.Tokens.Jwt.xml",
"lib/netstandard2.0/System.IdentityModel.Tokens.Jwt.dll",
"lib/netstandard2.0/System.IdentityModel.Tokens.Jwt.xml",
"system.identitymodel.tokens.jwt.8.14.0.nupkg.sha512",
"system.identitymodel.tokens.jwt.nuspec"
]
},
"System.IO.Pipelines/7.0.0": {
"sha512": "jRn6JYnNPW6xgQazROBLSfpdoczRw694vO5kKvMcNnpXuolEixUyw6IBuBs2Y2mlSX/LdLvyyWmfXhaI3ND1Yg==",
"type": "package",
@@ -2777,12 +3624,18 @@
},
"projectFileDependencyGroups": {
"net9.0": [
"BCrypt.Net-Next >= 4.0.3",
"FluentValidation.DependencyInjectionExtensions >= 12.0.0",
"Microsoft.AspNetCore.Authentication.JwtBearer >= 9.0.9",
"Microsoft.EntityFrameworkCore.Design >= 9.0.9",
"Npgsql.EntityFrameworkCore.PostgreSQL >= 9.0.4"
"Npgsql.EntityFrameworkCore.PostgreSQL >= 9.0.4",
"Swashbuckle.AspNetCore >= 9.0.6",
"System.IdentityModel.Tokens.Jwt >= 8.14.0"
]
},
"packageFolders": {
"C:\\Users\\heiye\\.nuget\\packages\\": {}
"C:\\Users\\heiye\\.nuget\\packages\\": {},
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {}
},
"project": {
"version": "1.0.0",
@@ -2793,13 +3646,19 @@
"packagesPath": "C:\\Users\\heiye\\.nuget\\packages\\",
"outputPath": "C:\\code\\SimpleTodoApiWithPg\\obj\\",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\heiye\\AppData\\Roaming\\NuGet\\NuGet.Config"
"C:\\Users\\heiye\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net9.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
@@ -2824,6 +3683,18 @@
"net9.0": {
"targetAlias": "net9.0",
"dependencies": {
"BCrypt.Net-Next": {
"target": "Package",
"version": "[4.0.3, )"
},
"FluentValidation.DependencyInjectionExtensions": {
"target": "Package",
"version": "[12.0.0, )"
},
"Microsoft.AspNetCore.Authentication.JwtBearer": {
"target": "Package",
"version": "[9.0.9, )"
},
"Microsoft.EntityFrameworkCore.Design": {
"include": "Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive",
"suppressParent": "All",
@@ -2833,6 +3704,14 @@
"Npgsql.EntityFrameworkCore.PostgreSQL": {
"target": "Package",
"version": "[9.0.4, )"
},
"Swashbuckle.AspNetCore": {
"target": "Package",
"version": "[9.0.6, )"
},
"System.IdentityModel.Tokens.Jwt": {
"target": "Package",
"version": "[8.14.0, )"
}
},
"imports": [

View File

@@ -1,10 +1,14 @@
{
"version": 2,
"dgSpecHash": "hQuQRTWDcxc=",
"dgSpecHash": "kIoE/znXMRY=",
"success": true,
"projectFilePath": "C:\\code\\SimpleTodoApiWithPg\\SimpleTodoApiWithPg.csproj",
"expectedPackageFiles": [
"C:\\Users\\heiye\\.nuget\\packages\\bcrypt.net-next\\4.0.3\\bcrypt.net-next.4.0.3.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\fluentvalidation\\12.0.0\\fluentvalidation.12.0.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\fluentvalidation.dependencyinjectionextensions\\12.0.0\\fluentvalidation.dependencyinjectionextensions.12.0.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\humanizer.core\\2.14.1\\humanizer.core.2.14.1.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.aspnetcore.authentication.jwtbearer\\9.0.9\\microsoft.aspnetcore.authentication.jwtbearer.9.0.9.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.bcl.asyncinterfaces\\7.0.0\\microsoft.bcl.asyncinterfaces.7.0.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.build.framework\\17.8.3\\microsoft.build.framework.17.8.3.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.build.locator\\1.7.8\\microsoft.build.locator.1.7.8.nupkg.sha512",
@@ -19,6 +23,7 @@
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.entityframeworkcore.analyzers\\9.0.9\\microsoft.entityframeworkcore.analyzers.9.0.9.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.entityframeworkcore.design\\9.0.9\\microsoft.entityframeworkcore.design.9.0.9.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.entityframeworkcore.relational\\9.0.9\\microsoft.entityframeworkcore.relational.9.0.9.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.extensions.apidescription.server\\9.0.0\\microsoft.extensions.apidescription.server.9.0.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.extensions.caching.abstractions\\9.0.9\\microsoft.extensions.caching.abstractions.9.0.9.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.extensions.caching.memory\\9.0.9\\microsoft.extensions.caching.memory.9.0.9.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.extensions.configuration.abstractions\\9.0.9\\microsoft.extensions.configuration.abstractions.9.0.9.nupkg.sha512",
@@ -29,9 +34,20 @@
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.extensions.logging.abstractions\\9.0.9\\microsoft.extensions.logging.abstractions.9.0.9.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.extensions.options\\9.0.9\\microsoft.extensions.options.9.0.9.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.extensions.primitives\\9.0.9\\microsoft.extensions.primitives.9.0.9.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.identitymodel.abstractions\\8.14.0\\microsoft.identitymodel.abstractions.8.14.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.identitymodel.jsonwebtokens\\8.14.0\\microsoft.identitymodel.jsonwebtokens.8.14.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.identitymodel.logging\\8.14.0\\microsoft.identitymodel.logging.8.14.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.identitymodel.protocols\\8.0.1\\microsoft.identitymodel.protocols.8.0.1.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.identitymodel.protocols.openidconnect\\8.0.1\\microsoft.identitymodel.protocols.openidconnect.8.0.1.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.identitymodel.tokens\\8.14.0\\microsoft.identitymodel.tokens.8.14.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\microsoft.openapi\\1.6.25\\microsoft.openapi.1.6.25.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\mono.texttemplating\\3.0.0\\mono.texttemplating.3.0.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\npgsql\\9.0.3\\npgsql.9.0.3.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\npgsql.entityframeworkcore.postgresql\\9.0.4\\npgsql.entityframeworkcore.postgresql.9.0.4.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\swashbuckle.aspnetcore\\9.0.6\\swashbuckle.aspnetcore.9.0.6.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\swashbuckle.aspnetcore.swagger\\9.0.6\\swashbuckle.aspnetcore.swagger.9.0.6.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\swashbuckle.aspnetcore.swaggergen\\9.0.6\\swashbuckle.aspnetcore.swaggergen.9.0.6.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\swashbuckle.aspnetcore.swaggerui\\9.0.6\\swashbuckle.aspnetcore.swaggerui.9.0.6.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\system.codedom\\6.0.0\\system.codedom.6.0.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\system.collections.immutable\\7.0.0\\system.collections.immutable.7.0.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\system.composition\\7.0.0\\system.composition.7.0.0.nupkg.sha512",
@@ -40,6 +56,7 @@
"C:\\Users\\heiye\\.nuget\\packages\\system.composition.hosting\\7.0.0\\system.composition.hosting.7.0.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\system.composition.runtime\\7.0.0\\system.composition.runtime.7.0.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\system.composition.typedparts\\7.0.0\\system.composition.typedparts.7.0.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\system.identitymodel.tokens.jwt\\8.14.0\\system.identitymodel.tokens.jwt.8.14.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\system.io.pipelines\\7.0.0\\system.io.pipelines.7.0.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\system.reflection.metadata\\7.0.0\\system.reflection.metadata.7.0.0.nupkg.sha512",
"C:\\Users\\heiye\\.nuget\\packages\\system.runtime.compilerservices.unsafe\\6.0.0\\system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512",