این بخش نحوه ایجاد یک میکروسرویس ساده را توضیح می دهد که عملیات ایجاد، خواندن، به روز رسانی و حذف (CRUD) را بر روی یک منبع داده انجام می دهد.
از نظر طراحی، این نوع میکروسرویس کانتینری بسیار ساده است. شاید مشکل برای حل ساده باشد، یا شاید پیاده سازی تنها یک اثبات مفهوم باشد.
نمونه ای از این نوع سرویس داده درایو ساده، ریزسرویس کاتالوگ از برنامه نمونه eShopOnContainers است. این نوع سرویس تمام عملکردهای خود را در یک پروژه ASP.NET Core Web API که شامل کلاس هایی برای مدل داده، منطق تجاری و کد دسترسی به داده است، پیاده سازی می کند. همچنین داده های مرتبط خود را در یک پایگاه داده در حال اجرا در SQL Server (به عنوان یک محفظه دیگر برای اهداف توسعه/آزمایش) ذخیره می کند، می تواند هر میزبان معمولی SQL Server نیز باشد.
وجود پایگاه داده در همان میزبان Docker ممکن است برای توسعه خوب باشد، اما برای تولید نه. هنگامی که در حال توسعه این نوع سرویس هستید، فقط به ASP.NET Core و یک API یا ORM دسترسی به داده مانند Entity Framework Core نیاز دارید. همچنین میتوانید ابرداده Swagger را بهطور خودکار از طریق Swashbuckle ایجاد کنید تا شرحی از آنچه خدمات شما ارائه میدهد، همانطور که در بخش بعدی توضیح داده شد، ارائه دهید.
توجه داشته باشید که اجرای یک سرور پایگاه داده مانند SQL Server در یک ظرف Docker برای محیط های توسعه عالی است، زیرا می توانید تمام وابستگی های خود را بدون نیاز به ارائه پایگاه داده در فضای ابری یا درون محل اجرا کنید. این رویکرد هنگام اجرای تست های یکپارچه سازی راحت است. با این حال، برای محیطهای تولید، اجرای یک سرور پایگاه داده در یک کانتینر توصیه نمیشود، زیرا معمولاً با این رویکرد دسترسی بالایی به دست نمیآورید. برای یک محیط تولید در Azure، توصیه می شود از Azure SQL DB یا هر فناوری پایگاه داده دیگری که می تواند دسترسی بالا و مقیاس پذیری بالا را ارائه دهد، استفاده کنید. به عنوان مثال، برای یک رویکرد NoSQL، ممکن است CosmosDB را انتخاب کنید.
در نهایت، با ویرایش فایلهای فراداده Dockerfile و docker-compose.yml، میتوانید نحوه ایجاد تصویر این کانتینر را پیکربندی کنید - از چه تصویری پایه استفاده میکند، به علاوه تنظیمات طراحی مانند نامهای داخلی و خارجی و پورتهای TCP.
برای پیاده سازی یک میکروسرویس ساده CRUD با استفاده از دات نت و ویژوال استودیو، با ایجاد یک پروژه ASP.NET Core Web API ساده (که بر روی دات نت اجرا می شود تا بتواند روی هاست لینوکس داکر اجرا شود) شروع می کنید.
برای ایجاد یک پروژه ASP.NET Core Web API، ابتدا یک ASP.NET Core Web Application و سپس نوع API را انتخاب کنید. پس از ایجاد پروژه، میتوانید کنترلکنندههای MVC خود را مانند هر پروژه Web API دیگری با استفاده از Entity Framework API یا سایر API پیادهسازی کنید. در یک پروژه Web API جدید، می توانید ببینید که تنها وابستگی شما در آن میکروسرویس به خود ASP.NET Core است.
پروژه API شامل ارجاعاتی به بسته Microsoft.AspNetCore.App NuGet است که شامل ارجاع به تمام بسته های ضروری است. این می تواند شامل برخی از بسته های دیگر نیز باشد.
Entity Framework (EF) Core یک نسخه سبک، قابل توسعه و چند پلتفرمی از فناوری محبوب دسترسی به داده Entity Framework است. EF Core یک نگاشت شی-رابطه ای (ORM) است که به توسعه دهندگان دات نت امکان می دهد با استفاده از اشیاء دات نت با پایگاه داده کار کنند.
میکروسرویس کاتالوگ از EF و ارائه دهنده SQL Server استفاده می کند زیرا پایگاه داده آن در یک ظرف با تصویر SQL Server برای Linux Docker اجرا می شود. با این حال، پایگاه داده می تواند در هر سرور SQL، مانند Windows on-premises یا Azure SQL DB مستقر شود. تنها چیزی که باید تغییر دهید رشته اتصال در میکروسرویس ASP.NET Web API است.
با EF Core، دسترسی به داده ها با استفاده از یک مدل انجام می شود. یک مدل از کلاس های موجودیت (مدل دامنه) و یک زمینه مشتق شده (DbContext) تشکیل شده است که یک جلسه با پایگاه داده را نشان می دهد و به شما امکان می دهد داده ها را پرس و جو کنید و ذخیره کنید. شما می توانید یک مدل از یک پایگاه داده موجود ایجاد کنید، به صورت دستی یک مدل را کدنویسی کنید تا با پایگاه داده خود مطابقت داشته باشد، یا از تکنیک مهاجرت EF برای ایجاد یک پایگاه داده از مدل خود، با استفاده از رویکرد کد اول استفاده کنید (که باعث می شود پایگاه داده به عنوان مدل شما تکامل یابد. در طول زمان تغییر می کند). برای میکروسرویس کاتالوگ از آخرین رویکرد استفاده شده است. می توانید نمونه ای از کلاس موجودیت CatalogItem را در مثال کد زیر مشاهده کنید، که یک کلاس موجودیت ساده Plain Old Class Object (POCO) است.
public class CatalogItem
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string PictureFileName { get; set; }
public string PictureUri { get; set; }
public int CatalogTypeId { get; set; }
public CatalogType CatalogType { get; set; }
public int CatalogBrandId { get; set; }
public CatalogBrand CatalogBrand { get; set; }
public int AvailableStock { get; set; }
public int RestockThreshold { get; set; }
public int MaxStockThreshold { get; set; }
public bool OnReorder { get; set; }
public CatalogItem() { }
// Additional code ...
}
شما همچنین به یک DbContext نیاز دارید که یک جلسه با پایگاه داده را نشان دهد. برای میکروسرویس کاتالوگ، کلاس CatalogContext از کلاس پایه DbContext مشتق شده است، همانطور که در مثال زیر نشان داده شده است:
public class CatalogContext : DbContext
{
public CatalogContext(DbContextOptions<CatalogContext> options) : base(options)
{ }
public DbSet<CatalogItem> CatalogItems { get; set; }
public DbSet<CatalogBrand> CatalogBrands { get; set; }
public DbSet<CatalogType> CatalogTypes { get; set; }
// Additional code ...
}
می توانید پیاده سازی های اضافی DbContext داشته باشید. به عنوان مثال، در نمونه ریزسرویس Catalog.API، یک DbContext دوم به نام CatalogContextSeed وجود دارد که در اولین باری که سعی می کند به پایگاه داده دسترسی پیدا کند، به طور خودکار داده های نمونه را پر می کند. این روش برای داده های آزمایشی و برای سناریوهای آزمایش خودکار نیز مفید است.
در DbContext، شما از روش OnModelCreating برای سفارشی کردن نگاشت های موجودیت شی/پایگاه داده و سایر نقاط توسعه پذیری EF استفاده می کنید.
نمونههای کلاسهای موجودیت شما معمولاً از پایگاه داده با استفاده از زبان یکپارچه Query (LINQ) بازیابی میشوند، همانطور که در مثال زیر نشان داده شده است:
[Route("api/v1/[controller]")]
public class CatalogController : ControllerBase
{
private readonly CatalogContext _catalogContext;
private readonly CatalogSettings _settings;
private readonly ICatalogIntegrationEventService _catalogIntegrationEventService;
public CatalogController(
CatalogContext context,
IOptionsSnapshot<CatalogSettings> settings,
ICatalogIntegrationEventService catalogIntegrationEventService)
{
_catalogContext = context ?? throw new ArgumentNullException(nameof(context));
_catalogIntegrationEventService = catalogIntegrationEventService
?? throw new ArgumentNullException(nameof(catalogIntegrationEventService));
_settings = settings.Value;
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
}
// GET api/v1/[controller]/items[?pageSize=3&pageIndex=10]
[HttpGet]
[Route("items")]
[ProducesResponseType(typeof(PaginatedItemsViewModel<CatalogItem>), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(IEnumerable<CatalogItem>), (int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> ItemsAsync(
[FromQuery]int pageSize = 10,
[FromQuery]int pageIndex = 0,
string ids = null)
{
if (!string.IsNullOrEmpty(ids))
{
var items = await GetItemsByIdsAsync(ids);
if (!items.Any())
{
return BadRequest("ids value invalid. Must be comma-separated list of numbers");
}
return Ok(items);
}
var totalItems = await _catalogContext.CatalogItems
.LongCountAsync();
var itemsOnPage = await _catalogContext.CatalogItems
.OrderBy(c => c.Name)
.Skip(pageSize * pageIndex)
.Take(pageSize)
.ToListAsync();
itemsOnPage = ChangeUriPlaceholder(itemsOnPage);
var model = new PaginatedItemsViewModel<CatalogItem>(
pageIndex, pageSize, totalItems, itemsOnPage);
return Ok(model);
}
//...
}
داده ها با استفاده از نمونه هایی از کلاس های موجودیت شما در پایگاه داده ایجاد، حذف و اصلاح می شوند. میتوانید کدی مانند مثال سختکد زیر (در این مورد دادههای ساختگی) به کنترلکنندههای Web API خود اضافه کنید.
var catalogItem = new CatalogItem() {CatalogTypeId=2, CatalogBrandId=2,
Name="Roslyn T-Shirt", Price = 12};
_context.Catalog.Add(catalogItem);
_context.SaveChanges();
در ASP.NET Core، می توانید از تزریق وابستگی (DI) خارج از جعبه استفاده کنید. شما نیازی به راه اندازی یک کانتینر وارونگی کنترل (IoC) شخص ثالث ندارید، اگرچه در صورت تمایل می توانید کانتینر IoC مورد نظر خود را به زیرساخت هسته ASP.NET وصل کنید. در این حالت، به این معنی است که می توانید مستقیماً EF DBContext یا مخازن اضافی مورد نیاز را از طریق سازنده کنترلر تزریق کنید.
در کلاس CatalogController که قبلا ذکر شد، نوع CatalogContext (که از DbContext به ارث می رسد) همراه با سایر اشیاء مورد نیاز در سازنده(CatalogController) تزریق می شود.
یک پیکربندی مهم برای راه اندازی در پروژه Web API ثبت کلاس DbContext در ظرف IoC سرویس است. شما معمولاً این کار را در کلاس Startup با فراخوانی سرویس ها انجام می دهید. متد AddDbContext<CatalogContext>() در داخل متد ConfigureServices()، همانطور که در مثال ساده شده زیر نشان داده شده است:
public void ConfigureServices(IServiceCollection services)
{
// Additional code...
services.AddDbContext<CatalogContext>(options =>
{
options.UseSqlServer(Configuration["ConnectionString"],
sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.MigrationsAssembly(
typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
//Configuring Connection Resiliency:
sqlOptions.
EnableRetryOnFailure(maxRetryCount: 5,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null);
});
// Changing default behavior when client evaluation occurs to throw.
// Default in EFCore would be to log warning when client evaluation is done.
options.ConfigureWarnings(warnings => warnings.Throw(
RelationalEventId.QueryClientEvaluationWarning));
});
//...
}