模型绑定最佳实践

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.EntityFrameworks;
using HelloShop.IdentityService.Models.Users;
using HelloShop.ServiceDefaults.Authorization;
using HelloShop.ServiceDefaults.Models.Paging;
using Microsoft.AspNetCore.Authorization;
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
@ -14,14 +18,29 @@ namespace HelloShop.IdentityService.Controllers
{
[HttpGet]
[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}")]
[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());
@ -31,7 +50,7 @@ namespace HelloShop.IdentityService.Controllers
{
return Forbid();
}
User? user = dbContext.Set<User>().Find(id);
if (user == null)
@ -39,26 +58,70 @@ namespace HelloShop.IdentityService.Controllers
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]
[Authorize(IdentityPermissions.Users.Create)]
public void PostUser([FromBody] User value)
public async Task<ActionResult<UserDetailsResponse>> PostUser([FromBody] UserCreateRequest model)
{
dbContext.Add(value);
dbContext.SaveChanges();
var user = new User
{
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}")]
[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);
if (user != null)
{
dbContext.SaveChanges();
user.UserName = model.UserName;
user.PhoneNumber = model.PhoneNumber;
user.Email = model.Email;
}
await dbContext.SaveChangesAsync();
return Ok();
}
[HttpDelete("{id}")]
@ -84,11 +147,13 @@ namespace HelloShop.IdentityService.Controllers
return Unauthorized();
}
[HttpGet(nameof(Bar))]
[Authorize(IdentityPermissions.Users.Create)]
public IActionResult Bar()
[HttpDelete]
[Authorize(IdentityPermissions.Users.Delete)]
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; }
}