반응형

인공지능 분야의 권위자인 안드레이 카르파시가 올초에 언급하면서 유명해진 단어 바이브코딩. 사실 유행탄지도 꽤됐고 저도 벌써 3달째 gpt와 claude를 병행 결제하고 있는데요. 그 중 gpt5가 나오기 전까지 개발자들에게 각광 받았던 클로드, 그중에서도 프로젝트 내 코드를 직접 수정하는 것을 집중적으로 잘해주는 클로드 코드 사용방법에 대해 설명드리겠습니다. 영어를 알아 볼 수만 있어도 공식홈페이지 직접 가는 것도 나은 방법일 수 있어요. 

 

 

우선 클로드 코드는 Pro이상의 결제가 필요합니다. pro가 포스트를 작성하는 기준으로 월 17달러랍니다.

 

 

일단 공홈의 클로드 코드 페이지 부터 링크 남겨드립니다.

https://www.anthropic.com/claude-code

 

Claude Code: Deep coding at terminal velocity \ Anthropic

Transform hours of debugging into seconds with a single command. Experience coding at thought-speed with Claude's AI that understands your entire codebase—no more context switching, just breakthrough results.

www.anthropic.com

 

 

물론 영어가 어렵다거나 간소화된 버전으로 보시고 싶으시다면 남아계시죠. 바로 들어가겠습니다. 클로드 코드는 node.js 18버전 이상에서 지원합니다. 우리 개발자분들이라면 필수적으로 설치하고 계시리라 믿습니다만, 처음오시는 분들을 위해 스크린샷 아래에 node.js의 다운로드 페이지도 남겨두었습니다. 운영체제에 맞게 다운로드 후 설치하시면 됩니다.

 

https://nodejs.org/en/download

 

Node.js — Download Node.js®

Node.js® is a free, open-source, cross-platform JavaScript runtime environment that lets developers create servers, web apps, command line tools and scripts.

nodejs.org

 

node.js 설치를 완료하셨다면 Windows에서는 실행(win + R) -> Cmd, mac OS에서는 터미널에서 아래명령어를 실행해줍니다.

npm install -g @anthropic-ai/claude-code

 

설치를 마치셨다면, 프로젝트를 진행할 폴더를 생성하고 "cd 폴더경로"로 진입 후 "claude"라고 치면 클로드 코드가 실행됩니다. 프로젝트를 진행할 폴더는 ide로 프로젝트 구조가 생성된 폴더여도 되고, 클로드에게 프로젝트에 쓸 언어와 프레임워크를 설명하고 생성해달라고 하더라도 잘해줍니다.

 

 

제가 예제로 간단하게 클로드 코드를 실행하며 vs code를 열겠습니다. fast api를 요즘 공부중이기 때문에 이름을 fastapi로 짓겠습니다.

mkdir fastapi_by_claude 
#엔터

cd fastapi_by_claude 
#엔터

claude

 

환영한다는 문구가 나오며, 해당 디렉토리를 접근해도 되냐고 물어볼 겁니다. yes, proceed를 선택 후 클로드 코드와 프롬프트로 개발을 시작할 수 있습니다. 이렇게 쌩판 터미널에서 개발하는 방법도 있지만 ide에서 할 수도 있습니다. vscode에서는 클로드 확장도 지원합니다.

 

vs code를 실행해줍니다. (mac에서는 소스 폴더 또는 그냥 폴더를 우클릭하고 터미널을 연 뒤), (windows에서는 탐색기 주소창에 cmd를 치고 터미널을 연뒤) code .을 쳐 줍니다. vs code를 그냥 실행하고 열기로 여셔도 무방합니다. 확장 마켓플레이스에서 claude code를 검색해보면 claude code for vs code라는 확장이 있습니다. 설치해줍니다. 

 

 

그러면 우측상단에 클로드 아이콘이 생기는데요, 그것을 누르면 알아서 터미널에 claude를 친 상태로 실행하게 됩니다. vs code의 상단 터미널에서 claude를 쳐줘도 같긴 합니다만, 버튼 한번에 이루어져 더 편리하게 느껴집니다. 

 

저는 간단한 예제를 보여드리기 위해 빈폴더에서 claude를 실행 후 fast api로 만들어 달라하였습니다.

 

 

파이썬 환경과 가상환경이 제멋대로라 정리를 부탁했습니다.

 

 

 

소스를 세세히 뜯어보면 아직 고장난 곳이 있지만, 프롬프트에 나타난 요청사항이 너무 광범위 하고 포괄적이기 때문에 이정도면 아주 빠르게 잘 개발 해준 것이라는 느낌이 들어요.

 

 

 

마지막으로 클로드 코드 토큰 사용량 측정방법입니다. 토큰 측정을 위한 모듈 두개를 설치해야합니다. 검정색 두줄을 순서대로 설치하시면 됩니다. 명령어가 아닌부분은 주석처리했습니다.

sudo npm install -g ccusage
# Password:

# added 1 package in 512ms

# 1 package is looking for funding
#  run `npm fund` for details
pip install claude-monitor

 

 

설치를 마치셨다면 설치한 토큰 사용량을 측정하는 cli를 실행해줍니다. 명령어와 결과를 보여드립니다.

claude-monitor

 

 

p.s 참고적으로 claude의 상태를 체크하는 명령어는 claude doctor입니다. flutter doctor가 떠올라서 급 남기고 포스트 종료합니다.

반응형
반응형

오늘은 컨트롤러 내 액션메소드의 반환값에 대해 알아보겠습니다.

 

이전 asp.net core mvc 기초 시리즈들을 정주행하신 독자분들이라면 기본적으로 아래 두 사항이 당연하게 인식되고 있으시리라 믿습니다.

 

 

1. HomeController 내 액션함수 Private()에서 반환값이  View() 인 경우 

프로젝트 하위의 Views/Home/Privacy.cshtml 페이지로 넘어가게 됩니다.

 

2. HomeController 내 액션함수 Abc()에서 반환값이  View("Privacy") 인 경우

[HttpGet("[action]")]
    public IActionResult Privacy()
    {
        return View();
    }

    [HttpGet("custom_route")]
    public IActionResult Abc()
    {
        return View("Privacy");
    }

프로젝트 하위의 Views/Home 폴더 내에서 확장자를 제외한 파일명이 Privacy .cshtml 페이지를 찾아 거기로 넘어갑니다.

View()내에 string으로 작성하면 위 예시인 경우 컨트롤러가 가리키는 Views내 폴더 내에서 파일을 찾습니다. 만약에 Views/Home외에 다른 경로를 가리키고 싶다면 두가지 방법이 있습니다. 

 

a. 절대경로 ->   return View("Views/Route/Home.cshtml"); 형태로 반환합니다.

b. 상대경로 ->   return View("../Route/Index");

 

 

 

3. HomeController 내 액션함수 Index()에서 반환값이  View(Model) 인 경우 

프로젝트 하위의 Views/Home/Privacy.cshtml 페이지로 Model과 함께 넘어가게 되어 프론트단에서 모델을 받아올 수 있습니다. 모델은 기본자료형, 선언한 클래스의 인스턴스 모두 올 수 있습니다.

 

[  Views/Home/Privacy.cshtml 파일 소스 예제]

@{
    ViewData["Title"] = "Privacy Policy";
    @model int? 
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy. Route</p>
@if (Model != null)
{
    <p>받은값: @Model</p>
}

 

가령 위와 같이 넘어가는 페이지 상단에서 @model <받아온 모델의 자료형> 을 하게되면 model 또는 model.속성 으로 자료형을 뷰에서도 자유롭게 사용할 수 있습니다.

 

4. 2번과 3번의 구분

2번에 string 값을 넣었어서 다른 페이지로 이동했고 3번에 모델을 넣어서 페이지로 이동하며 모델을 가져갔는데, string으로 반환하면 사실 두개가 겹치는 것은 아닌지?

 

Controller 추상 클래스 설명입니다.

 

이 구성을 보시면 string으로 반환하게 되면 viewName으로 인식합니다.

 

모델을 반환하고 싶을때 위에 따른 기본적인 방법은  string이 아닌 return View((object)"메시지 문자열"); 형태로 object 캐스팅을 하는 것입니다. 다른 방법은 named parameter를 사용하는 것입니다. named parameter라는 용어를 asp.net core에서도 사용하는지 모르겠네요. 아래와 같이 View(model: 모델); 로 반환해줍니다.

[HttpGet]
    public IActionResult Privacy()
    {
        return View(model: "모델입니다.");
    }

 

 

5. 기본적으로 매핑되는 뷰 말고 다른 페이지를 열면서 모델도 반환하고 싶을때는 View(뷰경로, 모델)을 반환합니다.

return View("Orders", Orders);

 

 

6. 모델을 뷰로 전달하는 방법은 모델 반환 외에도 있습니다. ViewData와 ViewBag입니다. 간단히 예제로 남기겠습니다.

 

먼저 ViewData입니다.

public IActionResult SomeAction()
{
    ViewData["Greeting"] = "Hi";
    ViewData["Address"]  = new Address()
    {
        Name = "Pichen",
        Street = "456 Street",
        City = "Seoul",
        PostalCode = "12345"
    };

    return View();
}

 

뷰에서는 아래와 같이 받습니다. object로 넘어가기 때문에 Address로 casting 해줘서 받고 활용할 수 있습니다. 

@{
    var address = ViewData["Address"] as Address;
}

@ViewData["Greeting"] World!

<address>
    @address.Name<br>
    @address.Street<br>
    @address.City @address.PostalCode
</address>

 

 

다음은 ViewBag입니다.

 

 

public IActionResult SomeAction()
{
    ViewBag.Greeting = "Hi";
    ViewBag.Address  = new Address()
    {
        Name = "Pichen",
        Street = "456 Street",
        City = "Seoul",
        PostalCode = "12345"
    };

    return View();
}​
@ViewBag.Greeting World!

<address>
    @ViewBag.address.Name<br>
    @ViewBag.address.Street<br>
    @ViewBag.address.City @ViewBag.address.PostalCode
</address>

 

ViewData와 ViewBag은 동시에 같이 사용하는 것도 당연히 가능합니다.

 

 

오늘을 View()와 모델을 뷰에 전달하는 방법에 대해 알아보았습니다. 액션메소드의 반환값들을 모두 정리할까 싶었는데 분량이 길것같아 나머지는 추후 포스트에서 다루겠습니다.

 

 

반응형
반응형

docker라 카테고리를 고민하다가 결국 도커 위에 있는 "DB"를 다루는 것이고 도커명령어는 몇 줄 없어서 DB에 올립니다.

 

오픈소스 DB에는 My SQL과 PostgreSQL 이 대표적인데, 코끼리를 더 좋아해서 PostgreSQL을 더 자주 씁니다. 물론 포텐도 이쪽이 더좋은 것같아요. 

 

먼저, 도커 자체도 처음 접한 분들을 위한 안내입니다.

 

0. 도커 데스크탑을 설치하세요. 사용하실 os에 맞게 받으시면 되겠습니다. 도커 데스크탑은 https://www.docker.com/products/docker-desktop/ 에서 다운받으실 수 있습니다.

 

도커 데스크탑을 설치하셨으면 실행해줍니다.

 

그러면 도커 엔진-데몬이 올라오면서 터미널에서 docker 명령어를 칠 수 있게 됩니다. 명령어는 어디서 치느냐, 터미널을 열어줍니다.

 

 

1. 도커 이미지 다운로드

docker run -d \
  --name postgres-container \
  -e POSTGRES_USER=postgres \          # 계정명 지정
  -e POSTGRES_PASSWORD=1234 \
  -e POSTGRES_DB=postgres \ 
  -v pg_data:/var/lib/postgresql/data \
  -p 5432:5432 \
  postgres:16

먼저 \는 원래 한줄로 쳐도되는 것을 굳이 여러줄에 거쳐 쓰기 위해 사용한 것이예요 \n 같은 거라고 보시면됩니다. \없이 한줄로 쓰셔도 됩니다.

a. -d 는 detach mode로 터미널과 분리되서 실행됩니다. 없는 경우에 터미널 종료시 도커가 종료됩니다.

b. -name은 도커 컨테이너의 이름입니다.

c. -e는 환경변수 입니다. 이미지에서 패스워드를 환경변수로 필수 요구하므로 기입합니다. user와 db는 기입하지 않으면 기본값이 postgres입니다.

d. -v은 볼륨입니다. 이미지 상태의 데이터가 도커 컨테이너 구동이 꺼지면 날아갈 수 있기 때문에 물리적 경로에 저장하여 이미지가 사라져도 데이터가 남게됩니다. -v는 지정하지 않을수 있고 그런경우에 도커 이미지를 지울 경우 데이터가 날아갑니다.

e. -p 포트입니다. 호스트포트:컨테이너포트입니다.

f. postgres: 버전입니다.

 

 

 

2. 위 명령어를 치셨다면 다음은 "docker ps" 명령어를 쳐줍니다. -a 옵션을 붙이면 실행하고 있지 않은 이미지도 나옵니다.

 

3. 가장 좌측에 container id를 복사합니다.

 

복사한 내용을 아래 명령어에서 <여기> 자리에 써줍니다.

docker exec it <여기> bash

# 예시
docker exec -it b6b8511efb79 bash

 

 

이제 터미널에서 자유롭게 쿼리를 쏠 준비가 된거예요. "\l" 이라고 먼저 쳐봅시다. database목록이 나오고, 좀 전에 생성한 기본값 postgres가 있죠.

 

그 데이터베이스에 연결해서 그 내부만 보겠습니다. 명령어는 [\c "postgres"] 이고 쌍따움표 안에 것은 위에서 아까 이미지 내려받아 생성한, 위에서 조회한 데이터베이스 이름이예요.

 

[\dt]는 데이터 테이블을 뜻하고, 제가 fast api를 공부하며 간단하게 만든 User테이블과 alembic으로 생성한 버전테이블이 나왔습니다. 

postgres=# \dt
              List of relations
 Schema |      Name       | Type  |  Owner
--------+-----------------+-------+----------
 public | User            | table | postgres
 public | alembic_version | table | postgres
(2 rows)

postgres=#

 

이제 테이블까지 확인했으니 간단하게 조회를 해보도록 할까요? 유의사항이 있어 그부분만 설명드리고 CUD는 포스트를 읽으시는 독자분들에게 숙제로 드리도록 하겠습니다.

 

먼저 조회 문에는 반드시 ;를 붙여야 한다는 점이예요. 근데 테이블명에 바짝 붙인 테이블명;말고 테이블명 ; (테이블명과 ; 사이에 띄어쓰기 필수!!) 안쓰면 조회가 안되거나 에러가 나더라구요. 실습 삼아 쳐보셔도 좋을 것 같아요.

 

두번째는 postgresql에 대한 이해도가 얕을때는 테이블명에 ""를 반드시 사용해라 입니다. ""를 사용하지 않으면 기본적으로 모두 소문자 처리는데 기본테이블과 겹치는 경우 예기치 않은 결과값이 나올 수 있습니다. 아래 쿼리를 보시면 user는 시스템 테이블에서 db로그인가능한 계정목록이 나옵니다. 아까 생성하실때 보셨겠지만 기본값인 postgres가 아래에서 조회된 것이구요. ""쌍따움표를 붙인 실제값이 마지막에 보이는 것이예요.

postgres=# select * from user
postgres-# select * from user;
ERROR:  syntax error at or near "select"
LINE 2: select * from user;
        ^
postgres=# select * from user ;
   user
----------
 postgres
(1 row)

postgres=# select * from "User" ;
             id             |  name  |         email         |                           password                           |         created_at         |         updated_at         | memo
----------------------------+--------+-----------------------+--------------------------------------------------------------+----------------------------+----------------------------+------
 01K36BTG6REPPHCDSW4SQJZV1Q | dddd | dddd@dmail.com | $2b$12$sRXbvBISkSty.TD2ghTlZOuNTzqiog15Wh7Gns94nnkY.xCOsa7uW | 2025-08-21 22:06:51.736949 | 2025-08-21 22:06:51.736949 |
(1 row)

 

간단하게 명령어로 도커에 db이미지를 올리고 조회까지 해보았습니다. 

 

P.S. 도커를 다시실행하게되면 docker이미지를 삭제한 것이 아니라면 docker run ~ 명령어는 하실 필요없이 docker exec -it 명령어 치시면됩니다. 애매하면 docker ps -a를 먼저 쳐보세요. 그리고 도커 이미지를 저장하는 명령어도 있는데 도커 자체 포스트는 아니기 때문에 나중에 다루겠습니다. 

반응형

'Common > DB' 카테고리의 다른 글

[open source / airbyte] sql server 연결 테스트  (0) 2024.08.14
반응형

백엔드에 라우팅 방식에는 HTTP Method의 한정이 필요하겠죠. 생각나는 이유에는 일단 두가지가 있네요. 첫째는 허용하지 않은 Method의 진입을 차단하는 것. 그리고 같은 라우트라도 메소드별로 다른 기능을 타기 위해서입니다. 1편에서 다루었던 Route 속성 방식은 모든 메소드로 진입이 가능해서 http method에 따라 결과가 바뀌지 않는 상황에는 쓸 수 있겠지만 RESTful하려면 get, post, patch, put, delete 등을 나눠서 같은 경로로 라우팅하는 것이 중요할 수 있고, 보안 등 여러 측면을 고려해서도 진입경로를 최소화하는 것이 좋을 것입니다. 그렇다면 어떻게 http method를 한정할 수 있는지 보여드리도록 하겠습니다.

 

 

먼저 Convention-based가 아니기 때문에 controller에도 Route를 걸어줄 것입니다. 라우트 경로에 [controller]라고 쓰게되면 해당부분에 클래스명 중 Controller 앞부분을 가져옵니다. 만약에 controller 클래스의 이름이 Controller로 끝나지 않는다면 클래스명 자체를 라우트 경로에 가져옵니다.

 

아래 스크린샷예제에서는 컨트롤러 이름이 RouteController이기 때문에 Route까지만 라우팅되겠습니다.

 

1편에서 사용했던 Route속성 과 함께 허용할 Http Method만 써주면됩니다. 위 예제에서는 Get방식만 허용해주었습니다. 결과는 아래와 같이 나옵니다. 

 

post방식으로 호출이 안되는지 살펴볼까요? postman으로 확인해보겠습니다. post방식을 살펴보기에 앞서 get방식은 어떻게 표출되는지 먼저 보여드리겠습니다.

 

아래 스크린샷은 포스트맨에서 get방식으로 호출한 예제입니다. 주소를 복사 붙여넣기 하는 과정에서 한글부분은 자동으로 url에서 읽을 수 있도록 유니코드 형식으로 변환됐구요. 아래 result 중에서도 html 코드를 세세히 봐야 같은 페이지인지 아실 것 같아서 Preview로 보여드렸습니다.

 

 

get방식은 잘 되네요. post 방식으로 요청해볼까요? 상단 네모박스보시면 post로 요청된 것을 확인하실 수 있고, 결과는 405 입니다. Method Not Allowed죠.

 

두개 이상의 http method를 허용하려면 단순히 속성하나를 더붙이면 됩니다.

 

 

[HttpPost]
[HttpGet]
[Route("내가만든/액션경로")]
public IActionResult Privacy()
{
    return View();
}

 

이제 post 방식으로도 접근이 가능합니다.

 

또는 

아래와 같이 httpPost, HttpGet 속성 대신에 AcceptVerbs 속성을 이용하는 방법도 있습니다.

//[HttpPost]
//[HttpGet]
[AcceptVerbs("GET", "POST")]

 

 

 

 

Http Method를 한정하는 라우트방식은 스프링에서도 route같은 애너테이션이 있고, httpget에 바로 라우트경로를 붙여주는 애너테이션도 있는데요, asp.net core에서도 마찬가지 방식도 가능하답니다. 여태까지 진행 했던 다른 속성은 주석처리 하고 HttpGet("라우팅 경로") 방식으로 작성하면 됩니다.

//[HttpPost]
[HttpGet("privacy-get")]
//[AcceptVerbs("GET", "POST")]
//[Route("내가만든/액션경로")]
public IActionResult Privacy()
{
    return View();
}

 

RESTful 하게 만드려면 아래와 같이 조회하는 경로와, 추가, 삭제하는 경로가 같으면서도 뒤에 변수만 차이가 있으면 이쁘게나오겠죠. 근데 여기서는 기본 템플릿으로 간단예제를 구현하느라 FindbyId로 get에서 변수받기, post 방식을 request body form으로 받아오기까지는 하지 않고, 복습차원에서 privacy라는 asp.net core의 기본 페이지 이기 때문에 static 변수 하나를 선언해서 /route/privacy/숫자 에서 숫자를 누적시켜보도록하겠습니다.

[Route("[controller]")]
public class RouteController(ILogger<RouteController> logger) : Controller
{  
    private readonly ILogger<RouteController> _logger = logger;
    private static int _sum = 0;

    public IActionResult Index(int? id)
    {
        return View(id);
    }

    [HttpGet("[action]")]
    public IActionResult Privacy()
    {
        return View();
    }

    [HttpGet("Privacy/{id}")]
    public IActionResult AddPrivacy(int? id)
    {
        if (id != null)
            _sum = _sum + (int)id;
        return View(_sum);
    }
}

 

위와 같이 개발했을때는 AddPrivacy에 매핑되는 Views/Route/AddPrivacy.cshtml을 생성해야합니다. 만약에 기본적인 웹파일경로와 다른 위치에 파일을 생성하려면 View("~/Views/지정경로")로 작성하시면 되겠습니다. 저같은 경우는 asp.net core에 기본적으로 생성되어있던 privacy를 복사해다가 Views/Route/AddPrivacy.cshtml로 만든 뒤 RouteController의 sum 값을 표출되도록 하였습니다.

 

브라우저 접근은 기본적으로 get방식이므로 /route/privacy는 접속이 잘되고,

이 라우팅 경로를 postman에서 post로 호출하면 405에러가 나오는 것을 확인하실 수 있습니다.

 

 

 

반대로, post 방식으로 라우팅했던 /route/privacy/{id} 경로는 브라우저에서 405에러가 납니다.

 

postman으로 post방식으로 호출해보면 잘 나오는 것을 알 수 있습니다. 1을 입력하고 9를 입력해볼텐데요. 누적합산 방식으로 받은값에 10이 나와있으면 결과는 성공입니다. 먼저 1입력.

 

결과가 10으로 잘된 것을 확인하실 수 있습니다.

반응형
반응형

이번 포스트에서도 asp.net core MVC의 라우트방식에 대해서 설명드릴텐데요. 지난 포스트에서는 기본으로 설정되어있는 라우트 방식인 Convention-based Routing에 대해서 다뤄봤었구요. 이번 포스트에서는 라우트를 커스텀하게 지정할 수 있는 Attribute Routing에 대해서 알아보겠습니다.

 

asp.net core에서 Attribute를 알고 계신가요? 일단 모르시더라도 어떤 형태인지만 보여드리고 넘어갈게요. 그것자체가 아주 커다란 카테고리이기 때문에 본문이 지나치게 길어질 것 같아서요. 자바를 하신적이 있으시다면 스프링에서 애너테이션과 유사한 역할인데 개념자체는 지금 글에서는 모르셔도 무방합니다.

위 이미지에서 [HttpGet]이라고 적힌 부분이 보이시죠? 지금 알고 계셔야하는 부분은 .net에서 함수 위에 대괄호로 [] 쓸 수 있는 것이 Attribute라는 것 뿐이예요. Attribute는 http에 연관된 것 뿐아니라 액션필터 등 메소드 진입 후에 통과될 로직을 작성하고 적용할 수도 있답니다. 자세한건 따로 찾아보시거나 아주 추후에 올리도록 하겠습니다.

 

 

 

Attribute Routing이라고하면, Controller의 Action Method 위에 attribute형태로 작성 지정한 경로로 라우팅을 가능하게 하는 방식이예요.

 

바로 예제로 들어가볼게요. 지난 글에서 설명드린 Convention-based Routing 방식으로 asp.net core mvc의 기본 템플릿 내에서 localhost:<port>/Home/Privacy 라는 페이지가 있어요. 이 부분을 복사해다가 경로를 변경해볼거예요. 먼저 이 페이지를 복사해다가 Route/Privacy에 위 페이지를 만들어볼게요. Views폴더의 Home폴더 내부의 파일들도 Views폴더 내에 Route (controller 앞부분과 동일하게) 라는 폴더를 생성하고 그아래 복사해주세요.

public class RouteController(ILogger<RouteController> logger) : Controller
{  
    private readonly ILogger<RouteController> _logger = logger;

    public IActionResult Index(int? id)
    {
        return View(id);
    }

    public IActionResult Privacy()
    {
        return View();
    }


    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()
    {
        return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }
}

 

 

그러면 이제 localhost:<port>/route/privacy 경로에 페이지가 보일꺼예요. 

 

간단하게 라우팅 경로를 "내가만든액션경로" 라고 하겠습니다. Attribute의 이름은 Route이고 변수를 string형태로 주시면 됩니다.

[Route("내가만든액션경로")]
public IActionResult Privacy()
{
    return View();
}

아주 쉽죠?

 

액션 메소드별로 경로를 바꿀 수 있는건 좋은데, 2단, 3단경로를 만들고 싶은데요? 라는 의문이 생기실 수 있어요. 간단합니다. route attribute에 그대로 추가하면돼요. "내가만든/액션경로"

 

[Route("내가만든/액션경로")]
public IActionResult Privacy()
{
    return View();
}

 

이것도 참 쉽죠? 

 

여러 경로를 일일히 컨트롤러의 메소드마다 집어넣는것은 너무 번거롭지 않냐는 생각이 드실 수 있어요. asp.net core에서 컨트롤러 자체에도 Route속성을 지원합니다. 컨트롤러에는 [Route("내가컨트롤러다이말이야")]를 붙이고 실행하겠습니다. 결과부터 말씀드리면 "localhost:<port>/내가컨트롤러다이말이야/내가만든/액션경로" 에서 해당페이지에 진입하게 됩니다.

 

 

 

그런데 여기서, controller에 전체적으로 경로 지정하고 싶긴했는데 한두개의 메소드에는 예외적으로 다른 경로를 쓰고 싶을 수 있죠. 결론 먼저 말씀드리면 가능합니다. 우리 개발자들이라면 다 아는 절대경로와 상대경로가 있죠. controller와 method에 둘다 route속성이 있는 경우에 method 부에 상대경로를 기입하면 <웹주소>/<controller의 라우트경로>/<메소드의 라우트경로> 가 되고 method부에 절대경로를 기입하게 되면 <웹주소>/ <메소드의 라우트경로> 가 됩니다.

 

 

아래는 절대경로 예제입니다. 절대경로임을 강조하기 위해 경로 앞 / 부분만 표시해두었습니다.

 

 

결과는 다음과 같죠.

 

여기서 주의하실점은 method 부분의 route경로의 절대/상대경로는 controller부분에 route attribute가 있을때만 성립한다는 점이예요. controller가 route가 없으면 <웹주소>/ 다음에 적을것이 따로 없기 때문에 무조건 웹주소/<메소드의 route경로>가 됩니다. 여기서 헷깔리시는 분들은 기본패턴이 존재했던 convention-base routing 방식과 혼동이 오셔서 그럴텐데, 메소드에 라우트를 입력하는 순간 convention-base routing이 아니게 됩니다.

 

정리해드리겠습니다.

 

아래 표에서 *O는 있음, X는 없음

controller에서 route attribute method에서 route attribute 결과
x x Convention-base attribute로 별도의 설정 수정이 없다면
<server-url>:<port>/{controller}/{action}를 따름
x o method의 route 경로를 따름
<server-url>:<port>/{method의 route경로}

o x 404 에러 발생.
controller에서 라우트 어트리뷰트를 작성한 순간 convention-base attribute의 영향을 받지 않고, 액션 메소드의 경로가 지정되지 않아 라우팅되지 않음
o o <server-url>:<port>/{controller의 route경로}/{method의 라우트경로}

 

이상으로 지난 글에 이어 라우트 방식 두가지에 대해서 알아보았습니다. 

 

감사합니다.

반응형
반응형

이번 포스트에서는 ASP.NET Core MVC에서 라우트 방식에 대해 설명드리겠습니다.

웹을 만들때 어떤 url에 들어갔을때 어떤 페이지를 열리게 할 것이냐에 대한 내용입니다.

 

ASP.NET core MVC에서는 기본적인 라우트 방식이 있습니다. 제가 기본적인 라우트 방식이라고 부른 방식은 asp.net core mvc 프로젝트의 program.cs 내부에 적혀 있습니다.

이 기본 라우트 방식의 pattern을 보시면 controller / action / id? 라고 적혀있죠? 

 

 

이는 각각 controller 클래스의 앞부분, action은 컨트롤러 내 함수의 이름, id는 id라는 변수가 있다면 그것을 나타냅니다.  또한pattern: "{controller=Home}/{action=Index}/{id?}" 이라는 부분에서 = 뒤에 나오는 값은, 해당 위치에 아무것도 없을때 표기할 패턴을 말합니다. 가령, localhost:5000으로 웹을 구동했다고 가정했을때 브라우저에서 localhost:5000로 진입하면, 이 웹 애플리케이션이 자동으로 localhost:5000/Home/Index로 진입하게 됩니다.

 

말로만 하면 무슨 말인지 모르시겠죠? 아래에서 간략하게 소스를 보면서 설명드리겠습니다.

 

 

바로 위 이미지에서 controller클래스의 앞부분이라고 말씀드렸던 "Home"이 패턴에서 {controller}에 해당하는 부분입니다. 그리고 빨간색 네모로 표시해둔 상자 중 아래 것의 부분인  HomeController() 내에 존재하는 Index()함수가 보이시죠? 함수명인 Index가 action 부분입니다. 따라서 브라우저 주소창에 http://localhost:5208/Home/Index를 입력하게 된다면 HomeController() 내에 있는 Index()함수가 호출하는 뷰를 볼 수 있게 되는 것이지요. 여기서는 반환값이 View()이기 때문에 프로젝트 내 폴더구조에서 Views/Home/Index.cshtml을 보게됩니다.

 

여기서, 프로젝트를 생성하고 빌드하신 분들은 사실 localhost:<port>를 입력했을때도 이 화면을 보셨을꺼예요.

 

이게 아까 설명드렸던 뒤에 나오는 값은, 아무것도 없을때 표기할 패턴입니다.  pattern: "{controller=Home}/{action=Index}/{id?}" 에서 localhost:<port> 뒤에 아무것도 없을 때는 Home/Index가 되도록 기본값이 지정되어 있죠. 마찬가지 원리로 localhost:<port>:Home 까지만 치더라도 같은 화면이 표출됩니다.

 

독자분들은 하나의 궁금증이 머릿속에 있으실꺼예요. 컨트롤러 라우트 패턴에 id도 있었는데 id가 어디갔나요? 라고 말이죠.

패턴에 보시면 id뒤에는 ?이 표기되어있죠? c#을 공부한 상태시라면 감은 오실꺼예요. ?은 nullable이라는 것을! 따라서 값이 없어도 됐던 것이죠. 지금은 id를 붙이더라도 설명드렸던대로의 원리로 동일한 화면이 나옵니다.

 

 

 

id값을 인식해서 뭔가 변화를 주고싶다면? 아래와 같이 아주 간단하게 보여드리겠습니다.

 

먼저 id를 받을 수 있도록 Index()에 자료형과 변수를 기입합니다. 변수명은 반드시 패턴과 매핑이 되는 id여야 합니다. id로 기입하지 않아도 받을 방법이 있지만 오늘 포스팅에서 다룰내용은 아니었어서 Route 중급편 정도에서 다루도록 하겠습니다.

 

그리고 뷰에 해당값이 전달될 수 있도록 모델을 반환해줍니다. 여기서는 id값만 전달하면 되므로 별도 클래스의 인스턴스나 컬렉션으로가 아닌 id자체를 반환해줍니다.

 

// HomeController 내 Index()

public IActionResult Index(int? id)
{
    return View(id);
}

 

Controller 에서 View로 반환했기 때문에 뷰쪽에서 Home/Index.cshtml을 찾습니다. Views폴더 내부에서 패턴형식에 맞게 {controller}/{Action}.cshtml를 찾으면 된다고 생각하시면 되겠습니다.

 

아래 소스이미지는 asp.net core MVC의 기본 템플릿에서 빨간 부분을 추가하여 표시한 것입니다.  컨트롤러에서 반환한 Model의 자료형은 int? 였기 때문에 상단의 @{} 문에서 @model을 자료형으로 선언한 뒤 본문에서 Model 변수로 사용하면 되겠습니다. 없을때도 있으므로 null이 아닐때만 표기하도록 하겠습니다.

 

결과는 아래와 같습니다. id값이 null이 아닐때만 표기하도록 개발한 것이라 localhost:<port>만 입력했을때는 이전에 보여드렸던 화면과 동일합니다.

 

이상으로 .net6.0이상의 core mvc 프로젝트에서 기본적으로 세팅되어있는 라우트 방식에 대해 알아보았습니다. 더많은 내용을 담으려는 생각도 있었는데 본문이 이미 너무 긴 것 같아 라우트 커스터마이징, id말고 다른변수 사용하기, 쿼리스트링에서 변수받아오기, post 요청시 request body에서 변수받아오기, 컨트롤러에서 view외에도 자주쓰이는 반환 값의 종류 등은 이후 포스팅에서 다루도록 하겠습니다. 감사합니다.

반응형
반응형

 

설계 유연성, 운영 이후의 유지보수성과 확장성까지 고려하면 의존성 주입은 수많은 웹기술에서 필수라고 할 수 있겠습니다.

spring boot에서는 대표적인 방법 중 하나로 @Component 애너테이션 스프링 컨테이너에 등록 후 컴포넌트스캔으로 구현체를 읽어오는 방식이 있는데, 과연 asp.net core 에서는 의존성 주입을 위한 방법에 어떤 것들이 있을까요?

 

asp.net core에서는 DI 컨테이너를 대변하는 IServiceProvider라는 인터페이스가 있습니다. 그리고 실제 컨테이너 그 자체는 아니지만, 등록된 서비스를 관리하는 IServiceCollection라는 인터페이스가 있습니다. 이부분은 소스부터 보고 말씀드리겠습니다.

 

아래와 같이 인삿말을 하는 interface, 구현체가 있다고 가정하겠습니다.

. - interface

public interface IHelloService
{
    public void Hello(string message = "Hello.");
}

 

 - 구현체

public class HelloService(IConfiguration configuration) : IHelloService
{
    private readonly IConfiguration _configuration = configuration;

    public void Hello(string message)
    {
        Console.WriteLine(message);
    }
}

 

asp.net core에서는 설정/등록은 program.cs 에서 거의 모두 처리한다고 보시면 되는데요, program.cs를 열어봅시다.

var builder = WebApplication.CreateBuilder(args);

위와 같이 builder가 선언되어있고, builder 내부에는 다양한 것들이 모두 포함되어있지만 그중에서도 Services 변수는 아까 설명드렸던 IServiceCollection을 구현한  변수로 여기에 DI을 할 구현체를 등록할 수 있습니다.

 

아래와 같이 말이죠.

builder.Services.AddTransient<IHelloService, HelloService>();

 

의존성 주입을 하는 함수는 AddTransient 를 포함하여 총 3가지가 있으며 상황에 맞게 사용하시면 되겠습니다.

 

1. AddTransient

 - 요청할때마다 새로운 인스턴스 생성 -> 상태를 별도로 보관하지 않고(stateless), 가볍게 생성 후 소멸

 

2. AddScoped

 - http request 단위로 동일한 인스턴스 유지 -> 요청 후 응답까지 공유해야하는 변수(필드, 프로퍼티) 등을 같은 인스턴스에서 사용

 

3. AddSingleton

 - 어플리케이션의 시작부터 종료까지 일관된 인스턴스 공유 - 서버 캐싱, 전역 변수 둥 처럼 매요청시마다 공유가 필요한 서비스에 사용

 

 

asp.net core MVC의 Controller에서 사용예제를 보여드리겠습니다.

using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;

// primary constructor
public class HomeController(ILogger<HomeController> logger, IHelloService helloService) : Controller
{
    private readonly ILogger<HomeController> _logger = logger;
    IHelloService _helloService = helloService; 

    public IActionResult Index()
    {
        _helloService.Hello();	// 사용
        return View();
    }

    public IActionResult Privacy()
    {
        return View();
    }

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()
    {
        return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }
}

 

이제 디버그모드로 실행 후 메인 페이지을 열면 Hello 함수가 실행됐음을 알 수 있습니다.

 

 

 

asp.net core에서의 의존성 주입을 알아보았습니다.

 

java lombok의 @RequestArgConstructor 처럼 의존성 주입과 그에 필요한 작성부분이 더 편리하게 쓸 수 있으면 좋았겠는 반면에, program.cs만 보더라도 어떤 구현체가 사용되고 있는지 한눈에 볼 수 있는 장점이 있었던 asp.net core에서의 의존성 주입이었습니다. 

반응형
반응형

오랜만에 작성하네요.

업무에 주는 아니지만 .NET Web을 꽤 사용하고 있는데, 원래 스프링 웹개발 부터 시작했다보니 스프링부트와 asp.net core mvc간에 유사점이 많아서 어느정도 선까지 익히기는 어렵지 않았어요.

 

 

아주 간단한 기본개념 또는 원리 부터 시작해보겠습니다.

 

아래는 .net8.0 환경에서 dotnet new mvc로 생성한 기본 프로젝트의 폴더 내부입니다.

MVC가 모델 뷰 컨트롤러죠. Models, Views, Controllers 폴더에 기본 템플릿으로 하나씩 생성되어있습니다.

 

이중에서 오늘은 appsettings.json, appsettings.Development.json에 대해서 다뤄볼꺼예요.

 

appsettings.json, appsettings.Development.json  이 두개의 파일은 설정파일입니다.

기본적으로 ide 등에서 디버그모드로 실행하는 경우에는 appsettings.Development.json을 읽고 빌드 후 사용하게 되면 appsettings.json을 읽습니다.

 

이제 본격적으로 설정파일을 읽고 프로젝트 소스 내에서 사용하는방법을 다루도록 하겠습니다.

 

설정 파일 내 값들은 program.cs에서는 아래 json의 value 값을 가져오기 위해서 다음과 같이 사용하실 수 있습니다. 제네릭은 입력한 값의 형태에 맞게 사용하시면 되겠습니다.

(appsettings.json 내 구조, 사용소스 순으로 본문 내 다른부분에서도 작성하겠습니다.)

{
	"key": "value"
}
builder.Configuration.GetValue<string>("key")

 

형태로도 불러올 수 있고, json파일 내에서 한 키값 내에 여러 값을 집어넣고, 그와 매핑되는 클래스를 만들어서 클래스의 인스턴스로 바인딩도 가능합니다.

{
	"MyConfig": {
      	"Config1": 1,
        "Config2": "1"
    }
}
public class MyConfig {
	public int config2 {get; set;}
	public string? config2 {get; set;}
}

var myConfig = builder.Configuration
    .GetSection("MyConfig")
    .Get<MyConfig>();

 

 

다음은 Controller 등의 다른 클래스에서 사용방법 입니다.

 

클래스의 속성으로 private readonly IConfiguration _configuration;를 추가 후 생성자에도 추가해줍니다.

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly IConfiguration _configuration;

    public HomeController(ILogger<HomeController> logger, IConfiguration configuration)
    {
        _logger = logger;
        _configuration = configuration;
    }
}

 

그 다음 컨트롤러의 메소드 내부에서 다음과 같이 사용하시면 되겠습니다.

{
	"key": "value"
}
string? key = _configuration["key"];

 

json 내부가 2단 이상의 구조라면 다음과 같이 사용하실 수 있습니다.

{
	"MyConfig": {
      	"Config1": 1,
        "Config2": "1"
    }
}
string? MyConfig2 = _configuration["MyConfig:Config2"];

 

 

 

마지막으로 section을 바인딩한 클래스로 사용하는 방법입니다.

Program.cs 파일을 아래와 같이 수정합니다.

var builder = WebApplication.CreateBuilder(args); 
// Program.cs 내 윗 부분 바로 아래 쯤에 아래 코드를 삽입합니다.

// MyConfig 섹션을 MyConfig 클래스로 바인딩하여 DI 컨테이너에 등록
builder.Services.Configure<MyConfig>(
    builder.Configuration.GetSection("MyConfig")
);

 

Program.cs에서 DI 컨테이너에 등록한 MyConfig클래스 Configure를 Controller에서 의존성을 주입하기 위해 private readonly로 선언 후 생성자에서 넣어줍니다.

using Microsoft.Extensions.Options;

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly MyConfig _myConfig;

    public HomeController(ILogger<HomeController> logger, IOptions<MyConfig> options)
    {
        _logger = logger;
        _myConfig = options.Value;
    }
}

 

이제 메소드 내에서 _myConfig.Config1 과 같이 사용이 가능해집니다.

 

 

오늘은 .net 6.0이상의 asp.net core mvc에서 설정파일 사용하는 방법을 알아보았습니다.

이전에 Serilog.AspNetCore 와 결합하면 의존성 주입으로 설정파일과 로그작성을 자유롭게 하시게 되었겠네요!

 

다음글에서는 controller와 viewer의 관계에 대해서 다룰까합니다.

감사합니다.

반응형

+ Recent posts