Day 5 ASP.NET Core Web API

김희윤·2021년 6월 21일
0

POS공부기

목록 보기
5/8

0. 준비

ASP.NET Core로 Web API 만들기 Docs

위의 페이지를 참고해서 학습했다.

1. .NET Core? .NET Framework?

.NET 진영에는 이름이 비슷해서 헷갈리는 .NET Framework와 .NET Core가 존재한다.

MS는 .NET Core와 .NET Framework를 호환되게 개발할 생각이 없다고 한다. 따라서 둘 중 하나만을 선택해서 사용해야 한다.

선택하는 간단한 기준은 아래와 같다.

  • 기존 앱이 .NET Core에서 사용할 수 없는 경우 = .NET Framework
  • 아닌 모든 경우 = .NET Core

즉 기존에 사용하던 Application이 .NET Framework에서 제작된 것이 아니라면 .NET Core로 새로 만드는 것을 추천한다는 의미이다.

1) .NET Framework

현재 이후 버전에 대한 개발 계획이 없기 때문에 지속적인 업데이트가 필요없는 Application에 적합하다. Core가 나오기 전에 만들어진 윈도우 프로그램과 Web이 보통 Framework에 속한다.

2) .NET Core

.NET Framework의 약점이었던 크로스 플랫폼을 지원한다. 리눅스, OS X, 윈도우 모든 환경을 지원하고 클라우드, IOT 등 다양한 환경에서 동작이 가능하다.

2. Web API

1) 개요

  • 아래와 같은 API들을 제작할 것이다.
API설명Req BodyRes Body
GET /api/TodoItems할 일 모두 가져오기없음전체 할 일
GET /api/TodoItems/{id}ID로 해당 항목 가져오기없음해당 할 일
POST /api/TodoItems새 항목 추가할 일 내용해당 할 일
PUT /api/TodoItems/{id}기존 항목 업데이트할 일 내용없음
DELETE /api/TodoItems/{id}항목 삭제없음없음

작동 원리는 아래 그림과 같다.

  • 웹 프로젝트 만들기 (with Visual Studio)
    • 파일(F)에서 새로 만들기 > 프로젝트 를 선택

    • API 템플릿을 선택하고 다음을 클릭

    • 프로젝트 이름은 TodoAPI

    • 새 ASP.NET Core 웹 애플리케이션 만들기에서 .NET CoreASP.NET Core 5.0이 선택되었는지 확인

2) 프로젝트 테스트

  • Ctrl + F5를 눌러 실행한다. 아래 두 창이 뜬다면 모두 Yes를 누른다.

처음에 https://localhost:/WeatherForecast 를 집어넣으면 아래와 비슷한 값이 나온다.

[
    {
        "date": "2019-07-16T19:04:05.7257911-06:00",
        "temperatureC": 52,
        "temperatureF": 125,
        "summary": "Mild"
    },
    {
        "date": "2019-07-17T19:04:05.7258461-06:00",
        "temperatureC": 36,
        "temperatureF": 96,
        "summary": "Warm"
    },
    {
        "date": "2019-07-18T19:04:05.7258467-06:00",
        "temperatureC": 39,
        "temperatureF": 102,
        "summary": "Cool"
    },
    {
        "date": "2019-07-19T19:04:05.7258471-06:00",
        "temperatureC": 10,
        "temperatureF": 49,
        "summary": "Bracing"
    },
    {
        "date": "2019-07-20T19:04:05.7258474-06:00",
        "temperatureC": -1,
        "temperatureF": 31,
        "summary": "Chilly"
    }
]

3) launchUrl 업데이트

하지만 우리가 만들 것은 날씨 API가 아닌 할 일 LIST이다.

  • Properties\launchSettings.json 에서 launchUrl을 변경한다.
"launchUrl": "api/TodoItems",

4) Model Class 추가

Model은 Application에서 관리하는 데이터를 나타내는 Class

  • 솔루션 탐색기에서 프로젝트를 마우스 우클릭해서 추가 > 새 폴더 를 선택한다. 폴더 이름은 Models로 지정.
  • Models 폴더 우클릭해서 추가 > 클래스 선택. 이름은 TodoItem
  • 아래와 같이 코드를 바꾼다
namespace TodoApi.Models
{
    public class TodoItem
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public bool IsComplete { get; set; }
    }
}

5) 데이터베이스 컨텍스트 추가

데이터베이스 컨텍스트는 데이터 모델에 맞게 Entity Framework 기능을 조정하는 주 클래스.

  • 도구 메뉴에서 NuGet 패키지 관리자 > 솔루션용 NuGet 패키지 관리를 선택.

  • 찾아보기(Browse) 탭을 선택한 후, 검색창에 Microsoft.EntityFrameworkCore.InMemory 입력

  • 오른쪽에서 프로젝트를 클릭하고 설치

6) TodoContext 데이터베이스 컨텍스트 추가

  • Models 폴더를 우클릭해서 추가 > 클래스를 선택.
  • Class 이름을 TodoContext로 지정하고 추가를 클릭
  • 아래와 같이 코드를 입력
using Microsoft.EntityFrameworkCore;

namespace TodoApi.Models
{
    public class TodoContext : DbContext
    {
        public TodoContext(DbContextOptions<TodoContext> options)
            : base(options)
        {
        }

        public DbSet<TodoItem> TodoItems { get; set; }
    }
}

7) 데이터베이스 컨텍스트 등록

ASP.NET Core에서는 DB 컨텍스트와 같은 서비스는 DI 컨테이너에 등록해야 한다.

Startup.cs을 업데이트 한다.

// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<TodoContext>(opt =>
                                               opt.UseInMemoryDatabase("TodoList"));
            services.AddControllers();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();
            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}
  • Swagger 호출을 제거
  • 사용되지 않는 using 제거
  • DI 컨테이너에 데이터베이스 컨텍스트 추가
  • 데이터베이스 컨텍스트가 메모리 내 데이터 베이스를 사용하도록 지정

8) 컨트롤러 스캐폴드

  • Controllers 폴더를 우클릭 추가 > 스캐폴드 항목 새로 만들기 선택
  • Entity Framework를 사용하며 동작이 포함된 API 컨트롤러를 선택하고 추가
  • Entity Framework를 사용하며 동작이 포함된 API 컨트롤러 추가 대화 상자에서
    • 모델 클래스TodoItem(TodoApi.Models) 선택
    • 데이터 컨텍스트 클래스에서 TodoContext(TodoApi.Models)를 선택
    • 추가를 선택
  • 만들어진 TodoItemsController.cs 에서 nameof 연산자를 사용하도록 PostTodoItem 업데이트
// POST: api/TodoItems
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

    //return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
    return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}

9) Postman으로 테스트

  • POST

  • GET

  • PUT

  • DELETE


3. 각 파일 분석

1) Program.cs

웹 호스트를 셋업하고 구동
(어떤 호스트를 사용할지, 어떤 Startup class를 사용할지)

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace TodoApi
{
    public class Program
    {	
        public static void Main(string[] args)
        {	
  	# 아래에서 정의한 CreateHostBuilder를 build하고 run 함
            CreateHostBuilder(args).Build().Run();
        }
		
  # Microsoft.Extensions.Hosting.IHostBuilder로 CreateHostBuilder 선언
  # Microsoft.Extensions.Hosting.Host로  default build host에 사용할 Configure를 Startup.cs 파일로 정함.
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

2) Startup.cs

프로그램 시작 옵션 및 DI 서비스 저장

  • Service를 구성하는 ConfigureService 메서드
  • 요청 처리 파이프라인을 만드는 Configure 메서드
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
  	# 선택사항
  	# Configure 메서드 전에 호스트에 의해 호출되어 Services 구성 (구성옵션)
  	# Microsoft.Extensions.DependencyInjection.IserviceCollection
  	# 의존성 주입
        public void ConfigureServices(IServiceCollection services)
        {
  	# TodoApi.Models.TodoContext를 사용해서 DB문법을 정의
            services.AddDbContext<TodoContext>(opt => opt.UseInMemoryDatabase("TodoList"));
  	# Controller를 추가한다	
            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  	# HTTP 요청에 응답하는 방식을 지정할 때 사용
  	# 구성요소를 IApplicationBuilder에 추가하여 구성함
  	# IApplicationBuilder를 Configure 메서드에 사용할 수 있지만 서비스에 등록되지 않음
  	# 호스트가 IApplicationBuilder를 만들고 Configure에 직접 전달
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
  	# 개발자 예외 페이지
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
              
            }
	# HTTPS 리다이렉션
            app.UseHttpsRedirection();
	# 앤드포인트 집합을 확인하고 요청을 기반으로 가장 일치하는 항목을 선택
            app.UseRouting();
	# 인증 및 권한설정
            app.UseAuthorization();
	# 앤드포인트 집합을 설정
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

3) TodoItemsController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi.Controllers
{
  [Route("api/TodoItems")]
  [ApiController]
  public class TodoItemsController : ControllerBase
  {
      private readonly TodoContext _context;

      public TodoItemsController(TodoContext context)
      {
          _context = context;
      }

      // GET: api/TodoItems
      [HttpGet]
	# IEnumerable = 순방향진행
      public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
      {
          return await _context.TodoItems.ToListAsync();
      }

      // GET: api/TodoItems/5
      [HttpGet("{id}")]
      public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
      {
          var todoItem = await _context.TodoItems.FindAsync(id);

          if (todoItem == null)
          {
              return NotFound();
          }

          return todoItem;
      }

      // PUT: api/TodoItems/5
      // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
      [HttpPut("{id}")]
      public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
      {
          if (id != todoItem.Id)
          {
              return BadRequest();
          }

          _context.Entry(todoItem).State = EntityState.Modified;

          try
          {
              await _context.SaveChangesAsync();
          }
          catch (DbUpdateConcurrencyException)
          {
              if (!TodoItemExists(id))
              {
                  return NotFound();
              }
              else
              {
                  throw;
              }
          }

          return NoContent();
      }

      // POST: api/TodoItems
      // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
      [HttpPost]
      public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
      {
          _context.TodoItems.Add(todoItem);
          await _context.SaveChangesAsync();

          return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
      }

      // DELETE: api/TodoItems/5
      [HttpDelete("{id}")]
      public async Task<IActionResult> DeleteTodoItem(long id)
      {
          var todoItem = await _context.TodoItems.FindAsync(id);
          if (todoItem == null)
          {
              return NotFound();
          }

          _context.TodoItems.Remove(todoItem);
          await _context.SaveChangesAsync();

          return NoContent();
      }

      private bool TodoItemExists(long id)
      {
          return _context.TodoItems.Any(e => e.Id == id);
      }
  }
}
profile
블록체인, IOT, 클라우드에 관심이 많은 개발자 지망생

0개의 댓글

관련 채용 정보