위의 페이지를 참고해서 학습했다.
.NET 진영에는 이름이 비슷해서 헷갈리는 .NET Framework와 .NET Core가 존재한다.
MS는 .NET Core와 .NET Framework를 호환되게 개발할 생각이 없다고 한다. 따라서 둘 중 하나만을 선택해서 사용해야 한다.
선택하는 간단한 기준은 아래와 같다.
- 기존 앱이 .NET Core에서 사용할 수 없는 경우 = .NET Framework
- 아닌 모든 경우 = .NET Core
즉 기존에 사용하던 Application이 .NET Framework에서 제작된 것이 아니라면 .NET Core로 새로 만드는 것을 추천한다는 의미이다.
현재 이후 버전에 대한 개발 계획이 없기 때문에 지속적인 업데이트가 필요없는 Application에 적합하다. Core가 나오기 전에 만들어진 윈도우 프로그램과 Web이 보통 Framework에 속한다.
.NET Framework의 약점이었던 크로스 플랫폼을 지원한다. 리눅스, OS X, 윈도우 모든 환경을 지원하고 클라우드, IOT 등 다양한 환경에서 동작이 가능하다.
API | 설명 | Req Body | Res Body |
---|---|---|---|
GET /api/TodoItems | 할 일 모두 가져오기 | 없음 | 전체 할 일 |
GET /api/TodoItems/{id} | ID로 해당 항목 가져오기 | 없음 | 해당 할 일 |
POST /api/TodoItems | 새 항목 추가 | 할 일 내용 | 해당 할 일 |
PUT /api/TodoItems/{id} | 기존 항목 업데이트 | 할 일 내용 | 없음 |
DELETE /api/TodoItems/{id} | 항목 삭제 | 없음 | 없음 |
작동 원리는 아래 그림과 같다.
파일(F)에서 새로 만들기 > 프로젝트 를 선택
API 템플릿을 선택하고 다음을 클릭
프로젝트 이름은 TodoAPI
새 ASP.NET Core 웹 애플리케이션 만들기에서 .NET Core 및 ASP.NET Core 5.0이 선택되었는지 확인
처음에 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"
}
]
하지만 우리가 만들 것은 날씨 API가 아닌 할 일 LIST이다.
"launchUrl": "api/TodoItems",
Model은 Application에서 관리하는 데이터를 나타내는 Class
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
}
}
데이터베이스 컨텍스트는 데이터 모델에 맞게 Entity Framework 기능을 조정하는 주 클래스.
도구 메뉴에서 NuGet 패키지 관리자 > 솔루션용 NuGet 패키지 관리를 선택.
찾아보기(Browse) 탭을 선택한 후, 검색창에 Microsoft.EntityFrameworkCore.InMemory 입력
오른쪽에서 프로젝트를 클릭하고 설치
using Microsoft.EntityFrameworkCore;
namespace TodoApi.Models
{
public class TodoContext : DbContext
{
public TodoContext(DbContextOptions<TodoContext> options)
: base(options)
{
}
public DbSet<TodoItem> TodoItems { get; set; }
}
}
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();
});
}
}
}
// 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);
}
DELETE
웹 호스트를 셋업하고 구동
(어떤 호스트를 사용할지, 어떤 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>();
});
}
}
프로그램 시작 옵션 및 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();
});
}
}
}
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);
}
}
}