در این مقاله از سری مقاله های آموزشی مونگودبی به آموزش نحوه ایجاد یک میکروسرویس (microservice) در C# asp.net core با دیتابیس مونگودبی (mongoDb) بصورت کاربردی و پروژه محور پرداخته می شود. منبع آموزشی استفاده شده در این سری مقاله ها ، آموزش های شرکت مایکروسافت در راستای معماری میکروسرویس و پروژه eShopOnContainers شرکت مایکروسافت و و آموزش های استاد بزرگوار Mehmet Özkaya در سایت udemy می باشد. ایده این سری مقاله های آموزشی از این موضوع سرچشمه می گیرد که بخشی از خوانندگان وجود دارد که به محتوای نوشتاری آنلاین بهتر پاسخ می دهند و ترجیج می دهند مهارت های جدید را به سرعت از طریق خواندن افزایش دهند.این سری اموزش ها با ارایه اولین پکیج آموزشی در خصوص مانگودبی آغاز می شود که انتظار می رود با واکنش مثبت کاربران همراه شود.
توجه: این مقاله به مرور زمان، ویرایش و یا تکمیل میشود!
تقاضا: در صورتی که با مشکل تایپی، دستوری و یا مفهومی در این مقاله برخورد کردید، از شما دوست عزیز و گرامی، صمیمانه تقاضا میکنم که اینجانب را مطلع کرده، تا نسبت به تصحیح و یا تکمیل آن، در اسرع وقت، اقدام نمایم. با کمال تشکر جواد جهانگیری
شماره تلفن همراه: 09149431772
نشانی پست الکترونیکی: javad.jahangiri.niopdc@gmail.com
فیلمهای آموزشی در آپارات:جواد جهانگیری (CTO) - آپارات
فیلم آموزشی در یوتویب: javad jahangiri - YouTube
نسخه مقاله: ۱.۱ - تاریخ بروزرسانی: 1400/09/09
ما در این مقاله اموزشی یک میکروسرویس در C# asp.net core بصورت web api براساس RestApi ایجاد می کنیم و عملیات CRUD بر روی product و Category با دیتابیس mongdb را خواهیم داشت و پیاده سازی بصورت Repository Pattern خواهد بود و از swagger برای Open Api استفاده می کنیم ,معماری استفاده شده بصورت architecture N-Layer می باشد و در نهایت میکروسرویس ایجاد شده بر روی Docker پابلیش خواهد شد
برای دسترسی به سورس های این پروژه می توانید وارد github بنده به ادرس javad.jahangiri.niopdc زیر شوید:
برای این مقاله آموزشی یک ریپوزیتوری بنام MicroservicesUsingASP.NETCoreMongoDB ایجاد شده و سورس ها در این مخزن push می شود
ابتدا نسبت به ایجاد یک پروژه ASP.NET Core Web Api مطابق تصاویر زیر به ترتیب اقدام می کنید
بر روی گزینه create and push کلیک می کنید و بر روی گیت هاب یک مخزن با نام مذکور ایجاد می شود و سورس های پروژه در ان Push می شود
پیشنهاد می شود قبل از شروع به مطالعه این مقاله نسبت به مطالعه مقالات ذیل اقدام نمایید
با عنایت به اینکه در این آموزش قصد داریم درنهایت پروژه را بر روی داکر پابلیش کنیم لذا می بایستی ابتدا بر روی سیستم عامل ویندوز داکر رو نصب کنیم برای این کار راحترین روش استفاده از Docker Desktop می باشد ابتدا وارد سایت زیر شده و برنامه داکر دسکتاب را دانلود و نصب می کنید
و وارد برنامه داکر دسکتاب می شویم:
سپس وارد سایت داکرهاب می شویم تا image مربوط به مونگودبی را پیدا کنیم
معمولا از نسخه رسمی 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 با شرایط ذیل ایجاد کنیم:
از repository برای جلوگیری از دوباره کاری و تکرار استفاده می شود. امروزه در پروژه های حرفه ای که با معماری multi-tier یا multi-layer ایجاد می شوند، لازم است که از دوباره کاری پرهیز شود.
گاهی اوقات لازم است یک منطق بین منطق کاری و منطق دسترسی داده ها تعریف شود. این منطق می تواند استفاده کردن از الگوی Repository را تعریف کند. اساسایک میانجی بین دو لایه است. عمدتا جایی استفاده می شود که نیاز است داده ها قبل از رفتن به مرحله بعد تغییر کنند.
گاهی اوقات لازم است یا بهتر است همه منطق های repository در یک مکان با استفاده از generic logic ساخته شوند. ما می توانیم فقط یک کلاسrepository ایجاد کنیم که مسئول رسیدگی به کل سناریو خواهد بود. می تواند یک منطق بین repository و دسترسی به داده ها یا یک منطق بین منطق کاری و repository باشد. در همه موارد ما فقط یک repository می نویسیم. مزیت اصلی generic repository ، استفاده مجدد از کد است.
از انجایی که پروژه از روی 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
ابتدا یه پوشه به پروژه بنام Entities اضافه می کنیم:
یک کلاس بنام Product به این پوشه اضافه می کنیم:
public class Product { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; } [BsonElement("Name")] 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; } }
داخل فایل appsetting.json شده و تنظیمات ذیل را به آن اضافه می کنید:
"DatabaseSettings":{ "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "StoreDb", "CollectionName": "Products" },
برای این کار یک پوشه بنام 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 = "602d2149e773f2a3990b47f5", Name = "IPhone X", Summary = "This phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.", Description = "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. 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.", ImageFile = "product-1.png", Price = 950.00M, Category = "Smart Phone" }, new Product() { Id = "602d2149e773f2a3990b47f6", Name = "Samsung 10", Summary = "This phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.", Description = "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. 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.", ImageFile = "product-2.png", Price = 840.00M, Category = "Smart Phone" }, new Product() { Id = "602d2149e773f2a3990b47f7", Name = "Huawei Plus", Summary = "This phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.", Description = "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. 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.", ImageFile = "product-3.png", Price = 650.00M, Category = "White Appliances" }, new Product() { Id = "602d2149e773f2a3990b47f8", Name = "Xiaomi Mi 9", Summary = "This phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.", Description = "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. 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.", ImageFile = "product-4.png", Price = 470.00M, Category = "White Appliances" }, new Product() { Id = "602d2149e773f2a3990b47f9", Name = "HTC U11+ Plus", Summary = "This phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.", Description = "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. 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.", ImageFile = "product-5.png", Price = 380.00M, Category = "Smart Phone" }, new Product() { Id = "602d2149e773f2a3990b47fa", Name = "LG G7 ThinQ", Summary = "This phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.", Description = "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. 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.", ImageFile = "product-6.png", Price = 240.00M, Category = "Home Kitchen" } }; } } }
یک فایل 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>("DatabaseSettings:ConnectionString")); var database = client.GetDatabase(configuration.GetValue<string>("DatabaseSettings:DatabaseName")); Products = database.GetCollection<Product>(configuration.GetValue<string ("DatabaseSettings:CollectionName")); StoreContextSeed.SeedData(Products); } public IMongoCollection<Product> Products { get; } } }
یک پوشه 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; } } }
کلاس 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("api/v1/[controller]")] 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("{id:length(24)}", Name = "GetProduct")] [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($"Product with id: {id}, not found."); return NotFound(); } return Ok(product); } [Route("[action]/{category}", Name = "GetProductByCategory")] [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("[action]/{name}", Name = "GetProductByName")] [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($"Products with name: {name} not found."); 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("GetProduct", 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("{id:length(24)}", Name = "DeleteProduct")] [ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)] public async Task<IActionResult> DeleteProductById(string id) { return Ok(await _repository.DeleteProduct(id)); } } }
برای این کار وارد فایل Startup پروژه می شویم و به متد ConfigureServices رفته و کدهای زیر را به ان اضافه می کنیم:
public void ConfigureServices(IServiceCollection services) { services.AddScoped<IStoreContext, StoreContext>(); services.AddScoped<IProductRepository, ProductRepository>(); services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "MicroservicesUsingASP.NETCoreMongoDB", Version = "v1" }); }); }
در اخر این مرحله یکبار پروژه را Build میگریم که خطای وجود نداشته باشد:
برای تست پروژه ابتدا مطمن شوید که داکر دسکتاب اجرا شده و کانتینر مونگودبی فعال می باشد
اگر کانتینر مونگودبی در حین اجرا نبود با روش بالا کانتینر را استارت می کنیم:
روش دیگری که می شود چک کنیم استفاده از ترمینال به شرح ذیل می باشد
تنظیمات دیباگ پروژه رو مطابق تصویر زیر انجام دهید:
سپس پروژه به شکل ذیل اجرا می کنیم:
برنامه به شکل ذیل اجرا می شود:
درنهایت خروجی پروژه در swagger به شکل ذیل نمایش داده می شود:
نحوه اجرای متد get برای نمایش اطلاعات محصولات به شرح ذیل عمل می کنید:
بر روی گزینه Try it out کلیکد کنید تا کلید execute نمایش داده شود :
باکلیک با روی گزینه execute درخواست به web api مربوطه ارسال شده و نتیجه نمایش داده می شود با عنایت به اینکه برای پروژه Seed تعریف شده بود دو رکوردی که در مرحله اول اجرا پروژه درج شده بودند نمایش داده می شود:
اجرای Api مربوط به GetProductByName
این وب ای پی آی برای فیلتر کردن محصولات براساس نام محصولات به شرح ذیل می باشد:
ابتدا وارد نرم افزار postman شده یک Collection اضافه می کنید بنام MicroservicesUsingASP.NETCoreMongoDB می کنیم و سپس یک درخواست از نوع get با نام GetProducts ایجاد می کنیم با درخواست http://localhost:5000/api/v1/Store ایجاد می کنیم و در نهایت بر روی گزینه send کلیک می کنیم
در این قسمت می خواهیم web api مربوط به GetProductByCategory از طریق Postman فراخوانی می کنیم :
برای این کار بصورت ذیل عمل می کنیم :
قبل شروع این مرحله می بایستی یک آشنایی مختصر با مفهوم 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 "C:\Users\BaharIctc\AppData\Local\Temp\GetVsDbg.ps1" -Version vs2017u5 -RuntimeID linux-x64 -InstallPath "C:\Users\BaharIctc\vsdbg\vs2017u5" 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 "C:\Users\BaharIctc\AppData\Local\Temp\GetVsDbg.ps1" -Version vs2017u5 -RuntimeID linux-musl-x64 -InstallPath "C:\Users\BaharIctc\vsdbg\vs2017u5\linux-musl-x64" 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 "D:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\docker-compose.yml" -f "D:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\docker-compose.override.yml" -f "D:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\obj\Docker\docker-compose.vs.debug.g.yml" -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: "true" 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 "/app/bin/Debug/net5.0/MicroservicesUsingASP.NETCoreMongoDB.dll"' com.microsoft.visualstudio.debuggee.killprogram: /bin/sh -c "if PID=$$(pidof dotnet); then kill $$PID; fi" 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 "D:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\docker-compose.yml" -f "D:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\docker-compose.override.yml" -f "D:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\obj\Docker\docker-compose.vs.debug.g.yml" -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 "D:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\docker-compose.yml" -f "D:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\docker-compose.override.yml" -f "D:\dev\MicroservicesUsingASP.NETCoreMongoDB\MicroservicesUsingASP.NETCoreMongoDB\obj\Docker\docker-compose.vs.debug.g.yml" -p dockercompose6193082444552166584 --ansi never up -d --no-build --force-recreate --remove-orphans Creating network "dockercompose6193082444552166584_default" 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 ["MicroservicesUsingASP.NETCoreMongoDB/MicroservicesUsingASP.NETCoreMongoDB.csproj", "MicroservicesUsingASP.NETCoreMongoDB/"] RUN dotnet restore "MicroservicesUsingASP.NETCoreMongoDB/MicroservicesUsingASP.NETCoreMongoDB.csproj" COPY . . WORKDIR "/src/MicroservicesUsingASP.NETCoreMongoDB" RUN dotnet build "MicroservicesUsingASP.NETCoreMongoDB.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "MicroservicesUsingASP.NETCoreMongoDB.csproj" -c Release -o /app/publish FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "MicroservicesUsingASP.NETCoreMongoDB.dll"]
سپس فایل های مربوط به 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: - "27017:27017" volumes: - mongo_data:/data/db microservicesusingasp.netcoremongodb: container_name: store.api environment: - ASPNETCORE_ENVIRONMENT=Development - "DatabaseSettings:ConnectionString=mongodb://storedb:27017" depends_on: - storedb ports: - "8080:80"
برای سرویس 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 پروژه به شرح زیر تغییر داده شود
و در نهایت این هم از نتیجه اجرای پروژه ای که بر روی داکر پابلیش شده است
اگر بخواهید پروژه را بصورت مستقیم بدون محیط ویژال استادیو اجرا کنیم کافی وارد پوشه پروژه شده و دستور زیر را اجرا کنید
docker-compose -f docker-compose.yml -f docker-compose.override.yml up -d
در دوره های آموزش تضمینی مجتمع فنی ارومیه که به صورت خصوصی و عمومی در دو شیوه حضوری و آنلاین برگزار می شود سرفصل های بسیار متنوع و کاربردی را بصورت پروژه محور آموزش داده می شود تا شخص کارآموز بتواند بلافاصله پس از اتمام این دوره در کمترین زمان ممکن وارد بازار کار شود.
آموزش تخصص ماست با ما حرفه ای شوید
جهت مشاوره با شماره 09149431772 در ارتباط باشید ...