模型绑定最佳实践

This commit is contained in:
hello 2024-04-04 07:43:24 +08:00
parent 40e307faef
commit 5516bb80dd
12 changed files with 196 additions and 14 deletions

View File

@ -1,8 +1,12 @@
using HelloShop.IdentityService.Entities; using HelloShop.IdentityService.Entities;
using HelloShop.IdentityService.EntityFrameworks; using HelloShop.IdentityService.EntityFrameworks;
using HelloShop.IdentityService.Models.Users;
using HelloShop.ServiceDefaults.Authorization; using HelloShop.ServiceDefaults.Authorization;
using HelloShop.ServiceDefaults.Models.Paging;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 // For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
@ -14,14 +18,29 @@ namespace HelloShop.IdentityService.Controllers
{ {
[HttpGet] [HttpGet]
[Authorize(IdentityPermissions.Users.Default)] [Authorize(IdentityPermissions.Users.Default)]
public IEnumerable<User> GetUsers() public async Task<ActionResult<PagedResponse<UserListItem>>> GetUsers([FromQuery] UserListRequest model)
{ {
return dbContext.Set<User>(); var userList= await dbContext.Set<User>().Skip((model.PageNumber - 1) * model.PageSize).Take(model.PageSize).ToListAsync();
var result = userList.Select(e => new UserListItem
{
Id = e.Id,
UserName = e.UserName!,
PhoneNumber = e.PhoneNumber,
PhoneNumberConfirmed = e.PhoneNumberConfirmed,
Email = e.Email,
EmailConfirmed = e.EmailConfirmed,
CreationTime = e.CreationTime,
}).ToList();
var responseModel = new PagedResponse<UserListItem>(result, result.Count);
return Ok(responseModel);
} }
[HttpGet("{id}")] [HttpGet("{id}")]
[Authorize(IdentityPermissions.Users.Default)] [Authorize(IdentityPermissions.Users.Default)]
public async Task<ActionResult<User>> GetUser(int id, [FromServices] IAuthorizationService authorizationService) public async Task<ActionResult<UserDetailsResponse>> GetUser(int id, [FromServices] IAuthorizationService authorizationService)
{ {
ResourceInfo resource = new(nameof(User), id.ToString()); ResourceInfo resource = new(nameof(User), id.ToString());
@ -31,7 +50,7 @@ namespace HelloShop.IdentityService.Controllers
{ {
return Forbid(); return Forbid();
} }
User? user = dbContext.Set<User>().Find(id); User? user = dbContext.Set<User>().Find(id);
if (user == null) if (user == null)
@ -39,26 +58,70 @@ namespace HelloShop.IdentityService.Controllers
return NotFound(); return NotFound();
} }
return Ok(user); UserDetailsResponse responseModel = new()
{
Id = user.Id,
UserName = user.UserName!,
PhoneNumber = user.PhoneNumber,
PhoneNumberConfirmed = user.PhoneNumberConfirmed,
Email = user.Email,
EmailConfirmed = user.EmailConfirmed,
CreationTime = user.CreationTime,
};
return Ok(responseModel);
} }
[HttpPost] [HttpPost]
[Authorize(IdentityPermissions.Users.Create)] [Authorize(IdentityPermissions.Users.Create)]
public void PostUser([FromBody] User value) public async Task<ActionResult<UserDetailsResponse>> PostUser([FromBody] UserCreateRequest model)
{ {
dbContext.Add(value); var user = new User
dbContext.SaveChanges(); {
UserName = model.UserName,
PhoneNumber = model.PhoneNumber,
Email = model.Email
};
await dbContext.AddAsync(user);
await dbContext.SaveChangesAsync();
UserDetailsResponse responseModel = new()
{
Id = user.Id,
UserName = user.UserName,
PhoneNumber = user.PhoneNumber,
PhoneNumberConfirmed = user.PhoneNumberConfirmed,
Email = user.Email,
EmailConfirmed = user.EmailConfirmed,
CreationTime = user.CreationTime,
};
return CreatedAtAction(nameof(GetUser), new { id = user.Id }, responseModel);
} }
[HttpPut("{id}")] [HttpPut("{id}")]
[Authorize(IdentityPermissions.Users.Update)] [Authorize(IdentityPermissions.Users.Update)]
public void PutUser(int id, [FromBody] User value) public async Task<IActionResult> PutUser(int id, [FromBody] UserUpdateRequest model)
{ {
if (model.Id != id)
{
throw new ArgumentException("Id mismatch", nameof(model));
}
var user = dbContext.Set<User>().Find(id); var user = dbContext.Set<User>().Find(id);
if (user != null) if (user != null)
{ {
dbContext.SaveChanges(); user.UserName = model.UserName;
user.PhoneNumber = model.PhoneNumber;
user.Email = model.Email;
} }
await dbContext.SaveChangesAsync();
return Ok();
} }
[HttpDelete("{id}")] [HttpDelete("{id}")]
@ -84,11 +147,13 @@ namespace HelloShop.IdentityService.Controllers
return Unauthorized(); return Unauthorized();
} }
[HttpGet(nameof(Bar))] [HttpDelete]
[Authorize(IdentityPermissions.Users.Create)] [Authorize(IdentityPermissions.Users.Delete)]
public IActionResult Bar() public async Task<IActionResult> DeleteUsers(IEnumerable<int> ids)
{ {
return Ok("Hello, World!"); await dbContext.Set<User>().Where(e => ids.Contains(e.Id)).ExecuteDeleteAsync();
return NoContent();
} }
} }
} }

View File

@ -0,0 +1,12 @@
namespace HelloShop.IdentityService.Models.Users;
public class UserCreateRequest
{
public required string UserName { get; init; }
public string? PhoneNumber { get; set; }
public string? Email { get; set; }
public required string Password { get; init; }
}

View File

@ -0,0 +1,20 @@
namespace HelloShop.IdentityService.Models.Users;
public class UserDetailsResponse
{
public int Id { get; init; }
public required string UserName { get; init; }
public string? PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public string? Email { get; set; }
public bool EmailConfirmed { get; set; }
public DateTimeOffset CreationTime { get; init; }
public List<int>? Roles { get; set; }
}

View File

@ -0,0 +1,18 @@
namespace HelloShop.IdentityService;
public class UserListItem
{
public int Id { get; init; }
public required string UserName { get; init; }
public string? PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public string? Email { get; set; }
public bool EmailConfirmed { get; set; }
public DateTimeOffset CreationTime { get; init; }
}

View File

@ -0,0 +1,8 @@
using HelloShop.ServiceDefaults.Models.Paging;
namespace HelloShop.IdentityService.Models.Users;
public class UserListRequest : KeywordSearchRequest
{
public string? PhoneNumber { get; init; }
}

View File

@ -0,0 +1,14 @@
namespace HelloShop.IdentityService.Models.Users;
public class UserUpdateRequest
{
public int Id { get; init; }
public required string UserName { get; init; }
public string? PhoneNumber { get; set; }
public string? Email { get; set; }
public string? Password { get; set; }
}

View File

@ -0,0 +1,7 @@
namespace HelloShop.ServiceDefaults.Constants;
public class PagingConstants
{
public const int DefaultPageSize = 10;
}

View File

@ -0,0 +1,6 @@
namespace HelloShop.ServiceDefaults.Models.Paging;
public class KeywordSearchRequest : PagedAndSortedRequest
{
public string? Keyword { get; init; }
}

View File

@ -0,0 +1,6 @@
namespace HelloShop.ServiceDefaults.Models.Paging;
public class PagedAndSortedRequest : PagedRequest
{
public IEnumerable<SortingOrder>? Sorts { get; init; }
}

View File

@ -0,0 +1,10 @@
using HelloShop.ServiceDefaults.Constants;
namespace HelloShop.ServiceDefaults.Models.Paging;
public class PagedRequest
{
public int PageNumber { get; init; } = 1;
public int PageSize { get; init; } = PagingConstants.DefaultPageSize;
}

View File

@ -0,0 +1,8 @@
namespace HelloShop.ServiceDefaults.Models.Paging;
public class PagedResponse<T>(IReadOnlyList<T> items, int totalCount)
{
public IReadOnlyList<T> Items { get; init; } = items;
public int TotalCount { get; init; } = totalCount;
}

View File

@ -0,0 +1,8 @@
namespace HelloShop.ServiceDefaults.Models.Paging;
public class SortingOrder
{
public required string PropertyName { get; init; }
public bool Ascending { get; init; }
}