2022. 12. 22. 00:00ㆍASPNET/ASPNET 7
Vertical Slice Architecture
UI, Application, Domain, DB 등의 각각을 Layer 로 분리 하여 따로 관리 하지 않고
기능별(user story or feature) 로 모아서 응집도를 높이는 Architecture
참고 : https://jimmybogard.com/vertical-slice-architecture/
일단 Controllers 폴더와 WeatherForecastController.cs 를 삭제하자
WeatherForecast.cs 파일도 삭제하자
자 위와 같은 Architecture 를 구현해보자
Features 폴더생성
User 폴더 생성
UserController.cs 생성
초기에 Vertical Slice 를 구현 하기 전에 UserController.cs 에 모든 코드를 집중해 보자.
UserController.cs
using Microsoft.AspNetCore.Mvc;
namespace ApiServer.Features.User;
[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
[HttpPost(Name = "Login")]
public IActionResult Login(string id, string password)
{
if (password == "1234")
{
return Ok();
}
return Unauthorized();
}
}
실행해 보자
아래와 같이 입력 하면
다음과 같이 에러가 발생한다. (401)
password 를 1234 로 바꾸면
특별한 response 없이 HttpsStatus 200 을 return 한다.
코드를 분리하기전에 MediatR 이라는 library 를 설치해보자
(Event Driven 을 구현하기 위한 좋은 library 이다. )
Ctrl + ` 또는 View --> Terminal click --> 개발자 명령 프롬프트로 이동
개발자 명령 프롬프트에서 프로젝트 폴더로 이동
**이미 프로젝트 폴더에 있다면 이동하지 않아도 된다. **
(현재 [솔루션명].sln 파일이 있는 폴더라면 [프로젝트명].csproj 파일이 있는 폴더로 이동)
다음 실행
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
Program.cs 에 다음 코드 추가
using MediatR;
…
builder.Services.AddMediatR(AssemblyHelper.GetAllAssemblies().ToArray());
Helper 폴더 추가 --> AssemblyHelper.cs 추가 -->코드 수정
using System.Reflection;
using System.Runtime.Loader;
namespace ApiServer.Helper;
public class AssemblyHelper
{
public static List<Assembly> GetAllAssemblies(SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
var assemblyFiles = Directory.GetFiles(baseDirectory
, "*.dll"
, searchOption);
var path = Directory.GetFiles(baseDirectory);
foreach (string assemblyPath in assemblyFiles)
{
try
{
var assembly = AssemblyLoadContext
.Default
.LoadFromAssemblyPath(assemblyPath);
}
catch (Exception ex)
{
//Debug.WriteLine(ex.ToString());
}
}
return AssemblyLoadContext.Default.Assemblies.ToList();
}
}
일단 이렇게 만든 상태에서 UserController.cs 에 있는 코드들을 분리해보자
Features/User/Login.cs
using MediatR;
using System.Runtime.CompilerServices;
namespace ApiServer.Features.User;
public class Login
{
public class Command : IRequest<Response>
{
public string Id { get; set; } = string.Empty;
public string Pasword { get; set; } = string.Empty;
}
public class Response
{
public bool Result { get; set; }
public Error? Error { get; set; }
public string? AccessToken { get; set; }
}
public class Error
{
public string Code { get; set; } = string.Empty;
public string Message { get; set; } = string.Empty;
}
public class CommandHandler : IRequestHandler<Command, Response>
{
public Task<Response> Handle(Command request, CancellationToken cancellationToken)
{
var response = new Response { Result = false };
string? accessToken = null;
if (request.Pasword == "1234")
{
accessToken = Guid.NewGuid().ToString("N");
response.Result = true;
}
else
{
response.Error = new Error()
{
Code = "02",
Message = $"Login Failed, check your password"
};
}
response.AccessToken = accessToken;
return Task.FromResult(response);
}
}
}
이제 UserController 을 수정해 보자
Features/User/UserController.cs
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace ApiServer.Features.User;
[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
private readonly IMediator _mediator;
public UserController(IMediator mediator)
{
_mediator = mediator;
}
[AllowAnonymous]
[ProducesResponseType(typeof(Login.Response), StatusCodes.Status200OK)]
[HttpPost("login")]
public async Task<IActionResult> Login(Login.Command request)
{
if (!ModelState.IsValid)
return BadRequest();
var response = await _mediator.Send(request);
return response.Result ? Ok(response) : Unauthorized(); //status code 로 response처리
//return Ok(response); // 내부의 result 와 error 를 통해 response 처리
}
}
관련영상
'ASPNET > ASPNET 7' 카테고리의 다른 글
Rest API Template 만들기 - EP 04 (Logger Customize, Trace) (0) | 2022.12.29 |
---|---|
Rest API Template 만들기 - EP 03 (Dependency Injection, Scrutor) (0) | 2022.12.26 |
Rest API Template 만들기 - EP 01 (Create , Swagger, Logging) (0) | 2022.12.19 |
gRPC HealthCheck (0) | 2022.12.15 |
ASPNET 7 - Endpoint Filter (0) | 2022.12.12 |