یک CMS تجاری بزرگ با قابلیتهای زیر
پشتیبانی از Full Text Search در SQL Server
Full Text Search یا به اختصار FTS یکی از قابلیتهای SQL Server جهت جستجوی پیشرفته در متون میباشد. این قابلیت تا کنون در EF 6.1.1 ایجاد نشده است.
در ادامه پیاده سازی از FTS در EF را مشاهده مینمایید.
جهت ایجاد قابلیت FTS از متد Contains در Linq استفاده شده است.
ابتدا متدهای الحاقی جهت اعمال دستورات FREETEXT و CONTAINS اضافه میشود.سپس دستورات تولیدی EF را قبل از اجرا بر روی بانک اطلاعاتی توسط امکان Command Interception به دستورات FTS تغییر میدهیم.
همانطور که میدانید دستور Contains در Linq توسط EF به دستور LIKE تبدیل میشود. به جهت اینکه ممکن است بخواهیم از دستور LIKE نیز استفاده کنیم یک پیشوند به مقادیری که میخواهیم به دستورات FTS تبدیل شوند اضافه مینماییم.
جهت استفاده از Fts در EF کلاسهای زیر را ایجاد نمایید.
کلاس FullTextPrefixes :
/// <summary> /// /// </summary> public static class FullTextPrefixes { /// <summary> /// /// </summary> public const string ContainsPrefix = "-CONTAINS-"; /// <summary> /// /// </summary> public const string FreetextPrefix = "-FREETEXT-"; /// <summary> /// /// </summary> /// <param name="searchTerm"></param> /// <returns></returns> public static string Contains(string searchTerm) { return string.Format("({0}{1})", ContainsPrefix, searchTerm); } /// <summary> /// /// </summary> /// <param name="searchTerm"></param> /// <returns></returns> public static string Freetext(string searchTerm) { return string.Format("({0}{1})", FreetextPrefix, searchTerm); } }
کلاس جاری جهت علامت گذاری دستورات FTS میباشد و توسط متدهای الحاقی و کلاس FtsInterceptor استفاده میگردد.
کلاس FullTextSearchExtensions :
public static class FullTextSearchExtensions { /// <summary> /// /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="source"></param> /// <param name="expression"></param> /// <param name="searchTerm"></param> /// <returns></returns> public static IQueryable<TEntity> FreeTextSearch<TEntity>(this IQueryable<TEntity> source, Expression<Func<TEntity, object>> expression, string searchTerm) where TEntity : class { return FreeTextSearchImp(source, expression, FullTextPrefixes.Freetext(searchTerm)); } /// <summary> /// /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="source"></param> /// <param name="expression"></param> /// <param name="searchTerm"></param> /// <returns></returns> public static IQueryable<TEntity> ContainsSearch<TEntity>(this IQueryable<TEntity> source, Expression<Func<TEntity, object>> expression, string searchTerm) where TEntity : class { return FreeTextSearchImp(source, expression, FullTextPrefixes.Contains(searchTerm)); } /// <summary> /// /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="source"></param> /// <param name="expression"></param> /// <param name="searchTerm"></param> /// <returns></returns> private static IQueryable<TEntity> FreeTextSearchImp<TEntity>(this IQueryable<TEntity> source, Expression<Func<TEntity, object>> expression, string searchTerm) { if (String.IsNullOrEmpty(searchTerm)) { return source; } // The below represents the following lamda: // source.Where(x => x.[property].Contains(searchTerm)) //Create expression to represent x.[property].Contains(searchTerm) //var searchTermExpression = Expression.Constant(searchTerm); var searchTermExpression = Expression.Property(Expression.Constant(new { Value = searchTerm }), "Value"); var checkContainsExpression = Expression.Call(expression.Body, typeof(string).GetMethod("Contains"), searchTermExpression); //Join not null and contains expressions var methodCallExpression = Expression.Call(typeof(Queryable), "Where", new[] { source.ElementType }, source.Expression, Expression.Lambda<Func<TEntity, bool>>(checkContainsExpression, expression.Parameters)); return source.Provider.CreateQuery<TEntity>(methodCallExpression); }
در این کلاس متدهای الحاقی جهت اعمال قابلیت Fts ایجاد شده است.
متد FreeTextSearch جهت استفاده از دستور FREETEXT استفاده میشود.در این متد پیشوند -FREETEXT- جهت علامت گذاری این دستور به ابتدای مقدار جستجو اضافه میشود. این متد دارای دو پارامتر میباشد ، اولی ستونی که میخواهیم بر روی آن جستجوی FTS انجام دهیم و دومی عبارت جستجو.
متد ContainsSearch جهت استفاده از دستور CONTAINS استفاده میشود.در این متد پیشوند -CONTAINS- جهت علامت گذاری این دستور به ابتدای مقدار جستجو اضافه میشود. این متد دارای دو پارامتر میباشد ، اولی ستونی که میخواهیم بر روی آن جستجوی FTS انجام دهیم و دومی عبارت جستجو.
متد FreeTextSearchImp جهت ایجاد دستور Contains در Linq میباشد.
کلاس FtsInterceptor :
public class FtsInterceptor : IDbCommandInterceptor { /// <summary> /// /// </summary> /// <param name="command"></param> /// <param name="interceptionContext"></param> public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) { } /// <summary> /// /// </summary> /// <param name="command"></param> /// <param name="interceptionContext"></param> public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) { } /// <summary> /// /// </summary> /// <param name="command"></param> /// <param name="interceptionContext"></param> public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { RewriteFullTextQuery(command); } /// <summary> /// /// </summary> /// <param name="command"></param> /// <param name="interceptionContext"></param> public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { } /// <summary> /// /// </summary> /// <param name="command"></param> /// <param name="interceptionContext"></param> public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { RewriteFullTextQuery(command); } /// <summary> /// /// </summary> /// <param name="command"></param> /// <param name="interceptionContext"></param> public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { } /// <summary> /// /// </summary> /// <param name="cmd"></param> public static void RewriteFullTextQuery(DbCommand cmd) { var text = cmd.CommandText; for (var i = 0; i < cmd.Parameters.Count; i++) { var parameter = cmd.Parameters[i]; if ( !parameter.DbType.In(DbType.String, DbType.AnsiString, DbType.StringFixedLength, DbType.AnsiStringFixedLength)) continue; if (parameter.Value == DBNull.Value) continue; var value = (string)parameter.Value; if (value.IndexOf(FullTextPrefixes.ContainsPrefix, StringComparison.Ordinal) >= 0) { parameter.Size = 4096; parameter.DbType = DbType.AnsiStringFixedLength; value = value.Replace(FullTextPrefixes.ContainsPrefix, ""); // remove prefix we added n linq query value = value.Substring(1, value.Length - 2); // remove %% escaping by linq translator from string.Contains to sql LIKE parameter.Value = value; cmd.CommandText = Regex.Replace(text, string.Format( @"\[(\w*)\].\[(\w*)\]\s*LIKE\s*@{0}\s?(?:ESCAPE N?'~')", parameter.ParameterName), string.Format(@"CONTAINS([$1].[$2], @{0})", parameter.ParameterName)); if (text == cmd.CommandText) throw new Exception("FTS was not replaced on: " + text); text = cmd.CommandText; } else if (value.IndexOf(FullTextPrefixes.FreetextPrefix, StringComparison.Ordinal) >= 0) { parameter.Size = 4096; parameter.DbType = DbType.AnsiStringFixedLength; value = value.Replace(FullTextPrefixes.FreetextPrefix, ""); // remove prefix we added n linq query value = value.Substring(1, value.Length - 2); // remove %% escaping by linq translator from string.Contains to sql LIKE parameter.Value = value; cmd.CommandText = Regex.Replace(text, string.Format( @"\[(\w*)\].\[(\w*)\]\s*LIKE\s*@{0}\s?(?:ESCAPE N?'~')", parameter.ParameterName), string.Format(@"FREETEXT([$1].[$2], @{0})", parameter.ParameterName)); if (text == cmd.CommandText) throw new Exception("FTS was not replaced on: " + text); text = cmd.CommandText; } } } }
در این کلاس دستوراتی را که توسط متدهای الحاقی جهت امکان Fts علامت گذاری شده بودند را یافته و دستور LIKE را با دستورات CONTAINSو FREETEXT جایگزین میکنیم.
در ادامه برنامه ای جهت استفاده از این امکان به همراه دستورات تولیدی آنرا مشاهده مینمایید.
public class Note { /// <summary> /// /// </summary> public int Id { get; set; } /// <summary> /// /// </summary> public string NoteText { get; set; } } public class FtsSampleContext : DbContext { /// <summary> /// /// </summary> public DbSet<Note> Notes { get; set; } /// <summary> /// /// </summary> /// <param name="modelBuilder"></param> protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new NoteMap()); } } /// <summary> /// /// </summary> class Program { /// <summary> /// /// </summary> /// <param name="args"></param> static void Main(string[] args) { DbInterception.Add(new FtsInterceptor()); const string searchTerm = "john"; using (var db = new FtsSampleContext()) { var result1 = db.Notes.FreeTextSearch(a => a.NoteText, searchTerm).ToList(); //SQL Server Profiler result ===>>> //exec sp_executesql N'SELECT // [Extent1].[Id] AS [Id], // [Extent1].[NoteText] AS [NoteText] // FROM [dbo].[Notes] AS [Extent1] // WHERE FREETEXT([Extent1].[NoteText], @p__linq__0)',N'@p__linq__0 //char(4096)',@p__linq__0='(john)' var result2 = db.Notes.ContainsSearch(a => a.NoteText, searchTerm).ToList(); //SQL Server Profiler result ===>>> //exec sp_executesql N'SELECT // [Extent1].[Id] AS [Id], // [Extent1].[NoteText] AS [NoteText] // FROM [dbo].[Notes] AS [Extent1] // WHERE CONTAINS([Extent1].[NoteText], @p__linq__0)',N'@p__linq__0 //char(4096)',@p__linq__0='(john)' } Console.ReadKey(); } }
ابتدا کلاس FtsInterceptor را به EF معرفی مینماییم. سپس از دو متد الحاقی مذکور استفاده مینماییم. خروجی هر دو متد توسط SQL Server Profiler در زیر هر متد مشاهده مینمایید.
تمامی کدها و مثال مربوطه در آدرس https://effts.codeplex.com قرار گرفته است.
منبع:
Full Text Search in Entity Framework 6
- سرعت بالاتر بارگذاری و اجرای کدها
- استفاده از آخرین فناوریهای وب مانند ES 6 و وب کامپوننتها با پشتیبانی تا IE 9.
- سطح API آن با طراحی جدید آن، به شدت کاهش یافته و خلاصه شدهاست. همین امر یادگیری آنرا نیز سادهتر میکند.
برای یادگیری Angular 2 نیازی به فراگیری Angular 1 نیست. در اینجا با آشنایی با TypeScript، به این نتیجه خواهید رسید که برنامههای Angular 2 چیزی بیشتر از یک مثال عملی TypeScript نیستند. زبان TypeScript، زبان اول و توصیه شدهی کار با Angular 2 است و مزیت آن دسترسی به تمام قابلیتهای ES 6 است؛ با این تفاوت که کامپایلر TypeScript قادر است آنها را به ES 5 یا نگارش فعلی جاوا اسکریپت که توسط تمام مرورگرها پشتیبانی میشود، ترجمه و تبدیل کند. به این نحو به یک طراحی شیءگرا، مدرن و با قابلیت نگهداری بالا خواهید رسید که با تمام مرورگرهای جدید نیز سازگار است.
بنابراین پیشنیازهای اصلی کار با Angular 2، فراگیری ES 6 و TypeScript هستند که دو سری ویژه و مختص به آنها در سایت جاری تهیه شدهاند:
«مبانی ES 6»
«مبانی TypeScript»
در این قسمت قصد داریم پیشنیازهای دریافت و نصب اجزاء و وابستگیهای AngularJS 2 را به همراه TypeScript، در ویژوال استودیو 2015 بررسی کنیم. البته استفاده از ویژوال استودیو در اینجا ضروری نیست و اساسا AngularJS وابستگی به ویژوال استودیو ندارد. اگر به دنبال پشتیبانی بهتری از TypeScript هستید، VSCode رایگان، سورس باز و چند سکویی، گزینهی بسیار بهتری است نسبت به ویژوال استودیوی کامل. البته این مورد تعجبی هم ندارد؛ از این جهت که VSCode با TypeScript نوشته شدهاست.
اهمیت آشنایی با npm
اگر در طی سالهای اخیر با ویژوال استودیو کار کرده باشید، به طور قطع با NuGet نیز آشنا هستید. NuGet به عنوان یک package manager دات نتی شناخته میشود و کار آن دریافت وابستگیهای یک پروژه، از مخزنی مشخص و نصب و به روز رسانی خودکار آنها است. اما این روزها خارج از محیط توسعهی مایکروسافت، مدیرهای بستههای دیگری مانند Bower نیز برای نصب و به روز رسانی بستههای front end مانند کتابخانههای CSS ایی و جاوا اسکریپتی، بسیار رواج پیدا کردهاند. Bower یکی از ابزارهای NodeJS است که توسط NPM یا NodeJS Package Manager نصب میشود. به این معنا که استفاده از Bower به معنای استفاده از NPM است. پیش از این از NPM صرفا جهت نصب بستههای مرتبط با NodeJS استفاده میشد، اما در طی یکسال اخیر، استفاده از NPM نیز برای مدیریت بستههای front end رواج پیدا کردهاست و در صدر مدیر بستههای نصب کتابخانههای front end قرار دارد. همچنین در این حالت شما تنها نیاز به یک ابزار و یک فایل تنظیمات آن خواهید داشت، بجای استفاده از چندین ابزار و چندین فایل تنظیمات جداگانه. به علاوه این روزها انجام کارهای جدی جاوا اسکریپتی بدون دانش NPM دیگر میسر نیست. بهترین ابزارها، کامپایلرها، فشرده کنندههای front end و امثال آنها، تحت NodeJS اجرا میشوند. برای کار با AngularJS 2.0 و دریافت وابستگیهای آن نیز استفاده از npm، روش پیش فرض و توصیه شدهاست.
کار با npm جهت دریافت وابستگیهای کتابخانههای front end
برای کار با npm یا میتوان از دستورات خط فرمان آن به صورت مستقیم استفاده کرد و یا از امکانات یکپارچگی آن با ویژوال استودیو نیز بهره گرفت که ما در ادامه از این روش استفاده خواهیم کرد. البته توانمندیهای خط فرمان npm فراتر است از امکانات توکار VS.NET، اما در اینجا نیازی به آنها نیست و هدف صرفا دریافت و به روز رسانی وابستگیهای مرتبط است.
ویژوال استودیوی 2015 به همراه ابزارهای NodeJS ارائه میشود. اما مشکل اینجا است که این ابزارها هم اکنون قدیمی شدهاند و تطابقی با آخرین نگارش ابزارهای NodeJS ندارند. برای نمونه حین نصب وابستگیهای AngularJS 2.0 که یکی از آنها RxJS است، یک چنین خروجی را در پنجرهی output ویژوال استودیو مشاهده میکنید:
npm WARN engine rxjs@5.0.0-beta.6: wanted: {"npm":">=2.0.0"} (current: {"node":"v0.10.31","npm":"1.4.9"})
همانطور که در تصویر نیز ملاحظه میکنید، به مسیر Tools->Options->Projects and Solutions->External Web Tools مراجعه کرده و متغیر محیطی PATH ویندوز را به ابتدای لیست منتقل کنید. به این صورت ابزارهای به روز شدهی خط فرمان، مقدم خواهند شد بر ابزارهای قدیمی به همراه نگارش فعلی ویژوال استودیو.
البته فرض بر این است که آخرین نگارش nodejs را از آدرس https://nodejs.org/en دریافت و نصب کردهاید. با نصب آن، برنامه npm، در خط فرمان ویندوز به صورت مستقیم قابل استفاده خواهد بود؛ از این جهت که مسیر آن به PATH ویندوز اضافه شدهاست:
افزودن فایل project.json به پروژه
تا اینجا فرض بر این است که nodejs را از سایت آن دریافت و نصب کردهاید. همچنین متغیر PATH را در External Web Tools ویژوال استودیو به ابتدای لیست آن منتقل کردهاید تا همواره از آخرین نگارش npm نصب شدهی در سیستم، استفاده شود.
پس از آن همانند نیوگت که از فایل xml ایی به نام packages.config برای ثبت آخرین تغییرات خودش استفاده میکند، npm نیز از فایلی به نام package.json برای ذکر وابستگیهای مورد نیاز پروژه بهره میبرد. برای افزودن آن، از منوی Project گزینهی Add new item را انتخاب کرده و سپس npm را در آن جستجو کنید:
در اینجا نام پیش فرض package.json را پذیرفته و این فایل را به پروژه و ریشهی آن اضافه کنید.
اگر گزینهی فوق را در لیست Add new item مشاهده نمیکنید، مهم نیست. یک فایل متنی را به نام package.json به ریشهی پروژهی جاری اضافه کنید.
در ادامه محتوای این فایل را به نحو ذیل تغییر دهید:
{ "name": "asp-net-mvc5x-angular2x", "version": "1.0.0", "author": "DNT", "description": "", "scripts": {}, "license": "Apache-2.0", "dependencies": { "jquery": "2.2.3", "angular2": "2.0.0-beta.15", "systemjs": "^0.19.26", "es6-promise": "^3.1.2", "es6-shim": "^0.35.0", "reflect-metadata": "0.1.2", "rxjs": "5.0.0-beta.2", "zone.js": "^0.6.12", "bootstrap": "^3.3.6" }, "devDependencies": { "typescript": "^1.8.9", "typings": "^0.8.1" }, "repository": { } }
چند نکته:
- هر زمانیکه این فایل را ذخیره کنید، بلافاصله کار دریافت این بستهها از اینترنت آغاز خواهد شد. جزئیات آنرا میتوان در پنجرهی output ویژوال استودیو مشاهده کرد (و حتما اینکار را جهت دیباگ کار انجام دهید. بسیاری از مشکلات و خطاها، در اینجا لاگ میشوند). بنابراین اگر قصد دارید کار همگام سازی تغییرات را انجام دهید، فقط کافی است دکمههای ctrl+s یا save را بر روی این فایل اعمال کنید.
- کاری که دکمهی ctrl+s در این فایل انجام میدهد، اعمال خودکار دستور npm install بر روی پوشهای است که package.json در آن قرار دارد. بنابراین برای دریافت این بستهها، روش خط فرمان آن، ابتدا وارد شدن به ریشهی پروژهی جاری و سپس صدور دستور npm install است (که نیازی به آن نیست و ویژوال استودیو اینکار را به صورت خودکار انجام میدهد).
- بستههای دریافت شده، در پوشهای به نام node_modules در ریشهی پروژه ذخیره میشوند:
برای مشاهدهی آنها میتوان بر روی دکمهی show all files در solution explorer کلیک نمائید.
- درون فایل package.json، پشتیبانی کاملی از intellisense وجود دارد. برای مثال اگر علاقمند بودید تا آخرین نگارش AngularJS را مشاهده کنید، پس از خاصیت angular2 در تنظیمات فوق، " را تایپ کنید تا منوی تکمیل کنندهای ظاهر شود:
بدیهی است این منو جهت دریافت آخرین اطلاعات، نیاز به اتصال به اینترنت را دارد.
البته همیشه آخرین شماره نگارش AngularJS 2.0 را در این آدرس نیز میتوانید مشاهده کنید: CHANGELOG.md
- در این فایل شماره نگارش آغاز شدهای با ^ مانند "3.1.2^" به این معنا است که اجازهی نصب نگارشهای جدیدتری از 3.1.2 نیز داده شدهاست.
به روز رسانی کامپایلر TypeScript
نیاز است یکبار مطلب «مبانی TypeScript؛ تنظیمات TypeScript در ویژوال استودیو» را جهت آشنایی با نحوهی به روز رسانی اجزای مرتبط با TypeScript مطالعه کنید.
افزودن فایل tsconfig.json به پروژه
مرحلهی بعد شروع به کار با AngularJS و TypeScript، انجام تنظیمات کامپایلر TypeScript است. برای این منظور از منوی پروژه، گزینهی Add new item، عبارت typescript را جستجو کرده و در لیست ظاهر شده، گزینهی TypeScript JSON Configuration File را با نام پیش فرض آن انتخاب کنید:
اگر این گزینهی ویژه را در لیست add new items ندارید، مهم نیست. یک فایل متنی را به نام tsconfig.json به ریشهی پروژهی جاری اضافه کنید.
پس از افزودن فایل tsconfig.json به ریشهی سایت، تنظیمات آنرا به نحو ذیل تغییر دهید:
{ "compileOnSave": true, "compilerOptions": { "target": "es5", "module": "system", "moduleResolution": "node", "noImplicitAny": false, "noEmitOnError": true, "removeComments": false, "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true }, "exclude": [ "node_modules", "wwwroot", "typings/main", "typings/main.d.ts" ] }
برای نمونه خاصیت compileOnSave سبب خواهد شد تا پس از ذخیره سازی یک فایل ts، بلافاصله فایل js معادل آْن تولید شود. نوع ماژولها در اینجا به system.js تنظیم شدهاست و خروجی کدهای js آن از نوع ES 5 درنظر گرفته شدهاست. همچنین فعال سازی decorators نیز در اینجا صورت گرفتهاست. از این جهت که AngularJS2 استفادهی گستردهای را از این مفهوم، انجام میدهد.
در قسمت excludes به کامپایلر TypeScript اعلام شدهاست تا از یک سری از مسیرها مانند پوشهی node_modules که پیشتر آنرا تنظیم و دریافت کردیم، صرفنظر کند.
خلاصهی بحث
تا اینجا با نحوهی نصب پیشنیازهای AngularJS 2 و همچنین TypeScript آشنا شدیم. به صورت خلاصه:
- nmp اصلی را از سایت nodejs دریافت و نصب کنید.
- متغیر PATH را در ویژوال استودیو، به ابتدای لیست ابزارهای خارجی وب آن منتقل کنید تا از npm اصلی استفاده کند.
- فایل project.json را با محتوای ذکر شده، به ریشهی پروژه اضافه کنید. سپس یکبار آنرا save کنید تا وابستگیها را از اینترنت دریافت کند.
- اطمینان حاصل کنید که آخرین کامپایلر TypeScript را نصب کردهاید.
- فایل tsconfig.json را با محتوای ذکر شده، به ریشهی پروژه اضافه کنید.
DateTimeOffsetToBinaryConverter
- DateTimeOffset to binary-encoded 64-bit value (stores it as a long, slight reduction in precision)
DateTimeOffsetToBytesConverter
- DateTimeOffset to byte array (stores it as a 12 byte array, 8 bytes for time, 4 bytes for offset. Full precision.)
DateTimeOffsetToStringConverter
- DateTimeOffset to string (ISO 8601 string including timezone)
protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); if (Database.ProviderName == "Microsoft.EntityFrameworkCore.Sqlite") { // SQLite does not have proper support for DateTimeOffset via Entity Framework Core, see the limitations // here: https://docs.microsoft.com/en-us/ef/core/providers/sqlite/limitations#query-limitations // To work around this, when the Sqlite database provider is used, all model properties of type DateTimeOffset // use the DateTimeOffsetToBinaryConverter // Based on: https://github.com/aspnet/EntityFrameworkCore/issues/10784#issuecomment-415769754 // This only supports millisecond precision, but should be sufficient for most use cases. foreach (var entityType in builder.Model.GetEntityTypes()) { var properties = entityType.ClrType.GetProperties().Where(p => p.PropertyType == typeof(DateTimeOffset)); foreach (var property in properties) { builder .Entity(entityType.Name) .Property(property.Name) .HasConversion(new DateTimeOffsetToBinaryConverter()); } } } }
مروری بر ASP.NET Core View Component
Partial Views and Child Actions are one the most used features of ASP.NET MVC. Partial Views provides us a way to create a reusable component that can be used in multiple Views. There are Actions which can be marked as Child Actions and these cannot be invoked via URL but inside views or partial views. Child Actions are no more available with ASP.NET Core. View Components are new way to implement this feature in ASP.NET Core.
انتشار WinJS 4.0
Top 3 Open Source ASP.NET Core based e-commerce web applications
nopCommerce
SimplCommerce
grandnode ( Powered By nopCommerce) :It’s an open source, free, cross-platform e-commerce software based on ASP.NET Core 2.2 and MongoDB — NoSQL database. You can run it on Linux, Windows, and MacOS easily. GrandNode also supports Docker, so you are able to install it just in seconds with Docker.
نگارش نهایی SQL Server 2022 منتشر شد
Today, we announced the general availability of SQL Server 2022, the most Azure-enabled release of SQL Server yet, with continued innovation across performance, security, and availability1. This marks the latest milestone in the more than 30-year history of SQL Server.