CREATE TABLE [dbo].[Tree]( [Id] [int] IDENTITY(1,1) NOT NULL, [Name] [nchar](10) NOT NULL, [ParentId] [int] NOT NULL, CONSTRAINT [PK_Tree] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO ALTER TABLE [dbo].[Tree] WITH CHECK ADD CONSTRAINT [FK_Tree_Tree] FOREIGN KEY([ParentId]) REFERENCES [dbo].[Tree] ([Id]) GO ALTER TABLE [dbo].[Tree] CHECK CONSTRAINT [FK_Tree_Tree] GO
- فیلترها در MVC
- ASP.NET MVC #15
فیلترها در ASP.NET MVC، امکان اجرای کدهایی را پیش و یا پس از مرحلهی خاصی از طول اجرای pipeline آن فراهم میکنند. کلیات فیلترها در ASP.NET Core با نگارشهای قبلی ASP.NET MVC (پیشنیازهای فوق) تفاوت چندانی را ندارد و بیشتر تغییراتی مانند نحوهی معرفی سراسری آنها، اکشن فیلترهای Async و یا تزریق وابستگیها در آنها، جدید هستند.
امکان تعریف فیلترهای Async در ASP.NET Core
حالت کلی تعریف یک فیلتر در ASP.NET MVC که در ASP.NET Core نیز همچنان معتبر است، پیاده سازی اینترفیس کلی IActionFilter میباشد که توسط آن میتوان به مراحل پیش و پس از اجرای قطعهای از کدهای برنامه دسترسی پیدا کرد:
namespace FiltersSample.Filters { public class SampleActionFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { // انجام کاری پیش از اجرای اکشن متد } public void OnActionExecuted(ActionExecutedContext context) { // انجام کاری پس از اجرای اکشن متد } } }
namespace FiltersSample.Filters { public class SampleAsyncActionFilter : IAsyncActionFilter { public async Task OnActionExecutionAsync( ActionExecutingContext context, ActionExecutionDelegate next) { // انجام کاری پیش از اجرای اکشن متد await next(); // انجام کاری پس از اجرای اکشن متد } } }
یک نکته: توصیه شدهاست که تنها یکی از حالتهای همزمان و یا غیرهمزمان را پیاده سازی کنید و نه هر دوی آنها را. اگر هر دوی اینها را در طی یک کلاس پیاده سازی کنید (تک کلاسی که هر دوی اینترفیسهای IActionFilter و IAsyncActionFilter را با هم پیاده سازی میکند)، تنها نگارش Async آن توسط ASP.NET Core فراخوانی و استفاده خواهد شد. همچنین مهم نیست که اکشن متد شما Async هست یا خیر؛ برای هر دو حالت میتوان از فیلترهای async نیز استفاده کرد.
ساده سازی تعریف فیلترها
اگر مدتی با ASP.NET MVC کار کرده باشید، میدانید که عموما کسی از این اینترفیسهای کلی برای پیاده سازی فیلترها استفاده نمیکند. روش کار با ارث بری از یکی از فیلترهای از پیش تعریف شدهی ASP.NET MVC صورت میگیرد؛ از این جهت که این فیلترها که در اصل همین اینترفیسها را پیاده سازی کردهاند، یک سری جزئیات توکار protected را نیز به همراه دارند که با ارث بری از آنها میتوان به امکانات بیشتری دسترسی پیدا کرد و کدهای سادهتر و کم حجمتری را تولید نمود:
ActionFilterAttribute
ExceptionFilterAttribute
ResultFilterAttribute
FormatFilterAttribute
ServiceFilterAttribute
TypeFilterAttribute
برای مثال در اینجا فیلتری را مشاهده میکنید که با ارث بری از فیلتر توکار ResultFilterAttribute، سعی در تغییر Response برنامه و افزودن هدری به آن کردهاست:
using Microsoft.AspNetCore.Mvc.Filters; namespace FiltersSample.Filters { public class AddHeaderAttribute : ResultFilterAttribute { private readonly string _name; private readonly string _value; public AddHeaderAttribute(string name, string value) { _name = name; _value = value; } public override void OnResultExecuting(ResultExecutingContext context) { context.HttpContext.Response.Headers.Add( _name, new string[] { _value }); base.OnResultExecuting(context); } } }
[AddHeader("Author", "DNT")] public class SampleController : Controller { public IActionResult Index() { return Content("با فایرباگ هدر خروجی را بررسی کنید"); } }
نحوهی تعریف میدان دید فیلترها
نحوهی دید فیلترها در اینجا نیز همانند سابق، سه حالت را میتواند داشته باشد:
الف) اعمال شدهی به یک اکشن متد.
ب) اعمال شدهی به یک کنترلر که به تمام اکشن متدهای آن کنترلر اعمال خواهد شد.
ج) حالت تعریف سراسری و این مورد محل تعریف آن به کلاس آغازین برنامه منتقل شدهاست:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { options.Filters.Add(typeof(SampleActionFilter)); // by type options.Filters.Add(new SampleGlobalActionFilter()); // an instance }); }
الف) اگر توسط ارائهی new ClassName معرفی شوند، یعنی وهله سازی را خودتان قرار است مدیریت کنید و در این حالت تزریق وابستگیهایی صورت نخواهند گرفت.
ب) اگر توسط typeof معرفی شوند، یعنی این وهله سازی توسط IoC Container توکار ASP.NET Core انجام خواهد شد و طول عمر آن Transient است. یعنی به ازای هربار نیاز به آن، یکبار وهله سازی خواهد شد.
ترتیب اجرای فیلترها
توسط خاصیت Order میتوان ترتیب اجرای چندین فیلتر اجرا شدهی به یک اکشن متد را مشخص کرد. اگر این مقدار منفی وارد شود:
[MyFilter(Name = "Method Level Attribute", Order=-1)]
تزریق وابستگیها در فیلترها
فیلترهایی که به صورت ویژگیها یا Attributes تعریف میشوند و قرار است به کنترلرها و یا اکشن متدها به صورت مستقیم اعمال شوند، نمیتوانند دارای وابستگیهای تزریق شدهی در سازندهی خود باشند. این محدودیتی است که توسط زبانهای برنامه نویسی اعمال میشود و نه ASP.NET Core. اگر ویژگی قرار است پارامتری در سازندهی خود داشته باشد، هنگام تعریف و اعمال آن، این پارامترها باید مشخص بوده و تعریف شوند. به همین جهت آنچنان با تزریق وابستگیهای از طریق سازندهی کلاس قابل مدیریت نیستند. برای رفع این نقصیه، راهحلهای متفاوتی در ASP.NET Core پیشنهاد و طراحی شدهاند:
الف) استفادهی از ServiceFilterAttribute
[ServiceFilter(typeof(AddHeaderFilterWithDi))] public IActionResult Index() { return View(); }
همچنین باید دقت داشت که در این حالت ثبت کلاس فیلتر در متد ConfigureServices کلاس آغازین برنامه الزامی است.
services.AddScoped<AddHeaderFilterWithDi>();
System.InvalidOperationException: No service for type 'FiltersSample.Filters.AddHeaderFilterWithDI' has been registered.
ب) استفاده از TypeFilterAttribute
[TypeFilter(typeof(AddHeaderAttribute), Arguments = new object[] { "Author", "DNT" })] public IActionResult Hi(string name) { return Content($"Hi {name}"); }
- نیازی نیست تا وابستگی آنرا در متد ConfigureServices ثبت کرد (هرچند وابستگیهای خود را از DI Container دریافت میکنند).
- امکان دریافت پارامترهای اضافی سازندهی کلاس مدنظر را نیز دارند.
یک مثال تکمیلی: لاگ کردن تمام استثناءهای مدیریت نشدهی یک برنامهی ASP.NET Core 1.0
میتوان با سفارشی سازی فیلتر توکار ExceptionFilterAttribute، امکان ثبت وقایع را توسط فریم ورک توکار Logging اضافه کرد:
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging; namespace Core1RtmEmptyTest.StartupCustomizations { public class CustomExceptionLoggingFilterAttribute : ExceptionFilterAttribute { private readonly ILogger<CustomExceptionLoggingFilterAttribute> _logger; public CustomExceptionLoggingFilterAttribute(ILogger<CustomExceptionLoggingFilterAttribute> logger) { _logger = logger; } public override void OnException(ExceptionContext context) { _logger.LogInformation($"OnException: {context.Exception}"); base.OnException(context); } } }
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { options.Filters.Add(typeof(CustomExceptionLoggingFilterAttribute));
در ادامه با این فرض که پیشتر تنظیمات ثبت وقایع صورت گرفتهاست:
public void Configure(ILoggerFactory loggerFactory) { loggerFactory.AddDebug(minLevel: LogLevel.Debug);
public IActionResult GetData() { throw new Exception("throwing an exception!"); }
EF Code First #12
یه سوال داشتم ازتون:
در عمل ما تو یه برنامهی وب (مثلا mvc) به متدهای زیادی فقط برای سرویس دهی به موضوعات احتیاج داریم،مثلاً
getTopCategories
getLastCategories
getCategoryByID(int Id)
getCategoriesByDate(Datetime date)
getProductCategories()
و ...
حالا سوالم اینه پیاده سازیهای این متدها باید تو کدوم لایه انجام بشه؟
1-مثلا باید لیست موضوعات،(همین متد GetAllCategories مربوط به سرویس شما)، رو از سرویس برگردوند و داخل controller کویریهای Linq رو روش اجرا کرد و اطلاعاتی که میخوایم رو ازش بکشیم بیرون و نمایش داد؟
2-یا باید توی اینترفیس ICategoryService تک تک متد هایی که احتیاج داریم رو تعریف و بعد توی EFCategoryService تو لایه سرویس اونارو پیاده سازی کنیم و فقط نتیجه رو به controller برگردوند و ازش استفاده کرد(یعنی تو controller فقط پارامترهای مورد نیاز متدهای لایه سرویس رو بهش پاس کنیم)؟
امیدوارم مفهوم رو رسونده باشم.
ممنون به خاطر زحمت هایی که میکشید.
کار با IDE و حرکت بین کدها
در ادامه، همان پروژهای را که در قسمت قبل ایجاد کردیم، مجددا با وارد شدن به پوشهی آن و اجرای دستور . code، توسط VSCode باز خواهیم کرد. سپس فایل Program.cs آنرا باز کنید. فرض کنید در سطر ذیل آن:
.UseStartup<Startup>()
الف) اشارهگر ماوس را به آن نزدیک کنید و سپس دکمهی Ctrl را نگه دارید. به این ترتیب واژهی Startup تبدیل به یک لینک خواهد شد که با کلیک بر روی آن میتوان به کلاس Startup رسید.
ب) روش دوم، قرار دادن اشارهگر متنی بر روی واژه Startup و سپس فشردن دکمهی F12 است. این گزینه بر روی منوی کلیک راست بر روی این واژه نیز وجود دارد.
اگر دکمهی F12 را بر روی کلاسی فشار دهید که کدهای آن در IDE وجود ندارند، یک صفحهی جدید باز شده و کلاس تعریف آنرا بر اساس ساختار و متادیتای این اسمبلی، به همراه مستندات کامل آنها نمایش میدهد.
در این حالت اگر خواستید به مکان قبلی بازگردید فقط کافی است دکمههای alt + left cursor key را بفشارید.
در اینجا امکان یافتن ارجاعات به یک کلاس، مشاهدهی پیاده سازیها و همچنین یک Refactoring به نام rename symbol نیز موجود است که با استفادهی از آن، تمام ارجاعات به این کلاس در IDE نیز تغییرنام خواهند یافت.
یافتن سریع فایلها در IDE
در یک پروژهی بزرگ، برای یافتن سریع یک فایل، تنها کافی است دکمههای Ctrl+P را فشرده و در صفحهی دیالوگ باز شده، قسمتی از نام آنرا جستجو کنید:
همچنین اگر میخواهید محتوای فایلها را جهت یافتن واژهای خاص جستجو کنید، کلیدهای Ctrl+Shift+F (منوی Edit بالای صفحه و یا دومین آیکن در نوار ابزار عمودی سمت چپ صفحه) چنین امکانی را فراهم میکنند:
افزودن فایلهای جدید به پروژه
فرض کنید میخواهیم یک کنترلر جدید را به پوشهی Controllers اضافه کنیم:
برای اینکار ابتدا پوشهی Controllers را انتخاب کنید. در همین حال، نوار ابزاری ظاهر میشود که توسط آن میتوان در این پوشه، یک فایل جدید و یا یک پوشهی جدید را ایجاد کرد.
اگر علاقمند به ایجاد فایل یا پوشهای در ریشهی پروژه باشید، باید تمام فایلها و پوشههای موجود، در حالت انتخاب نشده قرار بگیرند. به همین جهت فقط کافی است در یک مکان خالی، در لیست فایلها کلیک کنید تا فایلها و پوشهها از حالت انتخاب شده خارج شوند. اکنون نوار ابزار ظاهر شدهی افزودن فایلها، به پوشهی ریشهی پروژه اشاره میکند.
در ادامه فایل جدید AboutController.cs را در پوشهی Controllers ایجاد کنید. مشاهده خواهید کرد که یک فایل کاملا خالی ایجاد شدهاست. در VSCode به ازای پسوندهای مختلف فایلها، قالبهای از پیش آماده شدهای برای آنها درنظر گرفته نمیشود و نمای ابتدایی تمام آنها خالی است.
اما در اینجا اگر کلمهی name را تایپ کنیم، دو پیشنهاد افزودن فضای نام را ارائه میدهد:
اولی صرفا نام namespace را در صفحه درج خواهد کرد. دومی به یک code snippet اشاره میکند و کار آن ایجاد قالب یک فضای نام جدید است. برای درج آن فقط کافی است دکمهی tab را بفشارید.
همین کار را در مورد class نیز میتوان تکرار کرد و در اینجا در intellisense ظاهر شده یا میتوان واژهی class را درج کرد و یا code snippet آنرا انتخاب نمود که یک کلاس جدید را ایجاد میکند:
یک نکته: در VSCode نیازی نیست تا مدام دکمههای Ctrl+S را جهت ذخیره سازی فایلهای تغییر کرده فشرد. میتوان از منوی فایل، گزینهی Auto Save را انتخاب کرد تا اینکار را به صورت خودکار انجام دهد.
ایجاد Code Snippets جدید
هرچند تا اینجا با استفاده از code snippets پیش فرض فضاهای نام و کلاسها، یک کلاس جدید را ایجاد کردیم، اما روش سادهتری نیز برای انجام اینکارها و تکمیل کنترلر وجود دارد.
برای این منظور به منوی File -> Preferences -> User snippets مراجعه کنید و سپس از لیست ظاهر شده، زبان #C را انتخاب کنید:
به این ترتیب یک قالب جدید code snippet تولید خواهد شد. در اینجا میخواهیم برای تولید Actionهای یک کنترلر نیز یک code snippet جدید را تهیه کنیم:
{ "MVC Action": { "prefix": "mvcAction", "body": [ "public IActionResult ${1:ActionName}()", "{", " $0 ", " return View();", "}" ], "description": "Creates a simple MVC action method." } }
- در این آرایه، 0$ جائی است که اشارهگر متنی پس از درج snippet قرار میگیرد و 1$ به نامی که قرار است توسط کاربر تکمیل شود، اشاره میکند که در اینجا یک نام پیش فرض مانند ActionName را هم میتوان برای آن درنظر گرفت.
- در اینجا prefix نامی است که اگر در صفحه تایپ شود، منوی انتخاب این code snippet را ظاهر میکند:
استفاده از بستههای Code Snippets آماده
خوشبختانه پشتیبانی جامعهی توسعه دهندگان از VSCode بسیار مطلوب است و علاوه بر افزونههای قابل توجهی که برای آن نوشته شدهاند، بستههای Code Snippets آمادهای نیز جهت بالابردن سرعت کار با آن وجود دارند. برای دریافت آنها، به نوار ابزار عمودی که در سمت چپ صفحه وجود دارد، مراجعه کنید و گزینهی extensions آنرا انتخاب نمائید:
در اینجا اگر aspnetcore را جستجو کنید، لیست بستههای code snippets برچسب گذاری شدهی با aspnetcore ظاهر میشود. در همینجا اگر یکی از آنها را انتخاب کنید، در سمت راست صفحه میتوانید توضیحات آن را نیز مشاهده و مطالعه نمائید (بدون نیاز به خروج از IDE).
برای مثال wilderminds-aspnetcore-snippets را نصب کنید. پس از آن تنها کافی است mvc6 را درون یک کلاس کنترلر تایپ نمائید تا امکانات آن ظاهر شوند:
برای نمونه پس از ایجاد یک فایل خالی کنترلر، انتخاب code snippet ایی به نام mvc6-controller، سبب ایجاد یک کنترلر کامل به همراه اکشن متدهایی پیش فرض میشود. بنابراین معادل قالبهای new items در نگارش کامل ویژوال استودیو در اینجا میتوان از Code Snippets استفاده کرد.
درکل برای یافتن مواردی مشابه، بهتر است واژهی کلیدی snippets را در قسمت extensions جستجو نمائید و آنها صرفا مختص به #C یا ASP.NET Core نیستند.
مدیریت ارجاعات و بستههای نیوگت در برنامههای ASP.NET Core
تا اینجا مدیریت فایلها و نحوهی تکمیل آنها را توسط code snippets، بررسی کردیم. قدم بعدی و گردش کاری مهم مورد نیاز دیگر، نحوهی افزودن ارجاعات به پروژه در VSCode است.
مدیریت ارجاعات در نگارشهای جدید ASP.NET Core، در فایل csproj برنامه انجام میشوند. در اینجا است که بستههای نیوگت جدید، ارجاعات به پروژههای دیگر و حتی شماره فریم ورک مورد استفاده تعیین میشوند.
برای نمونه بستهی نیوگت DNTPersianUtils.Core را به لیست ارجاعات آن اضافه کنید:
<PackageReference Include="DNTPersianUtils.Core" Version="2.2.0" />
در اینجا با کلیک بر روی لینک و یا دکمهی restore ، کار دریافت این بسته و نصب آن انجام خواهد شد.
اگر علاقمند بودید تا اینکار را در خط فرمان به صورت دستی انجام دهید، دکمههای Ctrl+ back-tick را فشرده، تا امکانات خط فرمان درون VSCode ظاهر شوند و سپس دستور dotnet restore را صادر کنید.
روش دوم ثبت بستههای نیوگت در فایل csproj، مراجعه به خط فرمان (فشردن دکمههای دکمههای Ctrl+ back-tick) و صدور دستور ذیل است:
> dotnet add package DNTPersianUtils.Core
دیباگ برنامههای ASP.NET Core در VSCode
در قسمت قبل با فرامین dotnet run و dotnet build و همچنین نحوهی اجرای سریع آنها آشنا شدیم. در ادامه اگر به نوار ابزار عمودی کنار صفحهی آن دقت کنید، گزینهی دیباگ نیز وجود دارد:
در اینجا دو نوع نحوهی برپایی و اجرای برنامه را مشاهده میکنید که هر دو مورد در فایل vscode\launch.json. زمانیکه دیباگ پروژه را در ابتدای باز کردن آن در VSCode فعال میکنیم، تعریف شدهاند.
برای بررسی آن فایل HomeController.cs را گشوده و در ابتدای متد About آن یک break point را قرار دهید (با حرکت دادن اشارهگر ماوس، جائیکه شماره سطرها قرار دارند، علامت درج break point ظاهر میشود که با کلیک بعدی، دائمی خواهد شد و برعکس):
پس از آن تنها کاری که باید انجام داد، فشردن دکمهی F5 است که به معنای اجرای برنامه به همراه اتصال دیباگر به آن میباشد (در قسمت قبل، Ctrl+F5 را بررسی کردیم که به معنای اجرای برنامه، بدون اتصال دیباگر به آن است).
در ادامه پس از اجرای برنامه، بر روی لینک About کلیک کنید تا اکشن متد آن اجرا شود. بلافاصله کنترل کار به VSCode بازگشته و سطری که بر روی آن break-point قرار داده بودیم، ظاهر میشود:
اطلاعات بیشتر آن در برگهی دیباگ ظاهر میشوند و در کل تجربهی کاربری آن همانند سایر IDEهایی است که تاکنون با آنها کار کردهاید.
یک نکته: در اینجا در داخل فایلهای View (فایلهای razor) نیز میتوان break point قرار داد.
برپایی یک Watcher Build
ابزار ویژهای به همراه ابزارهای Build مخصوص پروژههای NET Core. وجود دارد به نام watcher که تغییرات پوشههای برنامه را تحت نظر قرار داده و با هر تغییری، پروژه را کامپایل میکند. به این ترتیب به سرعت میتوان آخرین تغییرات برنامه را در مرورگر بررسی کرد. برای نصب آن، تنظیم ذیل را به فایل csproj برنامه اضافه کنید:
<ItemGroup> <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0" /> </ItemGroup>
اکنون برای استفادهی از آن تنها کافی است دستور ذیل را صادر کنید:
>dotnet watch run ?[90mwatch : ?[39mStarted Hosting environment: Production Content root path: D:\vs-code-examples\FirstAspNetCoreProject Now listening on: http://localhost:5000 Application started. Press Ctrl+C to shut down.
یک نکته: اینبار برای دیباگ برنامه، باید گزینهی attach را انتخاب کرد:
اگر بر روی دکمهی سبز رنگ کنار آن کلیک کنید، لیست پروسههای دات نتی ظاهر شده و در این حالت میتوانید دیباگر را به پروسهی dotnet exec ایی که به dll برنامه اشاره میکند، متصل کنید (و نه پروسهی dotnet watch run که در حقیقت پروسهی dotnet exec را مدیریت میکند).
Accord.NET #1
چارچوب Accord.NET توسط آقای سزار سوزا بر پایه کتابخانهی مشهور و محبوب AForge.NET (که توسط آقای اندرو کریلو ایجاد شده بود) بنا شده و البته ابزارهای جدید زیادی به همراه یک محیط کامل برای محاسبات علمی (scientific computing) در NET. به آن اضافه شده است.
این چارچوب متشکل از چندین کتابخانه است که میتوان آن را از طریق NuGet دریافت و نصب کرد.
کتابخانههای Accord.NET را میتوان به سه دستهی کلی تقسیم کرد :
1. محاسبات علمی (scientific computing)
1.1. Accord.Math | جهت کار با ماتریسها عددی تجزیه ماتریسها (decomposition matrix) الگوریتمهای بهینه سازی عددی برای مسائل محدود و نامحدود توابع و ابزارهای خاص جهت استفاده در کاربردهای علمی |
1.2. Accord.Statistics | شامل توابعی جهت توزیعهای احتمال (probability distributions) آزمایش فرضیات (hypothesis testing) مدلهای آماری (statistical models) و توابعی شامل : رگرسیون خطی، مدل پنهان مارکوف (Hidden Markov Models)، آنالیز اجزای اساسی (Principal Component Analysis) و خیلی از تکنیکهای مرتبط دیگر. |
1.3. Accord.MachineLearning | شامل دسته بندهای معروف از جمله : ماشین برداری پشتیبان - Support Vector Machines درخت تصمیم - Decision Trees مدل نیو بیز - Naive Bayesian models K-means مدل ترکیبی گوسین - Gaussian Mixture models و الگوریتمهای متدوال دیگری مانند : Ransac, Cross-validation و Grid-Search |
1.4. Accord.Neuro | شامل الگوریتمهای معروف در حوزه شبکههای عصبی مصنوعی مانند: لونبرگ مارکوارت - Levenberg-Marquardt Parallel Resilient Back-propagation شبکه باور عمیق - Deep Belief Networks ماشین بولتزمن - Restrictured Boltzmann Machines و تعدادی از شبکههای عصبی دیگر |
2. پردازش تصویر و سیگنال
2.1. Accord.Imaging | شامل آشکارسازهای نقاط از جمله Harris, SURF, FAST و FREAK فیلترهایی برای تصاویر توابعی جهت انطباق (matching) و دوخت (stitching) تصاویر استخراج ویژگیهای خوبی مانند - ﻫﯿﺴﺘﻮﮔﺮام ﮔﺮادﯾﺎنﻫﺎی ﺷﯿﺐﮔﺮا و یا هاگ (Histograms of Oriented Gradients) و ویژگیهای توصیفی بافتی هارلیک (Haralick’s textural) |
2.2. Accord.Vision | تشخیص و ردیابی بیدرنگ چهره توابعی برای تشخیص، ردیابی و تبدیل اشیایی که در جریانی(streams) از تصاویر هستند |
2.3. Accord.Audio | شامل توابعی جهت پردازش صدا از جمله اسپکتروم آنالایزر |
3. سایر کتابخانههای پشتیبانی
3.1. Accord.Controls | شامل نمودار هیستوگرام، پلاتها و نمایشگرها و نمودارهایی برای دادههای جدولی جهت کاربردهای علمی. |
3.2. Accord.Controls.Imaging | شامل ابزاری برای نمایش سریع تصاویر برای برنامههای Windows Forms |
3.3. Accord.Controls.Audio | شامل کنترلهای Windows Forms برای نمایش شکل موج صوت و اطلاعات آن |
3.4. Accord.Controls.Vision | شامل اجزاء و کنترلهای Windows Forms برای ردیابی حرکات سر، صورت، دست و سایر کارهای مرتبط با بینایی ماشین |
اگر با مفاهیم یادگیری ماشین و هوش موصنوعی کمتر آشنا هستید و در این قسمت کمی کلمات تخصصی به کار رفته نگران نباشید؛ در مطالب آتی به صورت کاربردی به استفادهی از آنها خواهیم پرداخت.
روشهایی که قرار هست در ادامه توضیح داده شوند بر اساس کوئری بازگشتی میباشند. الگوریتمهای متنوعی بر اساس recursive CTE برای حل این مساله خلق شده اند. که من تنها به دو روش آن اکتفا میکنم.
Recursive CTE در نسخهی 2005 به SQL Server اضافه شده است. توسط این تکنیک مسائل پیچیده و گوناگونی را میتوان بسادگی حل نمود. مخصوصا مسائلی که ماهیت بازگشتی دارند مثل پیمایش یک درخت یا پیمایش یک گراف وزن دار.
روش اول:
یک کوئری بازگشتی دارای دو بخش هست به نامهای Anchor و recursive. در بخش دوم کوئری باز خودش را فراخوانی میکند تا به داده هایی که در مرحله قبل تولید شده اند دسترسی پیدا کند در اولین فراخوانی توسط عضو recursive، دادههای تولید شده در قسمت Anchor قابل دسترسی هستند. در قسمت دوم، کوئری آنقدر خود را فراخوانی میکند تا دیگر سطری از مرحله قبل وجود نداشته باشد که به آن مراجعه کند.
توضیح تکنیک:
در گام اول اندیس شروع و پایان کلمه اول را بدست میآوریم.
سپس در گام بعدی از اندیس پایان کلمه قبلی به عنوان اندیس شروع کلمه جدید استفاده میکنیم.
و اندیس پایان کلمه توسط تابع charindex بدست میآید.
کوئری تا زمانی ادامه پیدا میکند که کلمه برای تجزیه کردن در رشته باقی مانده باشد. فقط فراموش نکنید که حتما باید آخر عبارت یک کارکتر space داشته باشید.
DECLARE @S VARCHAR(50)='I am a student I go to school '; WITH CTE AS ( SELECT 1 rnk, 1 start, CHARINDEX(' ', @s) - 1 ed UNION ALL SELECT rnk + 1, ed + 2, CHARINDEX(' ', @s, ed + 2) - 1 FROM CTE WHERE CHARINDEX(' ', @s, ed + 2) > 0 ) SELECT rnk, SUBSTRING(@s, start, ed - start + 1) AS word FROM CTE /* Result rnk word ----------- ------- 1 I 2 am 3 a 4 student 5 I 6 go 7 to 8 school */
روش دوم:
در این روش در همان CTE عبارت تجزیه میشود و عمل تفکیک به مرحله بعدی واگذار نمیشود،
در گام اول، اولین کلمه انتخاب میشود. و سپس آن کلمه از رشته حذف میشود. با این روش همیشه اندیس شروع کلمه برابر با 1 خواهد بود و اندیس پایان کلمه توسط تابع charindex بدست خواهد آمد.
در گام بعدی اولین کلمه موجود در رشته ای که قبلا اولین کلمه از آن جدا شده است بدست میآید و باز مثل قبلی کلمه انتخاب شده از رشته جدا شده و رشته برش یافته به مرحله بعد منتقل میشود.
در این روش مثل روش قبلی آخر عبارتی که قرار هست تجزیه شود باید یک کارکتر خالی وجود داشته باشد.
DECLARE @a VARCHAR(50)='I am a student I go to school '; WITH MyWords(ranking, word, string) AS( SELECT 1, CAST(SUBSTRING(@a, 1, CHARINDEX(' ', @a) - 1) AS VARCHAR(25)), STUFF(@a, 1, CHARINDEX(' ', @a), '') UNION ALL SELECT ranking + 1, CAST(SUBSTRING(string, 1, CHARINDEX(' ', string) - 1) AS VARCHAR(25)), STUFF(string, 1, CHARINDEX(' ', string), '') FROM MyWords WHERE CHARINDEX(' ', string) > 0 ) SELECT ranking, word FROM MyWords;
ranking word ----------- ------------------------- 1 I 2 am 3 a 4 student 5 I 6 go 7 to 8 school
هدف ارائه راه حلی برای مدیریت Transactionها به عنوان یک Cross Cutting Concern، توسط ApplicationServiceها میباشد.
- دوره Aspect oriented programming
- بررسی مفاهیم معکوس سازی وابستگیها و ابزارهای مرتبط با آن
- طراحی و پیاده سازی ServiceLayer به همراه خودکارسازی Business Validationها
پیش فرض ما این است که شما از EF به عنوان OR-Mapper استفاده میکنید و الگوی Context Per Request را پیاده سازی کرده اید یا از طریق پیاده سازی الگوی Container Per Request به داشتن Context یکتا برای هر درخواست رسیده اید.
کتابخانه StructureMap.Mvc5 پیاده سازی از الگوی Container Per Request را با استفاده از امکانات Nested Container مربوط به StructureMap ارائه میدهد. اشیاء موجود در Nested Container طول عمر Singleton دارند.
واسط ITransaction
public interface ITransaction : IDisposable { void Commit(); void Rollback(); }
واسط بالا 3 متد را که برای مدیریت تراکنش لازم میباشد، در اختیار استفاده کننده قرار میدهد.
واسط IUnitOfWork
public interface IUnitOfWork : IDisposable { ... ITransaction BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.Snapshot); ITransaction Transaction { get; } IDbConnection Connection { get; } bool HasTransaction { get; } }
اعضای جدید واسط IUnitOfWork کاملا مشخص هستند.
پیاده سازی واسط ITransaction، توسط یک Nested Type در دل کلاس DbContextBase انجام میگیرد.
public abstract class DbContextBase : DbContext { ... #region Fields private ITransaction _currenTransaction; #endregion #region NestedTypes private class DbContextTransactionAdapter : ITransaction { private DbContextTransaction _transaction; public DbContextTransactionAdapter(DbContextTransaction transaction) { Guard.NotNull(transaction, nameof(transaction)); _transaction = transaction; } public void Commit() { _transaction?.Commit(); } public void Rollback() { if (_transaction?.UnderlyingTransaction.Connection != null) _transaction.Rollback(); } public void Dispose() { _transaction?.Dispose(); _transaction = null; } } #endregion #region Public Methods ... public ITransaction BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted) { if (_currenTransaction != null) return _currenTransaction; return _currenTransaction = new DbContextTransactionAdapter(Database.BeginTransaction(isolationLevel)); } #endregion #region Properties ... public ITransaction Transaction => _currenTransaction; public IDbConnection Connection => Database.Connection; public bool HasTransaction => _currenTransaction != null; #endregion } public class ApplicationDbContext : DbContextBase, IUnitOfWork, ITransientDependency { }
کلاس DbContextTransactionAdapter همانطور که از نام آن مشخص میباشد، پیاده سازی از الگوی Adapter برای وفق دادن DbContextTransaction با واسط ITransaction، میباشد. متد BeginTransaction در صورتی که تراکنشی برای وهله جاری DbContext ایجاد نشده باشد، تراکنشی را ایجاد کرده و فیلد currentTransaction_ را نیز مقدار دهی میکند.
TransactionalAttribute
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] public sealed class TransactionalAttribute : Attribute { public IsolationLevel IsolationLevel { get; set; } = IsolationLevel.ReadCommitted; public TimeSpan? Timeout { get; set; } }
TransactionInterceptor
public class TransactionInterceptor : ISyncInterceptionBehavior { private readonly IUnitOfWork _unitOfWork; public TransactionInterceptor(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; } public IMethodInvocationResult Intercept(ISyncMethodInvocation methodInvocation) { var transactionAttribute = GetTransactionaAttributeOrNull(methodInvocation.InstanceMethodInfo); if (transactionAttribute == null || _unitOfWork.HasTransaction) return methodInvocation.InvokeNext(); using (var transaction = _unitOfWork.BeginTransaction(transactionAttribute.IsolationLevel)) { var result = methodInvocation.InvokeNext(); if (result.Successful) transaction.Commit(); else { transaction.Rollback(); } return result; } } private static TransactionalAttribute GetTransactionaAttributeOrNull(MemberInfo methodInfo) { var transactionalAttribute = ReflectionHelper.GetAttributesOfMemberAndDeclaringType<TransactionalAttribute>( methodInfo ).FirstOrDefault(); return transactionalAttribute; } }
واسط ISyncInterceptionBehavior، مربوط میشود به کتابخانه جانبی دیگری که برای AOP توسط تیم StructureMap به نام StructureMap.DynamicInterception ارائه شدهاست. در متد Intercept، ابتدا چک میشود که که آیا این متد با TransactionAttribute تزئین شده و طی درخواست جاری برای Context جاری تراکنشی ایجاد نشده باشد؛ سپس تراکنش جدیدی ایجاد شده و بدنه اصلی متد اجرا میشود و نهایتا در صورت موفقیت آمیز بودن عملیات، تراکنش مورد نظر Commit میشود.
در آخر لازم است این Interceptor در تنظیمات اولیه StructureMap به شکل زیر معرفی شود:
Policies.Interceptors(new DynamicProxyInterceptorPolicy( type => typeof(IApplicationService).IsAssignableFrom(type), typeof(AuthorizationInterceptor), typeof(TransactionInterceptor), typeof(ValidationInterceptor)));
نکته: فرض کنید در بدنه اکشن متد یک کنترلر ASP.NET MVC یا ASP.NET Core، دو متد تراکنشی فراخوانی شود؛ در این صورت شاید لازم باشد که این دو متد طی یک تراکنش واحد به جای تراکنشهای مجزا، اجرا شوند؛ بنابراین نیاز است از الگوی Transaction Per Request استفاده شود. برای این کار میتوان یک ActionFilterAttribute سفارشی ایجاد کرد که ایجاد کننده تراکنش باشد و متدهای داخلی که هر کدام جدا تراکنشی بودند، نیز از تراکنش ایجاد شده استفاده کنند.