EF Code First #14
احتمالا علت حذف لینکها در آن پروژه این بوده: من یک سری لینک دارم. اما زمان ارسال به سرور نمیدانم کدام یکی جدید است و کدام یکی دارد ویرایش میشود. برای حل این مساله باید id هر رکورد را در یک فیلد مخفی کنار لینک قرار داد؛ یا حتی در یک ویژگی data-*. بعد هنگام ارسال به سرور، بر اساس این idها میشود تصمیم گیری کرد. اگر رکوردی جدید است و میشود به صورت پویا ردیفی را به لیست اضافه کرد، این id وجود ندارد. اگر قدیمی است، id آن دقیقا مشخص است و به سرور ارسال میشود. ضمن اینکه با داشتن این id حتی دیگر نیازی به واکشی رکورد متناظر آن از دیتابیس نخواهد بود. میشود به کمک روش علامتگذاری یک شیء به صورت EntityState.Modified، آنرا وارد سیستم Tracking کرد. در این مورد در مطلب «کار با کلیدهای اصلی و خارجی در EF Code first» بیشتر بحث شده و نکتهی مهم آن، کار کردن با Id یک شیء است در ارتباطات و تعریف صریح آن توسط ویژگی ForeignKey. همچنین مطلب «رفتار متصل و غیر متصل در EF چیست؟» نیز مفید است.
- ضمنا نیازی نیست اطلاعات select را در سمت سرور تولید کنید. امکان دریافت JSON از سرور و تبدیل آن به فرمت مورد نظر در سمت کلاینت هم پیش بینی شدهاست:
editoptions: { dataUrl: '...url to get json....', buildSelect: function (response) { var data = typeof response === "string" ? $.parseJSON(response.responseText) : response, var s = "<select>"; s += '<option value="0">--No Manager--</option>'; $.each(data, function () { s += '<option value="' + this.EmployeeId + '">' + this.EmployeeName + '</option>'; }); return s + "</select>"; } }
بازنویسی سطح دوم کش برای Entity framework 6
- اما در کل مشکلی با متدهای Async اصلی EF ندارد و به اندازهی کافی در این مورد آزمونهای واحد تهیه شدهاست.
var searchLocation = DbGeography.FromText(String.Format("POINT({0} {1})", longitude, latitude)); var nearbyLocations = (from location in _context.GeoLocations where // (Additional filtering criteria here...) select new { LocationID = location.ID, // ... Distance = searchLocation.Distance( DbGeography.FromText("POINT(" + location.Longitude + " " + location.Latitude + ")")) }) .OrderBy(location => location.Distance) .ToList();
نگاهی به محتوا و نحوهی تشکیل ایندکسهای FTS
متد sys.dm_fts_index_keywords
این متد محتوای full-text index یک جدول را باز میگرداند. از آن میتوان برای موارد ذیل استفاده کرد:
- آیا واژه کلیدی خاصی جزو full-text index است؟
- چه تعداد رکورد دارای واژهی کلیدی خاصی هستند؟
- متداولترین واژههای کلیدی موجود در ایندکس کدامند؟
- کدام واژه را میتوان به عنوان stop word تشخیص داد؟ شاید پس از بررسی، تشخیص داده شود که بهتر است متداولترین واژهی کلیدی ایندکس شده، به stop list اضافه شود.
SELECT * FROM sys.dm_fts_index_keywords(DB_ID(DB_NAME()), OBJECT_ID(N'dbo.Documents'));
متد sys.dm_fts_index_keywords_by_document
این متد اطلاعاتی را در سطح اسناد باز میگرداند. کاربردهای آن میتوانند شامل موارد زیر باشند:
- یافتن جمع تعداد واژههای کلیدی که یک full-text index دارا است.
- آیا واژهی کلیدی مورد نظر، در ردیف در حال بررسی وجود دارد؟
- یک واژهی کلیدی چندبار در کل ایندکس ظاهر شدهاست؟
- یک واژهی کلیدی در یک ردیف یا سند مشخص، چندبار تکرار شدهاست؟
- یک ردیف یا سند، از چند واژهی کلیدی تشکیل شدهاست؟
SELECT I.document_id, D.title, I.display_term, I.occurrence_count FROM sys.dm_fts_index_keywords_by_document(DB_ID(DB_NAME()), OBJECT_ID(N'dbo.Documents')) AS I INNER JOIN dbo.Documents D ON D.id = I.document_id;
متد sys.dm_fts_index_keywords_by_property
در قسمتهای قبل، خواص و متادیتای اسناد آفیس را نیز ایندکس کردیم. این متد، اطلاعات مرتبط با خواص اسناد موجود در full-text index را باز میگرداند.
کاربردهای آن:
- چه محتوایی، در خاصیتی مشخص از سندی معلوم، ذخیره شدهاست؟
- خاصیت مورد نظر چه اندازه بکار رفته و تکرار شدهاست؟
- چه اسنادی دارای خاصیتی مشخص هستند؟
SELECT I.document_id, D.title, I.display_term, I.property_id FROM sys.dm_fts_index_keywords_by_property(DB_ID(DB_NAME()), OBJECT_ID(N'dbo.Documents')) AS I INNER JOIN dbo.Documents D ON D.id = I.document_id;
متد sys.dm_fts_parser
متدهای قبلی که بررسی کردیم، نیاز به یک جدول و وجود full-text index بر روی آن دارند؛ اما متد dm_fts_parser خیر. این متد یک ورودی را گرفته و سپس تمام مراحل تهیهی یک full-text index را به صورت پویا انجام میدهد.
کاربردهای آن:
- درک اینکه موتور FTS با یک ورودی رشتهای چگونه رفتار میکند.
- استخراج ایندکسهای یک متن و ذخیرهی دستی آن در یک جدول.
- استخراج واژههای کلیدی یک رشته.
- آنالیز پویای INFLECTIONAL (مانند مثال زیر)
SELECT display_term, keyword FROM sys.dm_fts_parser(N'"Mycustom string"', 1033, NULL, 0);
SELECT * FROM sys.dm_fts_parser('FORMSOF(INFLECTIONAL,'+ 'term' + ')', 1033, NULL, 0);
در اینجا پارامتر دوم آن شماره زبان مورد استفاده است. پارامتر سوم مشخص کنندهی stop list میتواند باشد و پارامتر سوم حساسیت به لهجه را مشخص میکند.
#Execute VB code via C
static void AddChartButton( Workbook workBook, Worksheet xlWorkSheetNew, Range currentRange, int macroId, int startRow, int endRow, int startCol, int endCol, string buttonImagePath ) { var cell = currentRange.Next; var width = cell.Width; var height = 24; var left = cell.Left; var top = System.Math.Max( cell.Top + cell.Height - height, 0 ); var button = xlWorkSheetNew.Shapes.AddPicture( buttonImagePath, MsoTriState.msoFalse, MsoTriState.msoCTrue, left, top, width, height ); var module = workBook.VBProject.VBComponents.Add( vbext_ComponentType.vbext_ct_StdModule ); module.CodeModule.AddFromString( GetMacro( macroId, startRow, endRow, startCol, endCol ) ); button.OnAction = "Macro" + macroId; } static string GetMacro( int macroId, int startRow, int endRow, int startCol, int endCol ) { var sb = new StringBuilder(); var range = "ActiveSheet.Range(Cells(" + startRow + "," + startCol + "), Cells(" + endRow + "," + endCol + ")).Select"; sb.AppendLine( "Sub Macro" + macroId + "()" ); sb.AppendLine( "On Error Resume Next" ); sb.AppendLine( range ); sb.AppendLine( "ActiveSheet.Shapes.AddChart.Select" ); sb.AppendLine( "ActiveChart.ChartType = xlColumn" ); sb.AppendLine( "ActiveChart.SetSourceData Source:=" + range ); sb.AppendLine( "On Error GoTo 0" ); sb.AppendLine( "End Sub" ); return sb.ToString(); }
و برای استفاده از آن میتوان مانند مثال زیر عمل کرد:
var excelApp = new Microsoft.Office.Interop.Excel.Application(); var fileName = @"C:\Users\Vahid\Desktop\VBA.xlsm"; var workBook = excelApp.Workbooks.Open( fileName ); var sheet = workBook.Sheets[1]; AddChartButton( workBook, sheet, sheet.Range["B1"], 1231, 1, 10, 1, 2, @"C:\Users\Vahid\Desktop\BarChart.png"); excelApp.DisplayAlerts = false; workBook.Close( true, fileName );
خروجی مثال بالا
نکته: در صورتیکه بعد از اجرای برنامه، خطای " programmatic access to visual basic project is not trusted" رخ داد از این طریق میتوانید مشکل را حل کنید.
File -> Options -> Trust Center -> Trust Center Settings -> Macro Settings -> Trust Access to the VBA Project object model
volatile
class Program { volatile bool _shouldPartyContinue = true; static void Main() { var firstDimension = new Program(); var secondDimension = new Thread( firstDimension.StartPartyInAnotherDimension ); secondDimension.Start( firstDimension ); Thread.Sleep( 5000 ); firstDimension._shouldPartyContinue = false; Console.WriteLine( "Party Finish" ); } void StartPartyInAnotherDimension( object input ) { var currentDimensionInput = (Program)input; Console.WriteLine( "let the party begin" ); while ( currentDimensionInput._shouldPartyContinue ) {} Console.WriteLine( "Party ends: (" ); } }
::global
class Program { public static void Main(string[] args) { Console.WriteLine( Number ); // Error global::System.Console.WriteLine( "Console: " + Console ); //OK } public class System { } // Define a constant called ‘Console’ to cause more problems. const int Console = 7; const int Number = 67; }
DebuggerDisplayAttribute
[DebuggerDisplay( "{DebuggerDisplay}" )] public class DebuggerDisplayTest { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } [DebuggerBrowsable( DebuggerBrowsableState.Never )] string DebuggerDisplay => $"{FirstName} {LastName} {Age} years old"; }
[DebuggerDisplay( "Age {Age > 0 ? Age : 25}" )] public class DebuggerDisplayTest { //... }
- «صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid »
- «استفاده از Kendo UI templates»
صورت مساله
میخواهیم به یک چنین تصویری برسیم؛ که دارای گروه بندی اطلاعات است، فرمت شرطی روی ستون قیمت آن اعمال شده و تاریخ نمایش داده شده در آن نیز شمسی است. همچنین برای مثال ستون قیمت آن دارای ته جمع صفحه بوده و به علاوه یک دکمهی سفارشی به نوار ابزار آن اضافه شدهاست.
مباحث قسمت سمت سرور این مثال با مطلب «صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid» دقیقا یکی است. فقط یک خاصیت AddDate نیز در اینجا اضافه شدهاست.
تغییر نحوهی نمایش pager
اگر به قسمت pager تصویر فوق دقت کنید، یک دکمهی refresh، تعداد موارد هر صفحه و امکان وارد کردن دستی شماره صفحه، در آن پیش بینی شدهاست. این موارد را با تنظیمات ذیل میتوان فعال کرد:
$("#report-grid").kendoGrid({ // ... pageable: { previousNext: true, // default true numeric: true, // default true buttonCount: 5, // default 10 refresh: true, // default false input: true, // default false pageSizes: true // default false },
بومی سازی پیغامهای گرید
پیغامهای فارسی را که در تصویر فوق مشاهده میکنید، حاصل پیوست فایل kendo.fa-IR.js هستند:
<!--https://github.com/loudenvier/kendo-global/blob/master/lang/kendo.fa-IR.js--> <script src="js/messages/kendo.fa-IR.js" type="text/javascript"></script>
گروه بندی اطلاعات
برای گروه بندی اطلاعات در Kendo UI Grid دو قسمت باید تغییر کنند.
ابتدا باید فیلد پیش فرض گروه بندی در قسمت data source گرید تعریف شود:
var productsDataSource = new kendo.data.DataSource({ // ... group: { field: "IsAvailable" }, // ... });
$("#report-grid").kendoGrid({ // ... groupable: true, // allows the user to alter what field the grid is grouped by // ...
اضافه کردن ته جمعهای ستونها
این ته جمعها که aggregate نام دارند باید در دو قسمت فعال شوند:
var productsDataSource = new kendo.data.DataSource({ //... aggregate: [ { field: "Name", aggregate: "count" }, { field: "Price", aggregate: "sum" } ] //... });
سپس این متدها را میتوان مطابق فرمت hash syntax قالبهای Kendo UI در قسمت footerTemplate هر ستون تعریف کرد:
$("#report-grid").kendoGrid({ // ... columns: [ { field: "Name", title: "نام محصول", footerTemplate: "تعداد: #=count#" }, { field: "Price", title: "قیمت", footerTemplate: "جمع: #=kendo.toString(sum,'c0')#" } ] // ... });
فرمت شرطی اطلاعات
در ستون قیمت، میخواهیم اگر قیمتی بیش از 2490 بود، با پس زمینهی قهوهای و رنگ زرد نمایش داده شود. برای این منظور میتوان یک قالب Kendo UI سفارشی را طراحی کرد:
<script type="text/x-kendo-template" id="priceTemplate"> #if( Price > 2490 ) {# <span style="background:brown; color:yellow;">#=kendo.toString(Price,'c0')#</span> #} else {# #= kendo.toString(Price,'c0')# #}# </script>
$("#report-grid").kendoGrid({ //... columns: [ { field: "Price", title: "قیمت", template: kendo.template($("#priceTemplate").html()), footerTemplate: "جمع: #=kendo.toString(sum,'c0')#" } ] //... });
فرمت تاریخ میلادی به شمسی در حین نمایش
برای تبدیل سمت کلاینت تاریخ میلادی به شمسی از کتابخانهی moment-jalaali.js کمک گرفته شدهاست:
<!--https://github.com/moment/moment/--> <script src="js/cultures/moment.min.js" type="text/javascript"></script> <!--https://github.com/jalaali/moment-jalaali--> <script src="js/cultures/moment-jalaali.js" type="text/javascript"></script>
$("#report-grid").kendoGrid({ //... columns: [ { field: "AddDate", title: "تاریخ ثبت", template: "#=moment(AddDate).format('jYYYY/jMM/jDD')#" } ] //... });
اضافه کردن یک دکمه به نوار ابزار گرید
نوار ابزار Kendo UI Grid را نیز میتوان توسط یک قالب سفارشی آن مقدار دهی کرد:
$("#report-grid").kendoGrid({ // ... toolbar: [ { template: kendo.template($("#toolbarTemplate").html()) } ] // ... });
<script> // این اطلاعات برای تهیه خروجی سمت سرور مناسب هستند function getCurrentGridFilters() { var dataSource = $("#report-grid").data("kendoGrid").dataSource; var gridState = { page: dataSource.page(), pageSize: dataSource.pageSize(), sort: dataSource.sort(), group: dataSource.group(), filter: dataSource.filter() }; return kendo.stringify(gridState); } </script> <script id="toolbarTemplate" type="text/x-kendo-template"> <a class="k-button" href="\#" onclick="alert('gridState: ' + getCurrentGridFilters());">نوار ابزار سفارشی</a> </script>
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید:
KendoUI05.zip
پروژه DNTFrameworkCore که قصد پشتیبانی از آن را دارم، یک زیرساخت سبک وزن و توسعه پذیر با پشتیبانی از طراحی چند مستاجری، با تمرکز بر کاهش زمان و افزایش کیفیت توسعه سیستمهای تحت وب مبتنی بر ASP.NET Core، توسعه داده شده است.
اهدافی که این زیرساخت دنبال میکند
- ارائه ساختارهای مشترک بین پروژههای مختلف از جمله Cross-Cutting Concernها و ...
- دنبال کردن اصل DRY به منظور متمرکز شدن صرف برروی منطق تجاری سیستم نه انجام و حل یکسری مسائل تکراری
- کاهش زمان توسعه و اختصاص زمان بیشتر برای نوشتن آزمونهای واحد منطق تجاری
- کاهش باگ و جلوگیری از پخش شدن باگهای پیاده سازی در سراسر سیستم
- کاهش زمان آموزش نیروهای جدید برای ملحق شدن به تیم تولید شما با حداقل دانش طراحی و برنامه نویسی شیء گرا
- ارائه راهکاری یکپارچه برای توسعه پذیر بودن منطق تجاری پیاده سازی شده از طریق در معرض دید قرار دادن یکسری «Extensibility Point» با استفاده از رویکرد Event-Driven
امکانات این زیرساخت در زمان نگارش مطلب جاری
- مکانیزم اعتبارسنجی خودکار ورودیهای متدهای مرتبط با منطق تجاری
- مکانیزم به روز رسانی یک AggregateRoot، به همراه موجودیتهای وابسته به آن (سناریوهای Master-Detail)
- مکانیزم Eventing، به منظور آگاهی از تغییرات و رخدادهای یک AggregateRoot خاص
- مکانیزم مدیریت خودکار تراکنشها
- مکانیزم شماره گذاری و تولید خودکار کد منحصر به فرد برای موجودیتهای سیستم
- اعمال مفاهیم Functional Programming برای مدیریت خطاهای قابل پیش بینی و همچنین مواجهه با حالتهای شکست متدها
- مکانیزم اعمال دسترسیهای پویا
- پیاده سازی سرویس CRUD پایه، مبتنی بر EF Core
- پیاده سازی کنترلر CRUD پایه، مبتنی بر ASP.NET Core Web API
- پروایدر Logging به منظور ذخیره سازی لاگ سیستم در بانک اطلاعاتی، با استفاده از EF Core
- مکانیزم Auditing به منظور ذخیره اطلاعات آماری از وضعیت انجام شدن متدها به همراه ورودی ها، خروجی و همچنین موفقیت یا عدم موفقیت آنها در بانک اطلاعاتی با پروایدر مبتنی بر EF Core
- مکانیزم ذخیره سازی کلیدهای موقتی تولید شده Data Protecction API در بانک اطلاعاتی با استفاده از EF Core
- مکانیزم Configuration به منظور ذخیره سازی و خواندن تنظیمات مبتنی بر Name-Value در بانک اطلاعاتی با استفاده از EF Core
- مکانیزم Hooks به منظور توسعه پذیر کردن DbContext مبتنی EF Core به همراه تعدادی Hook پیش فرض تعریف شده در زیرساخت
- مکانیزم ردیابی تغییرات
- امکان طراحی چند مستاجری به همراه مکانیزم فیلتر خودکار اطلاعات با امکان غیرفعال کردن آن مبتنی بر EF Core
- مکانیزم حذف نرم به همراه فیلتر خودکار اطلاعات حذف شده با امکان غیرفعال کردن آن مبتنی بر EF Core
- بسته نیوگت DNTFrameworkCore.FluentValidation به عنوان Adapter کتابخانه FluentValidation با مکانیزم اعتبارسنجی خودکار ورودیهای متدها
- کتابخانه DNTFrameworkCore.Cqrs به عنوان ابزار کمکی برای اعمال الگوی معماری CQRS (به زودی)
- امکان انجام کارهای طولانی در پس زمینه
- لاگ تغییرات موجودیتها یا Entity History (به زودی)
نحوه استفاده از بستههای نیوگت مرتبط
PM> Install-Package DNTFrameworkCore -Version 1.0.0
services.AddDNTFramework() .AddDataAnnotationValidation() .AddModelValidation() .AddValidationOptions(options => { /*options.IgnoredTypes.Add(typeof());*/ }) .AddMemoryCache() .AddAuditingOptions(options => { // options.Enabled = true; // options.EnabledForAnonymousUsers = false; // options.IgnoredTypes.Add(typeof()); // options.Selectors.Add(new NamedTypeSelector("SelectorName", type => type == typeof())); }).AddTransactionOptions(options => { // options.Timeout=TimeSpan.FromMinutes(3); //options.IsolationLevel=IsolationLevel.ReadCommitted; });
متدهای الحاقی بالا برای ثبت سرویسها و تنظیمات مرتبط با مکانیزمهای اعتبارسنجی خودکار، مدیریت تراکنشها، لاگ آماری، Eventing و سایر امکانات ذکر شده، در IoC Container توکار ASP.NET Core استفاده خواهند شد.
PM> Install-Package DNTFrameworkCore.EntityFramework -Version 1.0.0
services.AddDNTUnitOfWork<ProjectDbContext>();
بسته نیوگت بالا شامل پیاده سازی مبتنی بر EF Core برای واسطهای تعریف شده در بسته نیوگت DNTFrameworkCore، میباشد؛ از جمله آن میتوان به CrudService پایه اشاره کرد. متد الحاقی AddDNTUnitOfWork برای ثبت و معرفی واسطهای IUnitOfWork و ITransactionProvider به عنوان مهیا کننده تراکنش به همراه پیاده سازهای آنها و همچنین ثبت یک سری Hook تعریف شده برای ردیابی تغییرات، در سیستم تزریق وابستگی، استفاده خواهد شد.
همچنین با نصب بسته بالا، امکان استفاده از مهیا کننده Logging با امکان ذخیره سازی در بانک اطلاعاتی را خواهید داشت:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseDefaultServiceProvider((context, options) => { options.ValidateScopes = context.HostingEnvironment.IsDevelopment(); }) .ConfigureLogging((hostingContext, logging) => { logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); logging.AddConsole(); logging.AddDebug(); logging.AddEntityFramework<ProjectDbContext>(options => options.MinLevel = LogLevel.Warning); }) .UseStartup<Startup>();
متد جنریک الحاقی AddEntityFramework برای ثبت مهیا کننده مذکور استفاده میشود.
PM> Install-Package DNTFrameworkCore.Web -Version 1.0.0
بسته نیوگت بالا شامل یکسری سرویس برای اعمال دسترسیهای پویا، CrudController مبتنی بر ASP.NET Core Web API، فیلتر مدیریت سراسری خطاهای برنامه و سایر امکاناتی که در ادامه مقالات با جزئیات بیشتری بررسی خواهیم کرد، میباشد. برای ثبت سرویسهای تعریف شده میتوانید از متد الحاقی AddDNTCommonWeb و به منظور تغییر محل ذخیره سازی کلیدهای موقت رمزنگاری مرتبط با Data Protection API و انتقال آنها به بانک اطلاعاتی، استفاده کنید.
services.AddDNTCommonWeb() .AddDNTDataProtection();
نکته: برای انتقال کلیدهای موقت رمزنگاری به بانک اطلاعاتی، نیاز است تا از متد الحاقی زیر که در بسته نیوگت DNTFrameworkCore.EntityFramework موجود میباشد، به شکل زیر استفاده کنید:
services.AddDNTProtectionRepository<ProjectDbContext>();
PM> Install-Package DNTFrameworkCore.EntityFramework.SqlServer -Version 1.0.0
بسته بالا از امکانات مخصوص SqlServer برای اعمال قفل منطقی برای مدیریت مباحث همزمانی استفاده میکند؛ همچنین PreUpdateHook مرتبط با تولید خودکار کد منحصر به فرد، در این کتابخانه پیاده سازی شده است. به شکل زیر میتوانید سرویسهای مرتبط با آن را به سیستم تزریق وابستگیهای معرفی کنید:
services.AddDNTNumbering(options => { options.NumberedEntityMap[typeof(Task)] = new NumberedEntityOption { Start = 100, Prefix = "Task-", IncrementBy = 5 }; });
به عنوان مثال برای شماره گذاری موجودیت Task، لازم است تنظیمات مرتبط آن را به شکل بالا به سیستم شماره گذاری معرفی کنید.
اگر قصد استفاده از کتابخانه FluentValidation را داشته باشید، میبایست بسته زیر را نیز نصب کنید:
PM> Install-Package DNTFrameworkCore.FluentValidation -Version 1.0.0
برای ثبت و معرفی Adapter مرتبط، به سیستم اعتبارسنجی خودکار معرفی شده، لازم است از طریق متد الحاقی AddFluentModelValidation به شکل زیر اقدام کنید:
services.AddDNTFramework() .AddDataAnnotationValidation() .AddModelValidation() .AddFluentModelValidation() .AddValidationOptions(options => { /*options.IgnoredTypes.Add(typeof());*/ }) .AddMemoryCache() .AddAuditingOptions(options => { // options.Enabled = true; // options.EnabledForAnonymousUsers = false; // options.IgnoredTypes.Add(typeof()); // options.Selectors.Add(new NamedTypeSelector("SelectorName", type => type == typeof())); }).AddTransactionOptions(options => { // options.Timeout=TimeSpan.FromMinutes(3); //options.IsolationLevel=IsolationLevel.ReadCommitted; });
برای شروع پروژه جدید، نصب این بستهها کفایت میکند. اگر نیاز به طراحی MultiTenancy دارید، بسته زیر را برای شناسایی Tenant جاری و از این قبیل کارها نیز میبایست نصب کنید:
PM> Install-Package DNTFrameworkCore.Web.MultiTenancy -Version 1.0.0
services.AddMultiTenancy<TenantResolver>();
app.UseMultiTenancy();
services.Scan(scan => scan .FromCallingAssembly() .AddClasses(classes => classes.AssignableTo<ISingletonDependency>()) .AsMatchingInterface() .WithSingletonLifetime() .AddClasses(classes => classes.AssignableTo<IScopedDependency>()) .AsMatchingInterface() .WithScopedLifetime() .AddClasses(classes => classes.AssignableTo<ITransientDependency>()) .AsMatchingInterface() .WithTransientLifetime() .AddClasses(classes => classes.AssignableTo(typeof(IDomainEventHandler<>))) .AsImplementedInterfaces() .WithTransientLifetime()); foreach (var descriptor in services.Where(s => typeof(IApplicationService).IsAssignableFrom(s.ServiceType)) .ToList()) { services.Decorate(descriptor.ServiceType, (target, serviceProvider) => ProxyGenerator.CreateInterfaceProxyWithTargetInterface( descriptor.ServiceType, target, serviceProvider.GetRequiredService<ValidationInterceptor>(), (IInterceptor) serviceProvider.GetRequiredService<TransactionInterceptor>())); }