جواد جهانگیری
جواد جهانگیری
خواندن ۳۲ دقیقه·۳ سال پیش

آموزش ایجاد میکروسرویس با C# asp.net core با دیتابیس MongoDB

به نام آن که جان را فکرت آموخت / چراغ دل به نور جان برافروخت

در این مقاله از سری مقاله های آموزشی مونگودبی به آموزش نحوه ایجاد یک میکروسرویس (microservice) در C# asp.net core با دیتابیس مونگودبی (mongoDb) بصورت کاربردی و پروژه محور پرداخته می شود. منبع آموزشی استفاده شده در این سری مقاله ها ، آموزش های شرکت مایکروسافت در راستای معماری میکروسرویس و پروژه eShopOnContainers شرکت مایکروسافت و و آموزش های استاد بزرگوار Mehmet Özkaya در سایت udemy می باشد. ایده این سری مقاله های آموزشی از این موضوع سرچشمه می گیرد که بخشی از خوانندگان وجود دارد که به محتوای نوشتاری آنلاین بهتر پاسخ می دهند و ترجیج می دهند مهارت های جدید را به سرعت از طریق خواندن افزایش دهند.این سری اموزش ها با ارایه اولین پکیج آموزشی در خصوص مانگودبی آغاز می شود که انتظار می رود با واکنش مثبت کاربران همراه شود.

Microservices Using ASP.NET Core, MongoDB
Microservices Using ASP.NET Core, MongoDB
توجه: این مقاله به مرور زمان، ویرایش و یا تکمیل می‌شود!
تقاضا: در صورتی که با مشکل تایپی، دستوری و یا مفهومی در این مقاله برخورد کردید، از شما دوست عزیز و گرامی، صمیمانه تقاضا می‌کنم که اینجانب را مطلع کرده، تا نسبت به تصحیح و یا تکمیل آن، در اسرع وقت، اقدام نمایم. با کمال تشکر جواد جهانگیری
شماره تلفن همراه: 09149431772
نشانی پست الکترونیکی: javad.jahangiri.niopdc@gmail.com
فیلم‌های آموزشی در آپارات:جواد جهانگیری (CTO) - آپارات
فیلم آموزشی در یوتویب: javad jahangiri - YouTube
نسخه مقاله: ۱.۱ - تاریخ بروزرسانی: 1400/09/09
https://www.aparat.com/javadjahangiriniopdc/playlists



ما در این مقاله اموزشی یک میکروسرویس در C# asp.net core بصورت web api براساس RestApi ایجاد می کنیم و عملیات CRUD بر روی product و Category با دیتابیس mongdb را خواهیم داشت و پیاده سازی بصورت Repository Pattern خواهد بود و از swagger برای Open Api استفاده می کنیم ,معماری استفاده شده بصورت architecture N-Layer می باشد و در نهایت میکروسرویس ایجاد شده بر روی Docker پابلیش خواهد شد

برای دسترسی به سورس های این پروژه می توانید وارد github بنده به ادرس javad.jahangiri.niopdc زیر شوید:

https://github.com/javadjahangiriniopdc

برای این مقاله آموزشی یک ریپوزیتوری بنام MicroservicesUsingASP.NETCoreMongoDB ایجاد شده و سورس ها در این مخزن push می شود

ابتدا نسبت به ایجاد یک پروژه ASP.NET Core Web Api مطابق تصاویر زیر به ترتیب اقدام می کنید

بر روی گزینه create and push کلیک می کنید و بر روی گیت هاب یک مخزن با نام مذکور ایجاد می شود و سورس های پروژه در ان Push می شود

پیش نیازهای این آموزش

پیشنهاد می شود قبل از شروع به مطالعه این مقاله نسبت به مطالعه مقالات ذیل اقدام نمایید

https://virgool.io/@javadjahangiri/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D8%AF%DB%8C%D8%AA%D8%A7%D8%A8%DB%8C%D8%B3-%D9%85%D9%88%D9%86%DA%AF%D9%88%D8%AF%D8%A8%DB%8C-mongodb-tutorial-incadc7thvtl
https://virgool.io/@javadjahangiri/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-mongodbcompass-%D8%AF%D8%B1-%D9%85%D9%88%D9%86%DA%AF%D9%88%D8%AF%D8%A8%DB%8C-ffdeooxnhrpy


نصب Docker Desktop

با عنایت به اینکه در این آموزش قصد داریم درنهایت پروژه را بر روی داکر پابلیش کنیم لذا می بایستی ابتدا بر روی سیستم عامل ویندوز داکر رو نصب کنیم برای این کار راحترین روش استفاده از Docker Desktop می باشد ابتدا وارد سایت زیر شده و برنامه داکر دسکتاب را دانلود و نصب می کنید

https://www.docker.com/products/docker-desktop

و وارد برنامه داکر دسکتاب می شویم:

سپس وارد سایت داکرهاب می شویم تا image مربوط به مونگودبی را پیدا کنیم

https://hub.docker.com/_/mongo

معمولا از نسخه رسمی Official Image استفاده می کنیم:

سپس وارد محیط ویژال استادیو خودمان می شویم بر روی Solution راست کلیک کرده و گزینه open terminal کلیک می کنیم:

تا پنجره پاور شل برای ما باز شود:

حال از طریق کد زیر چک می کنیم که داکر بر روی سیستم عامل ما نصب و فعال می باشد

docker ps

از طریق کد زیر ایمیج مربوط به مونگودبی روی کامپیوتر خودمان pull می کنیم:

docker pull mongo
نکته:دقت شود از آنجایی که اگر مونگودبی در ویندوز نصب شده باشد و سرویس ان فعال باشد پورت 27017 در حال استفاده است دستور اجرای داکر خطا می دهد لذا ابتدا از سرویس های ویندوز سرویس مانگودبی را stop کنید سپس از اقدام به اجرای داکر مونگودبی نمایید

سپس از طریق کد زیر ایمیج مونگودبی را بر روی داکر اجرا می کنیم

docker run -d -p 27017:27017 --name store-mongo mongo

از طریق کد زیر چک می کنیم که کانتنر مونگودبی اجرا شده است:

docker ps

از طریق دستور زیر می توانیم لاک کانتنر مونگودبی را مشاهده کنید برای خروج از حالت نمایش لاگ کلیدهای ترکیبی Ctrl+C را استفاده کنید:

docker logs -f store-mongo

از طریق دستور ذیل می توانیم وارد خط فرمان کانتنر بصورت اینتراکتیور مونگودبی بشوید:

docker exec -it store-mongo /bin/bash

سپس می توانید بصورت اینتر اکتیو mongo را اجرا کنید:

حالا که وارد محیط مونگودبی شل شدیم می توانید دستوارت مونگودبی را وارد نمایید برای مثال مشاهده دیتابیس ها:

show dbs

ایجاد دیتابیس StoreDb:

use StoreDb

ایجاد کالکشن (جدول) Products:

db.createCollection('Products')

درج سند (رکورد) در کالکشن (جدول) محصولات:

db.Products.insertMany([{ 'Name':'Asus Laptop','Category':'Computers', 'Summary':'Summary', 'Description':'Description', 'ImageFile':'ImageFile', 'Price':54.93 }, { 'Name':'HP Laptop','Category':'Computers', 'Summary':'Summary', 'Description':'Description', 'ImageFile':'ImageFile', 'Price':88.93 } ])

برای نمایش اطلاعات درج شده می تواند از دستور find بهمراه اپراتور pretty استفاده کرد:

db.Products.find({}).pretty()

آنالیز و معماری میکروسرویس Store

در این مقاله اموزشی ما قصد داریم یک میکرسرویس بنام Store با شرایط ذیل ایجاد کنیم:

  • ASP.NET Core Web API application
  • REST API principles, CRUD operations
  • MongoDB database connection and containerization
  • Repository Pattern Implementation
  • Containerize Store Microservices with MongoDb using Docker Compose

رست ای پی آی مربوط به میکرسرویس فروشگاه:

معماری لایه ای میکروسرویس فروشگاه:

Store Layered Architectures
Store Layered Architectures

پکیج ها ناگت مورد نیاز برای این پروژه:

  • MongoDb.Driver
  • SwashBuckle.AspNetCore

الگوی طراحی Repository Design Pattern چیست؟

از repository برای جلوگیری از دوباره کاری و تکرار استفاده می شود. امروزه در پروژه های حرفه ای که با معماری multi-tier یا multi-layer ایجاد می شوند، لازم است که از دوباره کاری پرهیز شود.

الگوی Repository:

گاهی اوقات لازم است یک منطق بین منطق کاری و منطق دسترسی داده ها تعریف شود. این منطق می تواند استفاده کردن از الگوی Repository  را تعریف کند.  اساسایک میانجی بین دو لایه است. عمدتا جایی استفاده می شود که نیاز است داده ها قبل از رفتن به مرحله بعد تغییر کنند.

مزایای استفاده از Repository:

  • . متمرکز کردن منطق داده ها (data logic) یا منطق کاری (business logic)و منطق سرویس (service logic)
  • یک  نقطه تعویض برای واحد تست است.
  • یک معماری قابل انعطاف فراهم میکند.
  • اگر بخواهید منطق دسترسی داده ها یا منطق کاری را تغییر دهید نیازی نیست منطق repository را تغییر دهید.

الگوی Generic repository:

گاهی اوقات لازم است یا بهتر است همه منطق های repository در یک مکان با استفاده از generic logic ساخته شوند. ما می توانیم فقط یک کلاسrepository ایجاد کنیم که مسئول رسیدگی به کل سناریو خواهد بود. می تواند یک منطق بین repository و دسترسی به داده ها  یا یک منطق بین منطق کاری و repository باشد. در همه موارد ما فقط یک repository می نویسیم. مزیت اصلی generic repository ، استفاده مجدد از کد است.

مزایای استفاده از Generic repository:

  • افزونگی کد را کاهش می دهد.
  • برنامه نویس را به استفاده از همان الگو مجبور میکند.
  • ایجاد خطاها را کمتر می کند.
  • اگر از این الگو استفاده کنید ، نگه داری منطق دسترسی به داده های متمرکز آسان می شود.

حذف WeatherForecast از پروژه :

از انجایی که پروژه از روی api template مایکروسافت ایجاد شده است شامل api مربوط به آب و هوا می باشد که باید از پروژه حذف شود برای این کار فایل های زیر از پروژه حدف می کنیم:

نصب پکیج ها ی مورد نیاز پروژه :

وارد NuGet Package Manager می شویم وارد در tab مربوط به Brows ابتدا mongoDb.Driver را جستجو و نصب می کنیم:

روش دیگر نصب پکیج های مورد نیاز استفاده از PMC (Package Manager Console) می باشد ابتدا وارد سایت nuget شده و عبارت mongoDb را جستجو کرده و از لیست پکیج ها MongoDB.Driver را انتخاب می کنیم :

سپس وارد محیط PMC و دستور زیر را که از سایت کپی کردیم وارد می کنیم :

Install-Package MongoDB.Driver -Version 2.14.0-beta1

اضافه کردن Entity های پروژه:

ابتدا یه پوشه به پروژه بنام Entities اضافه می کنیم:

یک کلاس بنام Product به این پوشه اضافه می کنیم:

public class Product { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; } [BsonElement(&quotName&quot)] public string Name { get; set; } public string Category { get; set; } public string Summary { get; set; } public string Description { get; set; } public string ImageFile { get; set; } public decimal Price { get; set; } }
Product.Cs
Product.Cs


اضافه کردن کانکشن دیتابیس مونگودبی به پروژه:

داخل فایل appsetting.json شده و تنظیمات ذیل را به آن اضافه می کنید:


&quotDatabaseSettings&quot:{ &quotConnectionString&quot: &quotmongodb://localhost:27017&quot, &quotDatabaseName&quot: &quotStoreDb&quot, &quotCollectionName&quot: &quotProducts&quot },

برنامه نویسی Data Layer پروژه:

برای این کار یک پوشه بنام Data به پروژه اضافه کنید و اینترفیس IStoreContext را به ان پوشه اضافه می کنیم:

public interface IStoreContext { IMongoCollection<Product> Products { get; } }

یک فایل کلاس بنام StoreContextSeed برای Seed داده های اولیه به پوشه Data اضافه می کنیم:

using MongoDB.Driver; using System.Collections.Generic; using System.Linq; namespace MicroservicesUsingASP.NETCoreMongoDB.Data { public class StoreContextSeed { public static void SeedData(IMongoCollection<Product> productCollection) { bool existProduct = productCollection.Find(p => true).Any(); if (!existProduct) { productCollection.InsertManyAsync(GetPreconfiguredProducts()); } } private static IEnumerable<Product> GetPreconfiguredProducts() { return new List<Product>() { new Product() { Id = &quot602d2149e773f2a3990b47f5&quot, Name = &quotIPhone X&quot, Summary = &quotThis phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.&quot, Description = &quotLorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.&quot, ImageFile = &quotproduct-1.png&quot, Price = 950.00M, Category = &quotSmart Phone&quot }, new Product() { Id = &quot602d2149e773f2a3990b47f6&quot, Name = &quotSamsung 10&quot, Summary = &quotThis phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.&quot, Description = &quotLorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.&quot, ImageFile = &quotproduct-2.png&quot, Price = 840.00M, Category = &quotSmart Phone&quot }, new Product() { Id = &quot602d2149e773f2a3990b47f7&quot, Name = &quotHuawei Plus&quot, Summary = &quotThis phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.&quot, Description = &quotLorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.&quot, ImageFile = &quotproduct-3.png&quot, Price = 650.00M, Category = &quotWhite Appliances&quot }, new Product() { Id = &quot602d2149e773f2a3990b47f8&quot, Name = &quotXiaomi Mi 9&quot, Summary = &quotThis phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.&quot, Description = &quotLorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.&quot, ImageFile = &quotproduct-4.png&quot, Price = 470.00M, Category = &quotWhite Appliances&quot }, new Product() { Id = &quot602d2149e773f2a3990b47f9&quot, Name = &quotHTC U11+ Plus&quot, Summary = &quotThis phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.&quot, Description = &quotLorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.&quot, ImageFile = &quotproduct-5.png&quot, Price = 380.00M, Category = &quotSmart Phone&quot }, new Product() { Id = &quot602d2149e773f2a3990b47fa&quot, Name = &quotLG G7 ThinQ&quot, Summary = &quotThis phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.&quot, Description = &quotLorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.&quot, ImageFile = &quotproduct-6.png&quot, Price = 240.00M, Category = &quotHome Kitchen&quot } }; } } }

یک فایل StoreContext.Cs به پوشه Data اضافه می کنید که از اینترفیس IStoreContext ارثبری کند:

using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using MicroservicesUsingASP.NETCoreMongoDB.Entities; using Microsoft.Extensions.Configuration; using MongoDB.Driver; using MongoDB.Driver.Core.Operations; namespace MicroservicesUsingASP.NETCoreMongoDB.Data { public class StoreContext :IStoreContext { public StoreContext(IConfiguration configuration) { var client = new MongoClient(configuration.GetValue<string>(&quotDatabaseSettings:ConnectionString&quot)); var database = client.GetDatabase(configuration.GetValue<string>(&quotDatabaseSettings:DatabaseName&quot)); Products = database.GetCollection<Product>(configuration.GetValue<string (&quotDatabaseSettings:CollectionName&quot)); StoreContextSeed.SeedData(Products); } public IMongoCollection<Product> Products { get; } } }
Data Layer
Data Layer


برنامه نویسی Business Layer پروژه:

یک پوشه Repositories به پروژه اضافه می کنیم و یک اینترفیس IProductRepository به پوشه Repositories اضافه می کنیم:

using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using MicroservicesUsingASP.NETCoreMongoDB.Entities; namespace MicroservicesUsingASP.NETCoreMongoDB.Repositories { public interface IProductRepository { Task<IEnumerable<Product>> GetProducts(); Task<Product> GetProduct(string id); Task<IEnumerable<Product>> GetProductByName(string name); Task<IEnumerable<Product>> GetProductByCategory(string categoryName); Task CreateProduct(Product product); Task<bool> UpdateProduct(Product product); Task<bool> DeleteProduct(string id); } }

یک کلاس بنام ProductRepository که از IProductRepository ارث بری کند به پروژه اضافه می کنیم و توابع مورد نیاز را پیاده سازی می کند:

using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using MicroservicesUsingASP.NETCoreMongoDB.Data; using MicroservicesUsingASP.NETCoreMongoDB.Entities; using MongoDB.Driver; namespace MicroservicesUsingASP.NETCoreMongoDB.Repositories{ public class ProductRepository : IProductRepository { private readonly IStoreContext _context; public ProductRepository(IStoreContext context) { _context = context ?? throw new ArgumentNullException(nameof(context)); } public async Task<IEnumerable<Product>> GetProducts() { return await _context .Products .Find(p => true) .ToListAsync(); } public async Task<Product> GetProduct(string id) { return await _context .Products .Find(p => p.Id == id) .FirstOrDefaultAsync(); } public async Task<IEnumerable<Product>> GetProductByName(string name) { FilterDefinition<Product> filter = Builders<Product>.Filter.ElemMatch(p => p.Name, name); return await _context .Products .Find(filter) .ToListAsync(); } public async Task<IEnumerable<Product>> GetProductByCategory(string categoryName) { FilterDefinition<Product> filter = Builders<Product>.Filter.Eq(p => p.Category, categoryName); return await _context .Products .Find(filter) .ToListAsync(); } public async Task CreateProduct(Product product) { await _context.Products.InsertOneAsync(product); } public async Task<bool> UpdateProduct(Product product) { var updateResult = await _context .Products .ReplaceOneAsync(filter: g => g.Id == product.Id, replacement: product); return updateResult.IsAcknowledged && updateResult.ModifiedCount > 0; } public async Task<bool> DeleteProduct(string id) { FilterDefinition<Product> filter = Builders<Product>.Filter.Eq(p => p.Id, id); DeleteResult deleteResult = await _context .Products .DeleteOneAsync(filter); return deleteResult.IsAcknowledged && deleteResult.DeletedCount > 0; } } }


برنامه نویسی Presentation Layer پروژه:

کلاس StoreController را به پوشه Controller اضافه می کنیم دقت شود که نوع این کنترلر باید به Api تبدیل شود و روتینگ api/v1 به ان اضافه شود و از ControllerBase ارث بری داشته باشد:

using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; using MicroservicesUsingASP.NETCoreMongoDB.Entities; using MicroservicesUsingASP.NETCoreMongoDB.Repositories; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace MicroservicesUsingASP.NETCoreMongoDB.Controllers { [ApiController] [Route(&quotapi/v1/[controller]&quot)] public class StoreController:ControllerBase { private readonly IProductRepository _repository; private readonly ILogger<StoreController> _logger; public StoreController(IProductRepository repository, ILogger<StoreController> logger) { _repository = repository; _logger = logger; } [HttpGet] [ProducesResponseType(typeof(IEnumerable<Product>), (int)HttpStatusCode.OK)] public async Task<ActionResult<IEnumerable<Product>>> GetProducts() { var products = await _repository.GetProducts(); return Ok(products); } [HttpGet(&quot{id:length(24)}&quot, Name = &quotGetProduct&quot)] [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)] public async Task<ActionResult<Product>> GetProductById(string id) { var product = await _repository.GetProduct(id); if (product == null) { _logger.LogError($&quotProduct with id: {id}, not found.&quot); return NotFound(); } return Ok(product); } [Route(&quot[action]/{category}&quot, Name = &quotGetProductByCategory&quot)] [HttpGet] [ProducesResponseType(typeof(IEnumerable<Product>), (int)HttpStatusCode.OK)] public async Task<ActionResult<IEnumerable<Product>>> GetProductByCategory(string category) { var products = await _repository.GetProductByCategory(category); return Ok(products); } [Route(&quot[action]/{name}&quot, Name = &quotGetProductByName&quot)] [HttpGet] [ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType(typeof(IEnumerable<Product>), (int)HttpStatusCode.OK)] public async Task<ActionResult<IEnumerable<Product>>> GetProductByName(string name) { var items = await _repository.GetProductByName(name); if (items == null) { _logger.LogError($&quotProducts with name: {name} not found.&quot); return NotFound(); } return Ok(items); } [HttpPost] [ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)] public async Task<ActionResult<Product>> CreateProduct([FromBody] Product product) { await _repository.CreateProduct(product); return CreatedAtRoute(&quotGetProduct&quot, new { id = product.Id }, product); } [HttpPut] [ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)] public async Task<IActionResult> UpdateProduct([FromBody] Product product) { return Ok(await _repository.UpdateProduct(product)); } [HttpDelete(&quot{id:length(24)}&quot, Name = &quotDeleteProduct&quot)] [ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)] public async Task<IActionResult> DeleteProductById(string id) { return Ok(await _repository.DeleteProduct(id)); } } }


رجیستر کردن کلاس های StoreContext و ProductRepository

برای این کار وارد فایل Startup پروژه می شویم و به متد ConfigureServices رفته و کدهای زیر را به ان اضافه می کنیم:

public void ConfigureServices(IServiceCollection services) { services.AddScoped<IStoreContext, StoreContext>(); services.AddScoped<IProductRepository, ProductRepository>(); services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc(&quotv1&quot, new OpenApiInfo { Title = &quotMicroservicesUsingASP.NETCoreMongoDB&quot, Version = &quotv1&quot }); }); }

در اخر این مرحله یکبار پروژه را Build میگریم که خطای وجود نداشته باشد:

تست و اجرای پروژه

برای تست پروژه ابتدا مطمن شوید که داکر دسکتاب اجرا شده و کانتینر مونگودبی فعال می باشد

اگر کانتینر مونگودبی در حین اجرا نبود با روش بالا کانتینر را استارت می کنیم:

روش دیگری که می شود چک کنیم استفاده از ترمینال به شرح ذیل می باشد

تنظیمات دیباگ پروژه رو مطابق تصویر زیر انجام دهید:

سپس پروژه به شکل ذیل اجرا می کنیم:

برنامه به شکل ذیل اجرا می شود:

درنهایت خروجی پروژه در swagger به شکل ذیل نمایش داده می شود:

اجرای Web Api مربوط به GetProduct

نحوه اجرای متد get برای نمایش اطلاعات محصولات به شرح ذیل عمل می کنید:

بر روی گزینه Try it out کلیکد کنید تا کلید execute نمایش داده شود :

باکلیک با روی گزینه execute درخواست به web api مربوطه ارسال شده و نتیجه نمایش داده می شود با عنایت به اینکه برای پروژه Seed تعریف شده بود دو رکوردی که در مرحله اول اجرا پروژه درج شده بودند نمایش داده می شود:

اجرای Api مربوط به GetProductByName
این وب ای پی آی برای فیلتر کردن محصولات براساس نام محصولات به شرح ذیل می باشد:

نحوه تست web api با استفاده از postman

ابتدا وارد نرم افزار postman شده یک Collection اضافه می کنید بنام MicroservicesUsingASP.NETCoreMongoDB می کنیم و سپس یک درخواست از نوع get با نام GetProducts ایجاد می کنیم با درخواست http://localhost:5000/api/v1/Store ایجاد می کنیم و در نهایت بر روی گزینه send کلیک می کنیم

نحوه فراخوانی GetProductByCategory از طریق Postman:

در این قسمت می خواهیم web api مربوط به GetProductByCategory از طریق Postman فراخوانی می کنیم :

برای این کار بصورت ذیل عمل می کنیم :

https://www.aparat.com/javadjahangiriniopdc/playlists

کانتینر کردن میکروسرویس با مونگودبی با استفاده از داکر کامپوز

قبل شروع این مرحله می بایستی یک آشنایی مختصر با مفهوم Docker-compose داشته باشید:

ابزار Docker-compose چیست؟

اصطلاحا Docker Compose گرداننده و یا راهنمای کانتینر داکر است.اگر دیده باشید توی گروه های موسیقی یک رهبر ارکستر وجود داره که وظیفش هدایت گروه تحت نظرشه و اونه که مشخص میکنه چگونه یک گروه باید در حین اجرا رفتار کنه، صدای کم یا زیاد، ریتم و غیره.

این دقیقا همون کاریه که Docker compose انجام میده، ولی توی این مورد ما رهبر ارکستر هستیم! در حقیقت این ماییم که تعیین میکنیم کانتینر یا کانتینرها چگونه با استفاده از یک فایل رفتار کنند. تمام داستان نوشتن یک فایل با فرمت Yaml است (Yaml Ain’t Markup Language)

در محیط Visual Studio 2019 برای ایجاد Docker-compose امکاناتی به شرح ذیل وجود دارد:

بر روی گزینه Container Orchestrator Support کلیک می کنیم و سپس گزینه Docker Compose را انتخاب می کنیم

و در قسمت سیستم عامل مقصد Linux را انتخاب می کنیم

ابتدا اگر روی سیستم شما image مربوط به mcr.microsoft.com/dotnet/aspnet:5.0 نباشد این ایمیج بر روی سیستم شما Pull خواهد شد

این عملیات زمانبر می باشد و با توجه به سرعت اینترنت تا نیم ساعت هم شاید طول بکشید بعد از این مرحله فرایندهای به شرح ذیل انجام می شود

========== Pulling Images ========== Pulling missing Docker images. To cancel this download, close the command prompt window. To disable image auto-pull, see Tools > Options > Container Tools. docker pull mcr.microsoft.com/dotnet/aspnet:5.0 docker pull completed ========== Preparing Containers ========== Getting Docker containers ready... C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe -NonInteractive -NoProfile -WindowStyle Hidden -ExecutionPolicy RemoteSigned -File &quotC:\Users\BaharIctc\AppData\Local\Temp\GetVsDbg.ps1&quot -Version vs2017u5 -RuntimeID linux-x64 -InstallPath &quotC:\Users\BaharIctc\vsdbg\vs2017u5&quot Info: Using vsdbg version '17.0.10712.2' Info: Using Runtime ID 'linux-x64' Info: Latest version of VsDbg is present. Skipping downloads C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe -NonInteractive -NoProfile -WindowStyle Hidden -ExecutionPolicy RemoteSigned -File &quotC:\Users\BaharIctc\AppData\Local\Temp\GetVsDbg.ps1&quot -Version vs2017u5 -RuntimeID linux-musl-x64 -InstallPath &quotC:\Users\BaharIctc\vsdbg\vs2017u5\linux-musl-x64&quot Info: Using vsdbg version '17.0.10712.2' Info: Using Runtime ID 'linux-musl-x64' Info: Latest version of VsDbg is present. Skipping downloads docker-compose -f &quotD:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\docker-compose.yml&quot -f &quotD:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\docker-compose.override.yml&quot -f &quotD:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\obj\Docker\docker-compose.vs.debug.g.yml&quot -p dockercompose6193082444552166584 --ansi never config services: microservicesusingasp.netcoremongodb: build: context: D:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB dockerfile: MicroservicesUsingASP.NETCoreMongoDB/Dockerfile labels: com.microsoft.created-by: visual-studio com.microsoft.visual-studio.project-name: MicroservicesUsingASP.NETCoreMongoDB target: base container_name: MicroservicesUsingASP.NETCoreMongoDB entrypoint: tail -f /dev/null environment: ASPNETCORE_ENVIRONMENT: Development ASPNETCORE_LOGGING__CONSOLE__DISABLECOLORS: &quottrue&quot DOTNET_USE_POLLING_FILE_WATCHER: '1' NUGET_FALLBACK_PACKAGES: /root/.nuget/fallbackpackages;/root/.nuget/fallbackpackages2 image: microservicesusingaspnetcoremongodb:dev labels: com.microsoft.visualstudio.debuggee.arguments: ' --additionalProbingPath /root/.nuget/packages --additionalProbingPath /root/.nuget/fallbackpackages --additionalProbingPath /root/.nuget/fallbackpackages2 &quot/app/bin/Debug/net5.0/MicroservicesUsingASP.NETCoreMongoDB.dll&quot' com.microsoft.visualstudio.debuggee.killprogram: /bin/sh -c &quotif PID=$$(pidof dotnet); then kill $$PID; fi&quot com.microsoft.visualstudio.debuggee.program: dotnet com.microsoft.visualstudio.debuggee.workingdirectory: /app ports: - target: 80 tty: true volumes: - D:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB:/app:rw - C:\Users\BaharIctc\vsdbg\vs2017u5:/remote_debugger:rw - C:\Users\BaharIctc\AppData\Roaming\ASP.NET\Https:/root/.aspnet/https:ro - C:\Users\BaharIctc\AppData\Roaming\Microsoft\UserSecrets:/root/.microsoft/usersecrets:ro - C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages:/root/.nuget/fallbackpackages:ro - C:\Program Files (x86)\Microsoft\Xamarin\NuGet:/root/.nuget/fallbackpackages2:ro - C:\Users\BaharIctc\.nuget\packages:/root/.nuget/packages:ro - D:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB:/src:rw version: '3.4' docker-compose -f &quotD:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\docker-compose.yml&quot -f &quotD:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\docker-compose.override.yml&quot -f &quotD:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\obj\Docker\docker-compose.vs.debug.g.yml&quot -p dockercompose6193082444552166584 --ansi never build Building microservicesusingasp.netcoremongodb #1 [internal] load build definition from Dockerfile #1 sha256:2de4178b636398d7f62590883d84d0d153cac4808b3fd9bbaea2615183367a68 #1 transferring dockerfile: 959B 0.0s done #1 DONE 0.0s #2 [internal] load .dockerignore #2 sha256:96e481c075e3846ab2f2c99d08161ca833f2df785879528caa1af0b046b32f19 #2 transferring context: 382B done #2 DONE 0.0s #3 [internal] load metadata for mcr.microsoft.com/dotnet/aspnet:5.0 #3 sha256:3b35130338ebb888f84ec0aa58f64d182f10a676a625072200f5903996d93690 #3 DONE 0.0s #5 [base 1/2] FROM mcr.microsoft.com/dotnet/aspnet:5.0 #5 sha256:31acc33a1535ed7869167d21032ed94a0e9b41bbf02055dc5f04524507860176 #5 DONE 0.1s #4 [base 2/2] WORKDIR /app #4 sha256:56abde746b4f39a24525b2b730b2dfb6d9688bcf704d367c86a4753aefff33f6 #4 DONE 0.0s #6 exporting to image #6 sha256:e8c613e07b0b7ff33893b694f7759a10d42e180f2b4dc349fb57dc6b71dcab00 #6 exporting layers 0.0s done #6 writing image sha256:46d0a001d9dc736c2727e3aaee0499ec7dddebf60e631019e70f37da8b140f40 done #6 naming to docker.io/library/microservicesusingaspnetcoremongodb:dev done #6 DONE 0.0s Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them docker-compose -f &quotD:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\docker-compose.yml&quot -f &quotD:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\docker-compose.override.yml&quot -f &quotD:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\obj\Docker\docker-compose.vs.debug.g.yml&quot -p dockercompose6193082444552166584 --ansi never up -d --no-build --force-recreate --remove-orphans Creating network &quotdockercompose6193082444552166584_default&quot with the default driver Creating MicroservicesUsingASP.NETCoreMongoDB ... Creating MicroservicesUsingASP.NETCoreMongoDB ... done Done! Docker containers are ready.

ابتدا یک فایل Dockerfile با محتویات ذیل به پروژه اضافه می شود

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base WORKDIR /app EXPOSE 80 FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build WORKDIR /src COPY [&quotMicroservicesUsingASP.NETCoreMongoDB/MicroservicesUsingASP.NETCoreMongoDB.csproj&quot, &quotMicroservicesUsingASP.NETCoreMongoDB/&quot] RUN dotnet restore &quotMicroservicesUsingASP.NETCoreMongoDB/MicroservicesUsingASP.NETCoreMongoDB.csproj&quot COPY . . WORKDIR &quot/src/MicroservicesUsingASP.NETCoreMongoDB&quot RUN dotnet build &quotMicroservicesUsingASP.NETCoreMongoDB.csproj&quot -c Release -o /app/build FROM build AS publish RUN dotnet publish &quotMicroservicesUsingASP.NETCoreMongoDB.csproj&quot -c Release -o /app/publish FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT [&quotdotnet&quot, &quotMicroservicesUsingASP.NETCoreMongoDB.dll&quot]

سپس فایل های مربوط به docker-compose.yml به پروژه اضافه می شود:

version: '3.4' services microservicesusingasp.netcoremongodb: image: ${DOCKER_REGISTRY-}microservicesusingaspnetcoremongodb build: context: . dockerfile: MicroservicesUsingASP.NETCoreMongoDB/Dockerfile

در نهایت پیغام Done! Docker Contianers are ready در صورتی که خطایی رخ ندهد را نمایش می دهد

و در نهایت اجرای پروژه بر روی docker-compose تغییر داده می شود

اضافه کردن ایمیج مونگودبی به داکر کامپوز فایل برای محیط های مولتی کانتینر داکر

برای این کار وارد فایل docker-compose.yml می شویم ابتدا یک سرویس به این فایل بنام storedb اضافه می کنیم و سپس برای اینکه درهنگام نصب و یا حذف کانتینر های اطلاعات دیتابیس حذف نشود و بعبارتی اطلاعات دیتابیس در سیستم فایل ما در یک فایل جداگانه از خود کانتینر نوشته شود یک volumes هم به فایل داکرکامپوز با نام mongo_data اضافه می کنیم

version: '3.4' services: storedb: image: mongo microservicesusingasp.netcoremongodb: image: ${DOCKER_REGISTRY-}microservicesusingaspnetcoremongodb build: context: . dockerfile: MicroservicesUsingASP.NETCoreMongoDB/Dockerfile volumes: mongo_data:

حالا نوبت به مهم ترین فایل docker-compose.override.yml می رسد, این فایل وقتی که ما دستور می دهیم که داکر کامپوز مجدد کانتینرها را بسازد داکر کامپوز برای رونویسی تنظیمات پروژه از این فایل استفاده می کند

version: '3.4' services: storedb: container_name: storedb restart: always ports: - &quot27017:27017&quot volumes: - mongo_data:/data/db microservicesusingasp.netcoremongodb: container_name: store.api environment: - ASPNETCORE_ENVIRONMENT=Development - &quotDatabaseSettings:ConnectionString=mongodb://storedb:27017&quot depends_on: - storedb ports: - &quot8080:80&quot

برای سرویس storedb که همانگونه که مستحضرید هر سرویس به یک داکر کانتینر در نهایت تبدیل می شود ابتدا برای کانتینر یک اسم می دهیم و سپس بهش اعلام می کنیم که اگر در حین استارت کانتینر به مشکل برخورد کرد همیشه کانتینر ریست شود و پورت 27017 برای کانتینر تنظیم کرده و والیومی که دیتاهای مونگودبی باید در ان مسیر نوشته شود را /data/db/ را برای ان تنظیم می کنیم

سپس برای کانتینر اصلی پروژه یک نام بنام store.api می دهیم و سپس در پیشنیازهای این سرویس اعلام می کنیم که قبل از استارت این کانتینر باید کانتینر storedb باید ابتدا استارت شده باشد و مشخص می کنیم که پورت ان نیز از 8000 به 80 منتقل شود

توجه شود چون ما در این مقاله برای مونگودبی یک کانتینر ایجاد کرده بودیم و روی پورت 27017 در حال سرویس می باشد فراموش نشود که این کانتینر را ابتدا stop کرده و سپس ان را پاک کنید چون در غیراینصورت با پیغام خطا ذیل روبه رو می شوید:
A non-critical error occurred while getting containers ready. Your project will continue to function normally. The error was: ERROR: for storedb Cannot start service storedb: driver failed programming external connectivity on endpoint storedb (8b42b5ae481272cbad790749fbdff47609ec1552047a893817d5e5987bb9d064): Bind for 0.0.0.0:27017 failed: port is already allocated
If the error persists, try restarting Docker Desktop.

در نهایت برای اجرای پروژه بر روی گزینه docker-composer کلیک می کنیم

ابتدا پروژه یکبار build شده و سپس در پشت پرده کانتینر ساخته شده و استارت می شود

نکته :توجه شود که هنگامی که ما docker-composer را با استفاده از ابزار Container Orchestrator Support می سازیم در هنگام هر تغییرات در فایل های docker-compose.yml و یا docker-compose.override.yml بصورت اتوماتیک دستور فوق در پشت پرده بصورت اتوماتیک اجرا می شود
نکته : چون ما دیتابیس پروژه رو بر روی داکر جدید انتقال دادیم که داخل کانتینر با نام storedb می باشد فراموش نشود که رشته اتصال در فایل appsetting.json پروژه به شرح زیر تغییر داده شود

و در نهایت این هم از نتیجه اجرای پروژه ای که بر روی داکر پابلیش شده است


https://www.aparat.com/javadjahangiriniopdc

اگر بخواهید پروژه را بصورت مستقیم بدون محیط ویژال استادیو اجرا کنیم کافی وارد پوشه پروژه شده و دستور زیر را اجرا کنید

docker-compose -f docker-compose.yml -f docker-compose.override.yml up -d
https://www.aparat.com/javadjahangiriniopdc/playlists


باتشکر از مطالعه مقاله ,مثل همیشه کنجکاو باشید !!!


در دوره های آموزش تضمینی مجتمع فنی ارومیه که به صورت خصوصی و عمومی در دو شیوه حضوری و آنلاین برگزار می شود سرفصل های بسیار متنوع و کاربردی را بصورت پروژه محور آموزش داده می شود تا شخص کارآموز بتواند بلافاصله پس از اتمام این دوره در کمترین زمان ممکن وارد بازار کار شود.
آموزش تخصص ماست با ما حرفه ای شوید
جهت مشاوره با شماره 09149431772 در ارتباط باشید ...
جواد جهانگیری مجتمع فنی ارومیهآموزش برنامه نویسی در ارومیهآموزش سی شارپ دانت کور در ارومیهاستخدام برنامه نویس در ارومیه
بنده دارای مدارک بین المللی شبکه ,برنامه نویسی, سرورهای ویندوزی و لینوکس هستم بیش از ده سال سابقه تدریس در زمینه های یاد شده را دارم. آموزش تخصص ماست با ما حرفه ای شوید 09149431772 مجتمع فنی ارومیه
شاید از این پست‌ها خوشتان بیاید