マイクロソフトをC .NETコアとMongoDB -パート1


あなたがスペイン語でこの記事を読むことに興味があるならば🇪🇸, ブログ一覧にもどる
The Developer's Dungeon
ヘイ!元気?最近の数週間、私はC - Chenhn開発者のポジションのインタビューを行っています.
私はASPで動作します.私が家にいるとき、私は私のトレーニング言語としてC .したがって、私が私のgithubに持っているC -経典はかなり古いです、そして、私の経歴の初期の年に属します.
それで、雇い主が私のGithubのために若干のより新しいCチェックコードを作成するように私に与えているコーディング挑戦を使用することに決めて、同時に、あなたがあなたの個人的な発展を改善するために続くことができる良いガイドを作成してください.

このチュートリアルから何を期待するか?


シリーズの最後に、以下の特徴を持つマイクロサービスを提供します.
  • インテグレートMongoDB
  • 関心の明確な分離による層状アーキテクチャ
  • APIドキュメント
  • 展開のためのDockerサポート
  • ユニットテスト
  • 導入


    我々は、中小企業を持って、我々は販売💻. 新しいコンピュータが販売されるたびに、我々はそれを買った量とクライアントと順序を記録する必要があります.
    我々は、Aに接続する小さなマイクロサービスを作成するつもりですMongoDB そして、私たちは/読み取り/更新/削除の順序を作成し、また、ユーザーの支出についていくつかの余分な計算を得ることができます.
    我々Order モデルは次の通りです.
    {
      "id": "guid",
      "userId": "guid",
      "amount": "int"
    }
    

    基本定義


    ASPを作成することから始めます.NETコア3.1 APIテンプレートを使用したWebアプリケーションとVisual Studio 2019でのDockerサポートを有効にします.

    それが作成されると、モデルとコントローラが表示されますWeatherForecast ボックスのAPIがあることを示すデフォルトのテンプレート方法です.

    デフォルトのコードを削除した後に、モデルと基本的なOrdersControllerを作成します.我々は、開始するつもりですGet and Post エンドポイント、そのように我々は追加とテストを受けることができるようになります.
        [Route("v1/[controller]")]
        [ApiController]
        public class OrdersController : ControllerBase
        {
            /// <summary>
            /// Retrieves all orders
            /// </summary>
            /// <returns>a list with all the orders available</returns>
            [HttpGet]
            public async Task<IEnumerable<Order>> GetAll()
            {
                throw new NotImplementedException();
            }
    
            /// <summary>
            /// Retrieves the order that matches the id supplied
            /// </summary>
            /// <returns>one order model</returns>
            [HttpGet("{orderId}")]
            public async Task<ActionResult<Order>> Get(Guid orderId)
            {
                throw new NotImplementedException();
            }
    
            /// <summary>
            /// Creates a new order
            /// </summary>
            /// <returns>the newly created order</returns>
            [HttpPost]
            public async Task<ActionResult<Order>> Post([FromBody]OrderCreateUpdate orderRequest)
            {
                throw new NotImplementedException();
            }
        }
    
    前のコードでは、GetAll , Get and Post エンドポイントは、我々はまた、パブリックAPIのコメントが含まれ、我々はすでに使用してAPIをversionedv1/[controller] 端点の命名あなたが注意を払っているならば、あなたはそれに気がついたかもしれませんPost まだ定義されていないモデルがあります.OrderCreateUpdate .
    データベース内の項目を作成するときは、OrderId , 順序がまだ存在しないので、それが独立して変わることができるように、それは2つのAPIモデルを切り離すのに良い実行です.これがモデルですOrderCreateUpdate :
    {
      "userId": "guid",
      "amount": "int"
    }
    
            public Guid UserId { get; set; }
            public int Amount { get; set; }
    

    データベースへの接続


    今のところ、データベースを作成するのではなく、最初からDockerでメッシングするのではなく、MongoDBAtlas .
    プロジェクトに戻るには、データベースに接続する設定を設定する方法を見つける必要がありますOptions Pattern . 以下の設定を定義します.
        public class OrdersServiceOptions
        {
            public string DatabaseConnectionString { get; set; }
            public string DatabaseName { get; set; }
            public string CollectionName { get; set; }
        }
    
    我々が我々の最初のものをつくるために動くことができる準備ができた今Repository それは我々の接続に責任があるMongoDB インスタンス.
    これは私たちのためのコードですOrdersRepository :
        public class OrdersRespository
        {
            private readonly IMongoDatabase database;
            private readonly IMongoCollection<Order> collection;
            private readonly ILogger<OrdersRespository> logger;
    
            public OrdersRespository(IOptions<OrdersProcessingServiceOptions> options, ILogger<OrdersRespository> logger)
            {
                if (options == null)
                {
                    throw new ArgumentNullException(nameof(options));
                }
    
                var configuration = options.Value;
                var client = new MongoClient(configuration.DatabaseConnectionString);
    
                this.database = client.GetDatabase(configuration.DatabaseName);
                this.collection = database.GetCollection<Order>(configuration.CollectionName);
                this.logger = logger;
            }
        }
    
    ご覧の通りRepository との接続を作成するMongoDB 我々が以前定義する設定オプションを使用することによって、我々は我々が我々のメソッドで使用するつもりであるロガーも受け入れます.次に、我々は我々が取得し、作成するために使用するメソッドを作成するつもりですOrders .
            public async Task<Order> GetOrder(Guid orderId) => await collection.Find(x => x.Id == orderId).FirstOrDefaultAsync();
    
            public async Task<IEnumerable<Order>> GetAll() => await collection.Find(_ => true).ToListAsync();
    
            public async Task<Order> CreateOrder(Order order)
            {
                try
                {
                    await collection.InsertOneAsync(order);
    
                    return order;
                }
                catch (Exception ex)
                {
                    logger.LogError(ex.Message, ex);
                    return null;
                }
            }
    
    3つのメソッドは非常に簡単です、私たちはidによって単一の順序を得ます、我々はすべての受注を得ます、そして、我々は新しい命令をつくります(創造が失敗するならば、適切な記録をして).これらのメソッドを追加した後、このリポジトリのインターフェイスを作成しますDependency Injection そのとおりです.ネットコア.
       public interface IOrdersRespository
        {
            Task<Order> GetOrder(Guid orderId);
            Task<IEnumerable<Order>> GetAll();
            Task<Order> CreateOrder(Order order);
        }
    

    作品の接続


    我々のところに戻りましょうController そして、我々の適切な呼び出しをしましょうRepository .
        [ApiController]
        [Route("v1/[controller]")]
        public class OrdersController : ControllerBase
        {
            private readonly IOrdersRepository ordersRepository;
    
            public OrdersController(IOrdersRepository ordersRepository)
            {
                this.ordersRepository = ordersRepository;
            }
    
            /// <summary>
            /// Retrieves all orders
            /// </summary>
            /// <returns>a list with all the orders available</returns>
            [HttpGet]
            public async Task<IEnumerable<Order>> GetAll()
            {
                return await ordersRepository.GetAll();
            }
    
            /// <summary>
            /// Retrieves the order that matches the id supplied
            /// </summary>
            /// <returns>one order model</returns>
            [HttpGet("{orderId}")]
            [ProducesResponseType(StatusCodes.Status200OK)]
            [ProducesResponseType(StatusCodes.Status404NotFound)]
            public async Task<ActionResult<Order>> Get(Guid orderId)
            {
                var result = await ordersRepository.GetOrder(orderId);
    
                if (result == null) return NotFound();
    
                return Ok(result);
            }
    
            /// <summary>
            /// Creates a new order
            /// </summary>
            /// <returns>the newly created order</returns>
            [HttpPost]
            [ProducesResponseType(StatusCodes.Status201Created)]
            [ProducesResponseType(StatusCodes.Status400BadRequest)]
            public async Task<ActionResult<Order>> Post([FromBody]OrderCreateUpdate orderRequest)
            {
                var order = new Order()
                {
                    Amount = orderRequest.Amount,
                    UserId = orderRequest.UserId
                };
    
                var result = await ordersRepository.CreateOrder(order);
    
                if (result == null) return BadRequest();
    
                return StatusCode(201, result);
            }
        }
    
    の依存関係を追加するIOrdersRepository コンストラクタでは、エンドポイントから使用します.また、結果に応じて異なる応答を処理しますRepository そして、我々は明示的にProducesResponseType .

    今日の結果?

    POST GET GET ALL
    あなたが現代のAPIを構築している若干の経験をするならば、あなたはおそらくショックにあります.この男は本当にAPIとデータベースの同じモデルを使用するつもりですか?彼はコントローラからリポジトリを呼び出すつもりですか?なぜすべて同じプロジェクトですか?
    心配しないでください、我々はこのシリーズの終わりの前にすべてを処理します、私はそれがあなたのgithub😄
    それは多くの、私は知っている、私はまた、すべてのアプリケーションのパターンを詳細には不可能だったので使用されませんでしたが使用されるすべてのパターンでは、ASPでそれを実装する方法の公式ガイドへのリンクです.ネットコア、マイクロソフトのチュートリアルは非常に良いですし、彼らはあなたに詳細が欠落を与える.
    閉じるこの動画はお気に入りから削除されていますUpdate , Delete , そして、結合された情報終点と時間があるならば、我々はより良い懸念を分離し始めて、我々のサービスを磨きます.
    いつものように、あなたが好きかどうかコメントで私に知らせて、それを共有しないでください😄