ASP.NET Minimal API 및 MongoDB 저장소를 사용하여 React 기반 앱 만들기

저는 한동안 React를 .NET과 혼합하고 많이 즐겨 사용했습니다. 이 게시물에서는 Compose 컨테이너, ASP.NET Minimal API 및 MongoDB 지원과 함께 이들을 결합하기로 결정했습니다!

This post is also available from my blog: https://stvansolano.github.io/blog/



반응 사용



저는 클라이언트 및 서버 측 렌더링을 위해 내 블로그(대부분 ~2015년경에 있었던 기존 코드에서 최근에 마이그레이션한 NodeJS/Jamstack 클라이언트 측에서 생성됨) 뒤에 있는 기술인 React를 사용합니다.

그래서 이번에는 샘플 앱에서 React와 .NET을 결합하는 샘플을 설정하기로 결정하고 이전에 했던 것과 동일한 구조에 따라 GitHub의 Docker에서 #248 리포지토리에 대해 Pull-RequestAwesome-Compose로 패키징했습니다. 해당 리포지토리에 대한 .NET 기여. Awesome-Compose에 대한 이전 게시물에 관심이 있거나 Docker-izing .NET 5/6 앱에 대해 궁금하거나 개발을 위해 GitHub Codespaces를 사용하는 경우 및 에서 검색할 수 있습니다.

이 게시물의 코드는 이 리포지토리의 내 GitHub에서도 사용할 수 있습니다.

https://github.com/stvansolano/codebox-react-dotnet-mongodb

자, 시작하겠습니다! 설치해야 할 몇 가지 사항:
  • 도커 작성
  • .NET 6 SDK
  • 노드JS

  • Side-note: I didn't really have to install anything while developing this on my local as I was using GitHub Codespaces with my some tailored devcontainer setup, so I can focus on development!





    1) /frontend 만들기: 간단한 TODO 앱입니다.



    이 샘플에서는 기본 앱을 만드는 데 react-scripts 스캐폴드를 사용하고 JavaScript, NodeJS/Npx 항목에 집중하기 위해 TODO 앱을 갖는 데 매우 간단하면서도 여전히 고전적인 샘플을 사용합니다. 이 샘플의 경우 Awesome-Compose 저장소에서 재사용한 일부 파일도 포함되어 있습니다.



    나중에 ASP.NET에서 API를 사용하기 위해 나중에 ASP.NET 웹 API에서 API 호출을 처리하기 위해 NGINX 파일을 추가해 보겠습니다. 사물은 자체 NGINX 기반 컨테이너에서 실행되므로 여기에서 백엔드가 분리됩니다.
       
    server {
        listen       80;
        server_name  localhost;
        
        server_tokens off;
        proxy_hide_header X-Powered-By;
        proxy_hide_header Server;
        add_header X-XSS-Protection "1; mode=block";
        add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';
        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;
        add_header X-Permitted-Cross-Domain-Policies master-only;
        add_header Referrer-Policy same-origin;
        add_header Expect-CT 'max-age=60';
        
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
            try_files $uri $uri/ /index.html;
        }
    
        location /api {
            proxy_set_header  Host $host;
            proxy_set_header  X-Real-IP $remote_addr;
            proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header  X-Forwarded-Host $server_name;
            proxy_pass        http://backend:8000;
            proxy_redirect    default;
        }
    }
     
    

    Important: The .NET CLI and also Visual Studio provide a great set of pre-defined templates that also include React, Angular and more great stuff, which I encourage to give it a try. Also, pretty much of this tutorial can be also take .NET on the frontend, with the help of amazing Blazor 💖✨



    2) 이제 /backend에서 .NET을 사용할 시간입니다. MongoDB용 최소 API 설정



    여기서 일이 더 흥미로워집니다. .NET 6에서 새로운 웹 API를 스캐폴딩함으로써 MongoDB 컬렉션을 호출하고 API에 대한 몇 가지 기본 작업을 지원하는 매우 간단하고 작은 프로그램을 구현할 수 있으며 몇 줄의 코드로 Swagger+OpenAPI 지원을 추가할 수 있습니다.
       
    using System;
    using System.Linq;
    using System.Threading.Tasks;
    using MongoDB.Bson;
    using MongoDB.Bson.Serialization.Attributes;
    using MongoDB.Driver;
    using Models;
    using Swashbuckle.AspNetCore.SwaggerGen;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();
    
    string connectionString = builder.Configuration.GetConnectionString("DocumentDbConnection");
    string databaseName = builder.Configuration.GetConnectionString("DocumentDbName") ?? "BackendMongoDb";
    string collectionName = builder.Configuration.GetConnectionString("DocumentCollectionName") ?? "ToDos";
    
    builder.Services.AddTransient((_provider) => new MongoClient(connectionString));
    
    var app = builder.Build();
    
    var isSwaggerEnabledFromConfig = bool.TrueString.Equals(builder.Configuration["EnableSwagger"] ?? "", StringComparison.OrdinalIgnoreCase);
    if (isSwaggerEnabledFromConfig) 
    {
        Console.WriteLine("Swagger enabled via appsettings.json");
    }
    
    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment() || isSwaggerEnabledFromConfig)
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    
    app.MapGet("/api/todos", async (MongoClient connection) =>
    {
        try
        {
            var database = connection.GetDatabase(databaseName);
            var collection = database.GetCollection(collectionName);
            var results = await collection.Find(_ => true).ToListAsync().ConfigureAwait(false);
    
            return Results.Ok(results);
        }
        catch (Exception ex)
        {
            return Results.Problem(detail: ex.ToString());
        }
    });
    
    app.MapGet("/api/todos/{id}", async (string id, MongoClient connection) =>
    {
        try
        {
            var database = connection.GetDatabase(databaseName);
            var collection = database.GetCollection(collectionName);
            var result = await collection.FindAsync(record => record.Id == id).ConfigureAwait(false) as ToDo;
            
            if (result is null) 
            {
                return Results.NotFound();
            }
    
            return Results.Created($"/todoitems/{result.Id}", result);
        }
        catch (Exception ex)
        {
            return Results.Problem(detail: ex.ToString());
        }
    });
    
    app.MapPost("/api/todos", async (ToDo record, MongoClient connection) =>
    {
        try
        {
            var database = connection.GetDatabase(databaseName);
            var collection = database.GetCollection(collectionName);
            await collection.InsertOneAsync(record).ConfigureAwait(false);
    
            return Results.Created($"/api/todos/{record.Id}", record);
        }
        catch (Exception ex)
        {
            return Results.Problem(detail: ex.ToString());
        }
    });
    
    app.Run();
       
    

    다음은/swagger 엔드포인트를 열 때 백엔드의 스크린샷입니다.



    3) 오! 네, 몽고DB입니다. 작성하고 .NET으로 마무리합시다!



    마지막으로 프론트엔드를 준비하고 백엔드에 연결하고 MongoDB에 To-Dos를 저장합시다.

    여기에서 컨테이너 이미지를 가져오고 설정하기만 하면 Compose 서비스를 사용할 수 있습니다.
       
     services:
      frontend:
        build:
          context: frontend
        ports:
          - 80:80
        volumes:
          - '.:/app'
          - '/app/node_modules'
        networks:
          - react-frontend
        depends_on:
          - backend
        links:
          - backend
    
      backend:
        build: backend
        restart: always
        ports:
          - 8000:8000
        depends_on: 
          - mongo
        links:
          - mongo
        environment:
          - ASPNETCORE_URLS=http://+:8000
          - EnableSwagger=true
        networks:
          - react-backend
          - react-frontend
    
      mongo:
        restart: always
        image: mongo:4.2.0
        volumes:
          - ./data:/data/db
        networks:
          - react-backend
    
      mongo-express:
        image: mongo-express
        restart: always
        ports:
          - 8081:8081
        environment:
          ME_CONFIG_MONGODB_ADMINUSERNAME: root
          ME_CONFIG_MONGODB_ADMINPASSWORD: example
        depends_on: 
          - mongo
        links:
          - mongo
        networks:
          - react-backend
    
    networks:
      react-backend: {}
      react-frontend: {} 
       
    

    Compose 파일에는 Compose 파일에 Mongo-Express 서버도 포함되어 있으므로 NoSQL 문서를 빠르게 탐색하고 React의 UI에서 모든 것을 .NET으로 생성된 Swagger 문서에서 엔드 투 엔드로 확인할 수 있습니다.

    보너스 팁: CosmosDB는 즉시 지원됩니다!



    우리는 MongoDB 커넥터를 지원하는 Azure CosmosDB를 사용할 수 있으므로 CosmosDB를 사용하기 위해 바닐라 MongoDB에서 설정 및 교체가 매우 쉽습니다. 여기에 추가 샘플과 함께 참조할 수 있는 몇 가지 링크가 포함되어 있습니다.
  • https://docs.microsoft.com/en-us/azure/cosmos-db/mongodb/connect-using-mongoose/
  • https://docs.microsoft.com/en-us/azure/cosmos-db/mongodb/mongodb-introduction/
  • https://devblogs.microsoft.com/cosmosdb/build-a-node-js-app-with-azure-cosmos-dbs-api-for-mongodb/

  • 즐거운 코딩하세요!

    좋은 웹페이지 즐겨찾기