[ASP.NET Core] ASP.Net Core 를 활용해서 API 서버 구축하기

Date:     Updated:

카테고리:

태그:

이전 프로젝트에서는 서버사이드 PHP를 사용하여 Http 통신을 하였습니다.

이번에는 ASP.NET Core를 사용하여 API 서버를 만들어서 데이터를 주고 받고 할 수 있도록 만들었습니다.

현재는 동작이되고, CRUD 가 되는 기본적인 상태입니다.

DataBase와 연결

ASP.NET Core에서 DB와 연결하기 위해서는 다음과 같은 세팅을 해줘야 합니다.

appsettings.json

우선, 데이터베이스 서버의 Connection String을 기입합니다.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MySqlServer": "your_database_string"
  }
}

Program.cs

appsettings.json을 기입하였다면, Program.cs 스크립트로 와서 DB 연결 코드를 추가합니다.

해당 코드를 삽입하면, 데이터베이스 서버와 연결이 완료 됩니다 .

builder.Services.AddDbContext<MySqlContext>
    (options => options.UseMySql(builder.Configuration.GetConnectionString("MySqlServer"),
        ServerVersion.AutoDetect(builder.Configuration.GetConnectionString("MySqlServer")))
    );

Model 클래스 만들기

이제 데이터베이스의 테이블과 매핑되는 Model클래스를 만듭니다. 이 클래스는 데이터베이스의 테이블에 있는 컬럼과 같게 만들어야 합니다. 대소문자는 구분하지 않지만, 이름이 다르면 인식하지 못하니 그점을 주의합니다.

🗅 class User

using System.ComponentModel.DataAnnotations;

namespace MyApi.Models
{
    public class User
    {
        [Key]
        public int Id { get; set; }

        [StringLength(255)]
        public  string? UserName { get; set; }

        [Phone]
        public string? phone_number {  get; set; }

        [Range(1,100)]
        public int? Age { get; set; }
    }
}

Context

이제 해당 DB의 Context를 가져와서, 테이블과 매핑합니다. 현재 저는 user 테이블과 test테이블 두가지 테이블을 만들어 놨습니다. 해당 Context 안에 UserTestItem 을 넣어 테이블의 컨텍스트를 만들어 줍니다.

🗅 class MySqlContext

using Microsoft.EntityFrameworkCore;

namespace MyApi.Models
{
    public class MySqlContext:DbContext
    {
        public MySqlContext(DbContextOptions<MySqlContext> options): base(options)
        {

        }
        public DbSet<User> User { get; set; } = null!;
        public DbSet<TestItem> Test { get; set; } = null!;
    }
}

Controller

이제 Controller를 만들어 실제 데이터를 주고받는 로직을 구현합니다.

Controller에서는 일반 Model클래스를 바로 사용하는 것이 아닌, DTO(Data Transfer Object) 를 만들어서, 필요한 정보만 담아서 보냅니다.

🗅 class UserDTO

using System.ComponentModel.DataAnnotations;

namespace MyApi.Models
{
    public class UserDTO
    {

        [Key]
        public int Id { get; set; }

        [StringLength(255)]
        public string? UserName { get; set; }

        [Phone]
        public string? phone_number { get; set; }

        [Range(1, 100)]
        public int? Age { get; set; }
    }
}

DTO를 만들었다면, Controller에 스크립트를 작성합니다.

Restful API에 맞게 Get, Post, Put, Patch, Delte 메서드를 만듭니다.

🗅 class UserController

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace MyApi.Controllers
{
    [Route("api/users")]
    [ApiController]
    public class UserController : ControllerBase
    {
        private readonly MySqlContext context;

        public UserController(MySqlContext context)
        {
            this.context = context;
        }

        [HttpGet]
        public async Task<ActionResult<IEnumerable<UserDTO>>> GetUsers()
        {
            try
            {
                return await context.User.Select(x => ItemToDTO(x)).ToListAsync();
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpGet("{id}")]
        public async Task<ActionResult<UserDTO>> GetUser(int id)
        {
            try
            {
                var user = await context.User.FindAsync(id);

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

                return ItemToDTO(user);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpPut("id")]
        public async Task<IActionResult> PutUser(int id, UserDTO userDTO)
        {

            if (id != userDTO.Id)
            {
                return BadRequest();
            }

            var user = await context.User.FindAsync(id);

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

            user.UserName = userDTO.UserName;
            user.phone_number = userDTO.phone_number;
            user.Age = userDTO.Age;

            try
            {
                await context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
            {
                return NotFound();
            }

            return NoContent();
        }

        [HttpPost]
        public async Task<IActionResult> PostUser(UserDTO userDTO)
        {
            try
            {
                var user = new User
                {
                    UserName = userDTO.UserName,
                    phone_number = userDTO.phone_number,
                    Age = userDTO.Age,
                };

                context.User.Add(user);
                await context.SaveChangesAsync();

                return CreatedAtAction(nameof(GetUser), new { id = user.Id }, ItemToDTO(user));
            }
            catch (Exception ex)
            {
                // 에러가 발생하면 BadRequest 응답을 반환합니다.
                return BadRequest(ex.Message);
            }
        }

        [HttpPatch("{id}")]
        public async Task<ActionResult<UserDTO>> PatchUser(int id, UserDTO userDTO)
        {
            try
            {
                var user = await context.User.FindAsync(id);
                if (user == null)
                {
                    return NotFound();
                }
                user.UserName = userDTO.UserName;
                user.phone_number = userDTO.phone_number;
                user.Age = userDTO.Age;

                await context.SaveChangesAsync();

                return CreatedAtAction(nameof(GetUser), new { id = user.Id }, ItemToDTO(user));
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteTodoItem(int id)
        {
            try
            {

                var user = await context.User.FindAsync(id);
                if (user == null)
                {
                    return NotFound();
                }
                context.User.Remove(user);
                await context.SaveChangesAsync();

                return NoContent();
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }

        }

        private bool TodoItemExists(long id)
        {
            return context.User.Any(e => e.Id == id);
        }

        private static UserDTO ItemToDTO(User todoItem) =>
            new UserDTO()
            {
                Id = todoItem.Id,
                UserName = todoItem.UserName,
                phone_number = todoItem.phone_number,
                Age = todoItem.Age
            };
    }
}

이렇게 하면, Swagger 를 통해 문서화된 API 서버를 만들 수 있습니다.

Swagger API

Unity Client

제가설정한 라우팅 경로로 접근하면 정보를 받을 수 있는지 테스트 하는 Unity Client 코드를 작성하였습니다.

전체코드는 저번에 작성하였던 PHP를 활용한 HTTP 통신 포스팅에 있는 코드와 거의 동일 합니다.

이번에는 Post 코드만 포스팅 하겠습니다.

 //Post == Insert
 public IEnumerator PostTodoItem(TodoItemDTO _item, Action<bool, TodoItemDTO> _action)
 {
     string itemJson = JsonUtility.ToJson(_item);
     byte[] jsonToSend = new UTF8Encoding().GetBytes(itemJson);

     UnityWebRequest request = new UnityWebRequest(url, "POST");
     request.uploadHandler = new UploadHandlerRaw(jsonToSend);
     request.downloadHandler = new DownloadHandlerBuffer();
     request.SetRequestHeader("Content-Type", "application/json");

     yield return request.SendWebRequest();
     try
     {
         if (request.result == UnityWebRequest.Result.ConnectionError ||
             request.result == UnityWebRequest.Result.ProtocolError)
         {
             _action(false, null);
         }
         else
         {
             Debug.Log("Received: " + request.downloadHandler.text);

             JObject jsonResponse = JObject.Parse(request.downloadHandler.text);

             long userID = method.ParseLongOrDefault(jsonResponse["id"].ToString());
             string userName = method.CheckNull(jsonResponse["name"].ToString());
             string isComplete = method.CheckNull(jsonResponse["isComplete"].ToString());

             TodoItemDTO todoItemDTO = new TodoItemDTO(userID, userName, isComplete);

             _action(true, todoItemDTO);
         }
     }
     catch (Exception ex)
     {
         //로깅작업
         _action(false, null);
     }
 }

Post는 내용을 받아 서버에 저장하는 역할을 합니다.

ASP .NET Core 카테고리 내 다른 글 보러가기

댓글 남기기