<!DOCTYPE html> <html> <head> <link rel="stylesheet" media="all" type="text/css" href="http://trentrichardson.com/Impromptu/jquery-impromptu.css" /> <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.0.min.js"></script> <script type="text/javascript" src="http://trentrichardson.com/Impromptu/jquery-impromptu.js"></script> </head> <body> <button class="show">ShowPrompt</button> <script type="text/javascript"> $(function(){ $(".show").click(function(e){ $.prompt("Hello World!"); }); }); </script> </body> </html>
مهارتهای تزریق وابستگیها در برنامههای NET Core. - قسمت سوم - رهاسازی منابع سرویسهای IDisposable
رفتار IoC Container توکار ASP.NET Core با سرویسهای IDisposable
ASP.NET Core به همراه یک IoC Container توکار ارائه میشود و اگر سرویسی با طول عمرTransient و یا Scoped به آن معرفی شود و همچنین این سرویس اینترفیس IDisposable را نیز پیاده سازی کند، کار dispose خودکار آن در پایان درخواست جاری صورت میگیرد و نیازی به تنظیمات اضافهتری ندارد. در اینجا سرویسهایی با طول عمر Singleton نیز در پایان کار برنامه، زمانیکه خود ServiceProvider به پایان کارش میرسد، dispose خواهند شد.
البته این مورد یک شرط را نیز به همراه دارد: کار وهله سازی سرویسهای درخواستی باید توسط خود این IoC Container مدیریت شود تا در پایان کار بداند چگونه آنها را Dispose کند.
یک مثال: بررسی Dispose شدن خودکار یک سرویس IDisposable
namespace CoreIocServices { public interface IMyDisposableService { void Run(); } public class MyDisposableService : IMyDisposableService, IDisposable { private readonly ILogger<MyDisposableService> _logger; public MyDisposableService(ILogger<MyDisposableService> logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _logger.LogInformation("+ {0} was created", this.GetType().Name); } public void Run() { _logger.LogInformation("Running MyDisposableService!"); } public void Dispose() { _logger.LogInformation("- {0} was disposed!", this.GetType().Name); } } }
اگر این سرویس را به یک برنامهی ASP.NET Core معرفی کنیم:
namespace CoreIocSample02 { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddTransient<IMyDisposableService, MyDisposableService>();
namespace CoreIocSample02.Controllers { public class HomeController : Controller { private readonly IMyDisposableService _myDisposableService; public HomeController(IMyDisposableService myDisposableService) { _myDisposableService = myDisposableService; } public IActionResult Index() { _myDisposableService.Run(); return View(); }
در ادامه با اجرای برنامه، اگر به لاگهای آن دقت کنیم، این خروجی قابل مشاهده خواهد بود:
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] Route matched with {action = "Index", controller = "Home"}. Executing action CoreIocSample02.Controllers.HomeController.Index (CoreIocSample02) info: CoreIocServices.MyDisposableService[0] + MyDisposableService was created . . . info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] Executed endpoint 'CoreIocSample02.Controllers.HomeController.Index (CoreIocSample02)' info: CoreIocServices.MyDisposableService[0] - MyDisposableService was disposed! info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Request finished in 1316.4719ms 200 text/html; charset=utf-8
بنابراین IoC Container، به صورت خودکار، کار Dispose این سرویس IDisposable را نیز انجام دادهاست.
Dispose خودکار وهلههایی که توسط IoC Container ایجاد نشدهاند
اگر ایجاد اشیاء از نوع IDisposable را خودتان و خارج از دید IoC Container توکار ASP.NET Core انجام میدهید، از مزیت پاکسازی خودکار منابع توسط آنها در پایان درخواست محروم خواهید شد، اما ... برای رفع این مشکل نیز متد context.Response.RegisterForDispose پیش بینی شدهاست. اگر شیءای از نوع IDisposable را توسط این متد به ASP.NET Core معرفی کنید، در پایان درخواست به صورت خودکار Dispose خواهد شد.
یک مثال: فرض کنید یک StreamWriter را داخل یک میانافزار ایجاد کردهاید، اما آنرا Dispose نکردهاید:
namespace CoreIocSample02 { public class Startup { public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.Use(async (context, next) => { var writer = File.CreateText(Path.GetTempFileName()); context.Response.RegisterForDispose(writer); context.Items["filewriter"] = writer; await writer.WriteLineAsync("some important information"); await writer.FlushAsync(); await next(); });
اکنون در ادامه، در اکشن متد WriteLog یک کنترلر دلخواه، کار ثبت وقایع با دریافت این writer از HttpContext.Items قابل انجام است؛ چون هنوز طول عمر درخواست جاری پایان نیافته و شیء writer به صورت خودکار Dispose نشدهاست:
namespace CoreIocSample02.Controllers { public class HomeController : Controller { public async Task<IActionResult> WriteLog() { var writer = HttpContext.Items["filewriter"] as StreamWriter; if (writer != null) { await writer.WriteLineAsync("more important information"); await writer.FlushAsync(); } return View(); }
زمانیکه به صورت متداولی از سیستم تزریق وابستگیهای ASP.NET Core استفاده میکنیم، به ازای هر درخواست HTTP رسیده، یک Scope از نوع IServiceScopeFactory ایجاد میشود و با پایان درخواست، این Scope نیز Dispose خواهد شد. به این ترتیب هر سرویس ایجاد شدهی درون این Scope نیز Dispose میشود؛ کاری شبیه به عملیات زیر:
using(var scope = serviceProvider.CreateScope()) { var provider = scope.ServiceProvider; var resolvedService = provider.GetRequiredService(someType); // Use resolvedService... }
مشکل! اگر از سرویس فرضی IOperationScoped با طول عمر Scoped در متدهای مختلف کلاس آغازین برنامه استفاده کنیم (مانند DbContext برنامه)، طول عمری را که دریافت خواهیم کرد singleton خواهد بود و نه Scoped؛ چون درون یک scopeFactory.CreateScope ایجاد شدهی به صورت خودکار توسط یک درخواست قرار نداریم. بنابراین هر درخواست وهلهای از سرویس IOperationScoped با طول عمر Scoped، تنها همان وهلهی ابتدایی آنرا باز میگرداند و singleton رفتار میکند؛ چون scope ایی ایجاد و تخریب نشدهاست.
در یک چنین مواردی، برای اطمینان حاصل کردن از dispose شدن سرویس در پایان کار، نیاز است مراحل ایجاد scope و dispose آنرا به صورت دستی به نحو ذیل مدیریت کنیم:
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IServiceScopeFactory scopeFactory) { using (var scope = scopeFactory.CreateScope()) { var initializer = scope.ServiceProvider.GetService<IOperationScoped>(); initializer.SeedAsync().Wait(); } }
Dispose کردن سرویسهای IDisposable در برنامههای Console
اگر همین سرویس IMyDisposableService را در مثال برنامهی کنسول قسمت اول استفاده کنیم:
var myDisposableService = serviceProvider.GetService<IMyDisposableService>(); myDisposableService.Run();
در برنامهی کنسول، کار ایجاد serviceProvider را خودمان انجام دادیم:
var serviceCollection = new ServiceCollection(); ConfigureServices(serviceCollection); var serviceProvider = serviceCollection.BuildServiceProvider();
namespace Microsoft.Extensions.DependencyInjection { public sealed class ServiceProvider : IServiceProvider, IDisposable, IServiceProviderEngineCallback { public void Dispose(); public object GetService(Type serviceType); } }
namespace CoreIocSample01 { class Program { static void Main(string[] args) { var serviceCollection = new ServiceCollection(); ConfigureServices(serviceCollection); using (var serviceProvider = serviceCollection.BuildServiceProvider()) { var myDisposableService = serviceProvider.GetService<IMyDisposableService>(); myDisposableService.Run(); var testService = serviceProvider.GetService<ITestService>(); testService.Run(); } }
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: CoreDependencyInjectionSamples-02.zip
اول اینکه، کیفیت دادههای ذخیرهشده در دستگاههای تلفن همراه کاربر بیشتر شخصی میشود تا مواردی دیگر! به غیر از ایمیل، پیامهای فوری، SMS / MMS ، لاگ تماسها، عکسها و پست صوتی وجود دارند که عموما توسعه دهندگان را دچار مشکل میکند.
برخی از گزینههای فوق بر روی یک کامپیوتر رومیزی هم وجود دارند، ولی اهمیت این دادهها بر روی اندروید و اجزای آن اهمیت فوق العادهای دارد. اطلاعات روی دستگاه موبایل شما به احتمال زیاد از ارزش بیشتری برخوردار خواهد بود، چرا که آنها را در یک صفحه 4 - 5 اینچی به همراه خود حمل میکنید و با خود هر کجا میبرید! این حالت، یک پلتفرم همگرا را بوجود میآورد؛ به این دلیل که سیستم رومیزی شما و تلفن همراه یک مجموعه غنی و کامل از اطلاعات حساس هستند که هردوی آنها شامل اطلاعات شخصی میباشند و برای شما اهمیت زیادی خواهند داشت. تصور کنید زمانیکه برای جلوگیری از نفوذ یا به سرقت رفتن شماره تلفنهای خود، یک پشتیبان بر روی سیستم رو میزی خود تهیه میکنید و فایل پشتیبان شمارههای تماس را بر روی سیستم شخصی نگه داری میکنید! آیا این همان پلتفرم همگرا نیست؟ آیا این دو سیستم مکمل هم نیستند؟حتی اگر همگامسازی را با یک مکان دوردست (Google Drive) انجام دهید، با این حال شما فقط در مقابل از دست دادن دادهها محافظت کردهاید و نه از دست دادن حریم خصوصی!
همچنین در نظر بگیرید که فرمت دادههای ذخیرهشده در دستگاههای تلفن همراه، تعیین و مشخص شوند! این کار اطلاعات حساس شما را به مرز سرقت نزدیکتر میکند. هر تلفن همراه SMS / MMS ، تماسها، و پست صوتی خواهد داشت. مکانهای ذخیره شده از روی GPS و مواردی دیگر که قطعا اطلاع دارید، تمامی اینها جزء مواردی هستند که خطرات امنیتی را در سیستم عامل اندروید شامل میشود. حالا در نظر بگیرید که این اطلاعات تا چه حد مهم است؟ برای کاربرانی که هیچ گونه پشتیبانی از اطلاعاتی از خود ندارند، از دست دادن دادهها قابل تصور نیست!
خطرناکترین نوع حملات بر روی پلتفرم اندروید انجام میشوند، در سکوت کامل و چندین هزار مایل دروتر از شما و فرد مهاجم نیازی به دسترسی فیزیکی و لمس تلفن همراه شما نخواهد داشت! این نوع حملات در هر زمانی ممکن است رخ دهد و اغلب میتواند به دلیل امنیت ضعیف در جای دیگری بر روی دستگاه رخ دهد.
در مطلب بعدی پیرامون امنیت معماری اندروید صبحت خواهیم کرد...
- تغییر اندازه تصویر در زمان ذخیرهسازی
- در زمانی که میخواهیم تصویر را به بازدید کننده نشان دهیم
using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; namespace PWS { public static class Helpers { /// <summary> /// تغییر اندازه تصویر /// </summary> /// <param name="imageFile">آرایه بایتی از تصویر مورد نظر</param> /// <param name="targetSize">اندازه تصویر خروجی</param> /// <param name="format">فرمت تصویر خروجی</param> /// <returns></returns> public static byte[] ResizeImageFile(this byte[] imageFile, Int32 targetSize, ImageFormat format) { if (imageFile == null) throw new Exception("لطفا تصویر اصلی را مشخص نمایید"); //باز کردن تصویر اصلی به عنوان یک جریان using (var oldImage = Image.FromStream(new MemoryStream(imageFile))) { //محاسبه اندازه تصویر خروجی با توجه به اندازه داده شده var newSize = CalculateDimensions(oldImage.Size, targetSize); //ایجاد تصویر جدید using (var newImage = new Bitmap(newSize.Width, newSize.Height, PixelFormat.Format24bppRgb)) { using (var canvas = Graphics.FromImage(newImage)) { canvas.SmoothingMode = SmoothingMode.AntiAlias; canvas.InterpolationMode = InterpolationMode.HighQualityBicubic; canvas.PixelOffsetMode = PixelOffsetMode.HighQuality; //تغییر اندازه تصویر اصلی و قرار دادن آن در تصویر جدید canvas.DrawImage(oldImage, new Rectangle(new Point(0, 0), newSize)); var m = new MemoryStream(); //ذخیره تصویر جدید با فرمت وارد شده newImage.Save(m, format); return m.GetBuffer(); } } } } /// <summary> /// محاسبه ابعاد تصویر خروجی /// </summary> /// <param name="oldSize">اندازه تصویر اصلی</param> /// <param name="targetSize">اندازه تصویر خروجی</param> /// <returns></returns> private static Size CalculateDimensions(Size oldSize, Int32 targetSize) { var newSize = new Size(); if (oldSize.Height > oldSize.Width) { newSize.Width = Convert.ToInt32(oldSize.Width * (targetSize / (float)oldSize.Height)); newSize.Height = targetSize; } else { newSize.Width = targetSize; newSize.Height = Convert.ToInt32(oldSize.Height * (targetSize / (float)oldSize.Width)); } return newSize; } } }
- در متد ResizeImageFileتصویر اصلی به عنوان یک جریان باز میشود. (سطر 23)
- اندازه تصویر خروجی با توجه به اندازه وارد شده توسط متد CalculateDimensions تعیین میشود؛ روال کار متد CalculateDimensions اینگونه است که اندازه عرض و ارتفاع تصویر اصلی بررسی میشود و با توجه به اینکه کدام یک از اینها بزرگتر است تغییر اندازه در آن صورت میگیرد، مثلا در صورتی که عکس ارتفاع بیشتری نسبت به عرض تصویر داشته باشد تصویر تغییر اندازه داده شده نیز با توجه به تناسب ارتفاع تغییر داده میشود و بالعکس. (سطر 26)
- پس از تغییر اندازه تصویر جدیدی در حافظه ایجاد میشود. (سطر 28)
- سپس تنظیمات گرافیکی لازم بروی تصویر جدید اعمال میشود. (سطر 30 تا 34)
- تصویر اصلی با توجه به اندازه جدید تغییر کرده و در تصویر جدید قرار میگیرد. (سطر 36)
- در نهایت تصویر جدید با فرمت وارد شده در متد ذخیره شده و به عنوان خروجی متد برگشت داده میشود. (سطر 37 تا 40)
نحوه استفاده از این تابع در ASP.NET میتواند به صورت زیر باشد :
byte[] oldImage = FileUploadImage.FileBytes; byte[] target = oldImage.ResizeImageFile(100, ImageFormat.Jpeg);
در بخش بعد در زمان نمایش تصویر به کاربر آن را تغییر اندازه خواهیم داد.
لازم به ذکر است که کدهای تغییر اندازه از StarterKitهای میکروسافت کپیبرداری شده است.
namespace jqGrid10.Models { public class Post { public int Id { set; get; } public string Title { set; get; } public string CategoryName { set; get; } public int NumberOfViews { set; get; } } }
- گروه بندی بر روی ستون CategoryName انجام شود.
- ستونی که بر روی آن گروه بندی انجام میشود، نمایش داده نشود.
- در ابتدای نمایش گروهها، تمام آنها به صورت جمع شده و Collapsed نمایش داده شوند.
- پس از نمایش گروهها، اولین گروه به صورت خودکار باز شود.
- تعداد ردیف هر گروه به عنوان گروه اضافه شود.
- جمع کل ستون تعداد بار مشاهدات هر گروه قابل محاسبه شود.
- جمع کل هر گروه در زمانیکه هر گروه نیز بستهاست نمایش داده شود.
- رنگ ردیف جمع کل قابل تنظیم باشد.
فعال سازی گروه بندی در jqGrid
فعال سازی گروه بندی در jqGrid به سادگی افزودن تعاریف ذیل است:
$('#list').jqGrid({ caption: "آزمایش دهم", //... grouping: true, groupingView: { groupField: ['CategoryName'], groupOrder: ['asc'], groupText : ['<b>{0} - {1} ردیف</b>'], groupDataSorted: true, groupColumnShow: false, groupCollapse: true, groupSummary: [true], showSummaryOnHide: true } });
groupField بیانگر آرایهای از ستونهایی است که قرار است بر روی آنها گروه بندی صورت گیرد.
groupOrder آرایهای اختیاری از مقادیر asc یا desc است که متناظر هستند با نحوهی مرتب سازی پیش فرض ستونهای معرفی شده در آرایه groupField.
groupText آرایهای اختیاری از عناوین گروه بندیهای انجام شدهاست. اگر ذکر شود، {0} آن با نام گروه و {1} آن با تعداد عناصر گروه جایگزین میشود.
تنظیم groupDataSorted سبب خواهد شد تا نام ستونی که بر روی آن گروه بندی صورت میگیرد، به سرور ارسال شود (توسط پارامتر sidx). به این ترتیب در سمت سرور میتوان اطلاعات را به صورت پویا مرتب سازی کرده و بازگشت داد.
با تنظیم groupColumnShow به false سبب خواهیم شد تا ستونهای معرفی شده در قسمت groupField نمایش داده نشوند.
با تنظیم groupCollapse به true، در ابتدای نمایش گروهها، ردیفهای آنها نمایش داده نخواهند شد و در حالت جمع شده قرار میگیرند.
groupSummary به معنای فعال سازی نمایش ردیف محاسبهی summary مانند sum، min، max و امثال آن بر روی یک گروه است.
اگر مقدار showSummaryOnHide مساوی true باشد، ردیف محاسبهی summary حتی در حالت groupCollapse: true نمایش داده خواهد شد.
فعال سازی محاسبهی جمع ستون تعداد بار مشاهدات مطالب
برای فعال سازی نهایی محاسبهی جمع ستون تعداد بار مشاهدات، علاوه بر تنظیم groupSummary به true، نیاز است در همان ستون مشخص کنیم که این محاسبات چگونه باید انجام شوند:
colModel: [ // ........ { name: '@(StronglyTyped.PropertyName<Post>(x => x.Title))', index: '@(StronglyTyped.PropertyName<Post>(x => x.Title))', align: 'right', width: 150, summaryTpl: '<div style="text-align: left;">خلاصه </div>', summaryType: function (val, name, record) { return ""; } }, // ........ { name: '@(StronglyTyped.PropertyName<Post>(x => x.NumberOfViews))', index: '@(StronglyTyped.PropertyName<Post>(x => x.NumberOfViews))', align: 'center', width: 70, summaryType: 'sum', summaryTpl: '<b>جمع مشاهدات: {0}</b>' } ],
summaryType مانند ستون عنوان، سفارشی شده نیز میتوان باشد. در ردیف summary و ستون عنوان تنها میخواهیم یک مقدار ثابت را نمایش دهیم، به همین جهت summaryType آن به یک مقدار خالی تنظیم شدهاست.
تغییر رنگ ردیف خلاصه عملیات هر گروه به همراه گشودن خودکار اولین گروه
گروه بندی به همراه یک سری متد توکار نیز هست. برای مثال اگر متد groupingToggle را بر روی Id هر گروه فراخوانی کنیم، میتوان سبب باز یا بسته شده آن گروه شد. متدهای دیگری مانند groupingGroupBy برای گروه بندی پویا و groupingRemove برای حذف گروه بندی نیز وجود دارند:
$('#list').jqGrid({ caption: "آزمایش دهم", //......... loadComplete: function() { //......... $('#list').jqGrid('groupingToggle', 'list' + 'ghead_0_0'); $("tr.jqfoot td").css({ "background": "#2f4f4f", "color": "#FFF" }); }, });
مثال کامل این قسمت را از اینجا میتوانید دریافت کنید:
jqGrid10.zip
در این قسمت بیشتر یک سری از ماژولها را به شما در قالب جداول گروه بندی شده معرفی خواهیم کرد :
همانطور که در قسمتهای قبلی گفتیم سرور IIS آماده خصوصی سازی و کار بر اساس علائق شماست؛ ولی توجه داشته باشید حذف تمامی ماژولها ممکن است اثرات جانبی هم داشته باشد. در اینجا ما ماژول هایی را به شما معرفی میکنیم که بدانید کار هر ماژول چیست تا مثلا با حذف ماژولی، امنیت وب سایت خود را به خطر نیندازید :
ماژولهای سودمند یا utility
نام ماژول: | UriCacheModule |
توضیح: | این ماژول نوعی کش برای URLها به شمار میرود. موقعی که url درخواست میشود، اطلاعات در اولین درخواست خوانده شده و کش میشود و اگر دوباره همان url درخواست شود، بدون خواندن تنظیمات و بر اساس تنظیمات قبلی، کار url مربوطه را انجام میدهد تا اطلاعات پیکربندی تغییر کند و بر اساس اطلاعات جدید، خود را به روز کند. |
تگ قابل پیکربندی: | لازم ندارد |
وابستگی: | ندارد |
اثرات حذف آن: | کارایی سیستم کاهش مییابد و سیستم مجبور است برای هر درخواست فایل پیکربندی را بخواند. |
نام ماژول : | FileCacheModule |
توضیح : | فایل هندلِ فایلهایی که قبلا در سرور باز شدهاند را کش میکند تا در صورت نیاز در دفعات بعدی سریعتر عمل کند. |
تگ قابل پیکربندی : | لازم ندارد . |
وابستگی : | ندارد. |
اثرات حذف آن : | کارایی سیستم کاهش مییابد. سیستم در هر اجرای دستور مربوط به فایلها باید فایل هندل را به دست آورد. |
نام ماژول : | TokenCacheModule |
توضیح : | توکنهای امنیتی ویندوز که پسوردهایی بر اساس authentication schemes هستند را کش میکند (anonymous authentication, basic authentication, IIS client certificate authentication ) |
تگ قابل پیکربندی : | لازم ندارد |
وابستگی : | ندارد |
اثرات حذف آن : | کارایی سیستم به شدت پایین میآید. کاربر باید با هر درخواستی لاگین کند. یکی از اصلیترین ضربهها با حذف این ماژول این است که اگر مثلا یک پسورد از یک فایل html محافظت میکند و این صفحه به 50 تصویر ارجاع دارد، 51 بار باید درخواست لاگین اجرا گردد یا شاید هم بدتر |
MANAGED ENGINE: ASP.NET INTEGRATION
نام ماژول : | ManagedEngine |
توضیح : | مدیریت ماژولهای native و مدیریت شده |
تگ قابل پیکربندی : | |
وابستگی : | ندارد |
اثرات حذف آن : | مشخصا غیرفعال شدن asp.net integrated و غیر فعال شدن تمامی ماژولها و هندلرهای تگ وب کانفیگ یا داخل فایل کانفیگ IIS که در مقالات قبلی به تفصیل بیان کردهایم. |
IIS 7 NATIVE MODULES
نام ماژول : | HttpCacheModule |
توضیح : | مدیریت کش خروجی در htttp.sys بر اساس پیکربندی مثل تعریف سایز کش و ... |
تگ قابل پیکربندی : | System.webServer/caching |
وابستگی : | ندارد. |
اثرات حذف آن : | محتوا دیگر به صورت کرنل مد، کش نمیشود و کش پروفایل هم ندید گرفته میشود و احتمالا بر کارآیی و استفاده از منابع هم اثر میگذارد. |
نام ماژول : | DynamicCompressionModule |
توضیح : | پیاده سازی in-memory compression در محتوای پویا |
تگ قابل پیکربندی : | system.webServer/httpCompression and system.webServer/urlCompression. |
وابستگی : | وابستگی ندارد چرا که به طور پیش فرض غیرفعال است. |
نام ماژول : | StaticCompressionModule |
توضیح : | پیادسازی فشرده سازی در محتوای ایستا و برای فایلهای سیستمی از نوع in memory |
تگ قابل پیکربندی : | system.webServer/httpCompression and system.webServer/urlCompression |
وابستگی : | ندارد. |
اثرات حذف آن : | در صورت عدم فشرده سازی بر مصرف ترافیک تاثیر گذار است. |
نام ماژول : | DefaultDocumentModule |
توضیح : | پیاده سازی یک لیست سند پیش فرض. درخواستها مدام پشت سر هم میآیند و این درخواستهای پشت سرهم، به سند پیش فرض هدایت میشوند. همان پنجره ای که شما به ترتیب فایلهای index.htm,index.asp,default.aspx و... را تعیین میکنید. |
تگ قابل پیکربندی : | system.webServer/defaultDocument |
وابستگی : | ندارد. |
اثرات حذف آن : | درخواست را به ریشه هدایت میکند. مثلا برای localhost صفحه 404 باز میگرداند و اگر directoryBrowsing فعال باشد لیستی از دایرکتوری ریشه را باز میگرداند. |
نام ماژول : | DirectoryListingModule |
توضیح : | پیادی سازی لیستی از محتویات یک دایرکتوری |
تگ قابل پیکربندی : | system.webServer/directoryBrowse |
وابستگی : | ندارد. |
اثرات حذف آن : | اگر این ماژول و ماژول قبلی غیرفعال باشند response نهایی خالی است. |
نام ماژول : | ProtocolSupportModule |
توضیح : | پیاده سازی اختصاصی از response header پیاده سازی تنظیمات trace و HTTP verbs. پیاده سازی تنظیمات مربوطه به keep-alive بر اساس پیکربندی |
تگ قابل پیکربندی : | system.webServer/httpProtocol |
وابستگی : | ندارد. |
اثرات حذف آن : | بازگرداندن پیام خطای "405 Method not allowed". |
نام ماژول : | HttpRedirectionModule |
توضیح : | پیاده سازی عملیات انتقال یا redirect |
تگ قابل پیکربندی : | system.webServer/httpRedirect |
وابستگی : | ندارد. |
اثرات حذف آن : | خطر امنیتی: اگر منابعی با redirect کردن محافظت میشوند، از این پس در دسترسند. |
نام ماژول : | ServerSideIncludeModule |
توضیح : | حمایت از فایل shtm یا shtml و ... |
تگ قابل پیکربندی : | system.webServer/serverSideInclude |
وابستگی : | ندارد. |
اثرات حذف آن : | این فایلها به صورت متنی نمایش داده میشوند |
نام ماژول : | StaticFileModule |
توضیح : | فایلهای ایستا را به همراه پسوند ارسال میکند. مثل jpg,html و نوع محتوا را بر اساس staticContent/mimeMap پیکربندی میکند. |
تگ قابل پیکربندی : | system.webServer/staticContent |
وابستگی : | ندارد. |
اثرات حذف آن : | فایلهای ایستا دیگر ارائه نشده و به جای آن خطای 404 بازگشت داده میشود. |
نام ماژول : | AnonymousAuthenticationModule |
توضیح : | پیاده سازی سیستم شناسایی افراد ناشناس. همانطور که میدانید در یک وب سایت حداقل محتوایی برای افرادی بدون داشتن اکانت هم وجود دارد. برای اینکار یک شیء httpuser ایجاد میکند. |
تگ قابل پیکربندی : | system.webServer/security/authentication/anonymousAuthentication |
وابستگی : | ندارد. |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS میباشد و در صورت نبودن هیچ سیستم شناسایی وجود نداشته و در نبود شیء httpuser سیستم خطای 401.2 را تولید میکند. |
نام ماژول : | CertificateMappingAuthenticationModule |
توضیح : | مجوز SSL را به Active Directory نگاشت میکند. |
تگ قابل پیکربندی : | system.webServer/security/authentication/clientCertificateMappingAuthentication |
وابستگی : | برای اینکه این ماژول وظیفه خود را انجام دهد باید تنظیمات SSL انجام شود و همچنین سیستم IIS جزئی از دامنه Active directory باشد |
اثرات حذف آن : | درخواستها، نرمال رسیدگی میشوند انگار SSL وجود ندارد. |
نام ماژول : | BasicAuthenticationModule |
توضیح : | پیاده سازی پایهای و روتین شناسایی کاربران بر اساس آن چیزی که در استانداد زیر آمده است |
تگ قابل پیکربندی : | system.webServer/security/authentication/basicAuthentication |
وابستگی : | None. |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناساسایی یا authenticate وجود داشته باشد. httpuser یک ساختار دادهای در IIS میباشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید میکند. |
نام ماژول : | WindowsAuthenticationModule |
توضیح : | ((windows Authentication (NTLM or Negotiate (Kerberos |
تگ قابل پیکربندی : | system.webServer/security/authentication/windowsAuthentication |
وابستگی : | ندارد. |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS میباشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید میکند. |
نام ماژول : | DigestAuthenticationModule |
توضیح : | پیاده سازی سیستم شناسایی دیاجست بر اساس RFC 2617 . |
تگ قابل پیکربندی : | system.webServer/security/authentication/digestAuthentication |
وابستگی : | IIS باید بخشی از دامنه Active Directory باشد. |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد.
httpuser یک ساختار داده ای در IIS میباشد و در صورت نبود، هیچ سیستم
شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید
میکند. |
نام ماژول : | IISCertificateMappingAuthenticationModule |
توضیح : | پیاده سازی نگاشت مجوزهای IIS، نگهداری و ذخیره اطلاعات همه نگاشتها و مجوزهای کاربری چون SSL client certificates |
تگ قابل پیکربندی : | system.webServer/iisClientCertificateMappingAuthentication |
وابستگی : | اطلاعات SSL به همراه دریافت client certificates جهت پیکربندی این ماژول |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد.
httpuser یک ساختار داده ای در IIS میباشد و در صورت نبود، هیچ سیستم
شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید
میکند. |
نام ماژول : | UrlAuthorizationModule |
توضیح : | پیاده سازی authorization بر اساس قوانین پیکربندی شده |
تگ قابل پیکربندی : | system.webServer/security/authorization |
وابستگی : | ندارد. |
اثرات حذف آن : | محتواهای محافظت شده توسط authorization دیگر محافظت نمیشوند. |
نام ماژول : | IsapiModule |
توضیح : | پیاده سازی ISAPI Extension |
تگ قابل پیکربندی : | system.webServer/isapiCgiRestriction |
وابستگی : | ندارد. |
اثرات حذف آن : | هندلرهای معرفی شده در بخش IsapiModule و تگ handlers دیگر اجرا نمیشوند |
نام ماژول : | IsapiFilterModule |
توضیح : | پیاده سازی ISAPI filter |
تگ قابل پیکربندی : | system.webServer/isapiFilters |
وابستگی : | ندارد. |
اثرات حذف آن : | اگر برنامه ای از ISAPI filter استفاده میکند، در اجرا دچار مشکل خواهد شد. |
نام ماژول : | IpRestrictionModule |
توضیح : | یک سیستم تشخیص دسترسی بر اساس آی پیهای ورژن4 |
تگ قابل پیکربندی : | system.webServer/security/ipSecurity |
وابستگی : | IPv4 stack باید نصب شود. |
اثرات حذف آن : | کلاینت هایی که IP هایشان در IPsecurity لیست شدهاند ندید گرفته میشوند |
نام ماژول : | RequestFilteringModule |
توضیح : | پیاده سازی یک مجموعه قدرتمند از قوانین امنیتی که درخواستهای مشکوک را پس میزند. |
تگ قابل پیکربندی : | system.webServer/security/requestFiltering |
وابستگی : | ندارد. |
اثرات حذف آن : | دیگر قوانین امنیتی اجرا نخواهند شد و سبب وجود مشکلات امنیتی میشود. |
نام ماژول : | CustomLoggingModule |
توضیح : | پیاده سازی اینترفیس ILogPlugin در سمت IIS، به مشتریان اجازه میدهد تا لاگهای خود را توسعه دهند. هر چند این روش توصیه نمیشود و توصیه کارشناس مایکروسافت استفاده از یک ماژول دست نویس از نوع RQ_LOG_REQUEST می باشد. Implements the ILogPlugin interface on top of IIS. ILogPlugin is a previous COM implementation that allowed customers to extend IIS logging. We do not not recommend extending IIS using this interface. Instead, customers should write a module and subscribe to the RQ_LOG_REQUEST notification. |
تگ قابل پیکربندی : | system.webServer/httpLogging and system.applicationhost/sites/site/logFile/customLogPluginClsid |
وابستگی : | ندارد. |
اثرات حذف آن : | مسلما پلاگینهایهای این اینترفیس از کار میافتند که سیستم ODBC Logging هم جز آن است. |
نام ماژول : | CustomErrorModule |
توضیح : | پیاده سازی مدیریت خطاهای ویژه |
تگ قابل پیکبرندی : | system.webServer/httpErrors |
وابستگی : | None. |
اثرات حذف آن : | در صورتی که خطایی از هسته باشد، نتیجه یک صفحه، با توضیح مختصری از خطا خواهد بود. در غیر این صورت اگر خطا از برنامه یا کامپوننتی باشد جزئیات خطا فاش خواهد شد |
نام ماژول : | HttpLoggingModule |
توضیح : | پیاده سازی سیستم logging استاندارد http.sys |
تگ قابل پیکربندی : | system.applicationHost/log and system.webServer/httpLogging |
وابستگی : | ندارد. |
اثرات حذف آن : | از کار افتادن سیستم لاگ |
نام ماژول : | FailedRequestsTracingModule |
توضیح : | پیاده سازی سیستم ردیابی درخواستهای ناموفق و اجرای قوانین، طبق پیکربندی |
تگ قابل پیکربندی : | system.webServer/tracing and system.webServer/httpTracing |
وابستگی : | ندارد. |
اثرات حذف آن : | Tracing http requests will no longer work. |
نام ماژول : | RequestMonitorModule |
توضیح : | پیاده سازی IIS Run-time State and Control Interface یا به اختصار RSCA . به کاربران اجازه میدهد از اطلاعات، حین اجرا، کوئری بگیرند. مثل درخواست درحال اجرای جاری، آغاز به کار یا توقف وب سایت و دامنههای اپلیکیشن در حال اجرای جاری |
تگ قابل پیکربندی : | ندارد. |
وابستگی : | ندارد. |
اثرات حذف آن : | ابزارهای مرتبط با این موضوع از کار میافتند |
نام ماژول : | CgiModule |
توضیح : | پیاده سازی CGI در سمت IIS |
تگ قابل پیکبرندی : | system.webServer/cgi and system.webServer/isapiCgiRestriction |
وابستگی : | ندارد. |
اثرات حذف آن : | برنامههای CGI متوقف میشوند |
نام ماژول : | TracingModule |
توضیح : | پیاده سازی سیستم ردیابی ETW |
تگ قابل پیکربندی : | system.webServer/httpTracing |
وابستگی : | ندارد. |
اثرات حذف آن : | باعث از کار افتادن سیستم مربوطه میشود |
نام ماژول : | ConfigurationValidationModule |
توضیح : | اعتبارسنجی تنظیمات برنامه ASP.Net که به حالت integrate انتقال یافته است |
تگ قابل پیکربندی : | system.webServer/Validation |
وابستگی : | ندارد. |
اثرات حذف آن : | عدم اعتبارسنجی و در نتیجه عدم نمایش خطاها |
MANAGED MODULES:
نام ماژول : | OutputCache |
توضیح : | پیاده سازی output caching |
تگ قابل پیکربندی : | system.web/caching/outputCache |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | عدم اجرای output cache |
نام ماژول : | Session |
توضیح : | مدیریت سشن ها |
تگ قابل پیکربندی : | system.web/sessionState |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | سشنها از دسترس خارج میشوند. |
نام ماژول : | WindowsAuthentication |
توضیح : | |
تگ قابل پیکربندی : | system.web/authentication |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | این حالت قابل اجرا نخواهد بود |
نام ماژول : | FormsAuthentication |
توضیح : | |
تگ قابل پیکربندی : | system.web/authentication |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | این حالت قابل اجرا نیست و کاربران مجوز دار هم نمیتوانند به منابع محافظت شده دسترسی داشته باشند. |
نام ماژول : | DefaultAuthentication |
توضیح : | اطمینان از وجود شی Authentication در context مربوطه |
تگ قابل پیکربندی : | system.web/authentication |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | اگر مد Forms authentication انتخاب شده باشد بر روی بعضی از کاربران ناشناس کار نخواهد کرد و رویداد DefaultAuthentication.OnAuthenticate اجرا نخواهد شد. |
نام ماژول : | RoleManager |
توضیح : | |
تگ قابل پیکربندی : | |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | این قابلیت در دسترس نمیباشد |
نام ماژول : | UrlAuthorization |
توضیح : | |
تگ قابل پیکربندی : | system.web/authorization. |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | باعث از کار افتادن asp.net authorization و فاش شدن بعضی اطلاعات و همچنین دیگر تهدیدات امنیتی |
نام ماژول : | AnonymousIdentification |
توضیح : | |
تگ قابل پیکربندی : | |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | The anonymous identification feature used by the ASP.NET Profile will not work. |
نام ماژول : | Profile |
توضیح : | |
تگ قابل پیکربندی : | |
وابستگی : | ManagedEngine module must be installed. |
اثرات حذف آن : | ASP.Net Profile از کار خواهد افتاد |
نام ماژول : | UrlMappingsModule |
توضیح : | تبدیل یک Url واقعی به یک Url کاربرپسند |
تگ قابل پیکبرندی : | |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | نگاشت Urlها صورت نمیگیرد |
آموزش PouchDB : معرفی
هدف این مقاله بر این است که شما را با دیتابیس PouchDB آشنا سازد .
در مطلب اول هدف فقط آشنایی و نحوه نصب PouchDB قرار خوهد داشت و در مطالب بعدی نحوه آشنایی با نحوه کدنویسی و استفاده به صورت آفلاین یا آنلاین بررسی خواهد شد .
فهرست مطالب :
- بخش اول : معرفی PouchDB
- شروع به کار با PouchDB
- نحوه استفاده از API ها
- سوالات متداول در مورد PouchDB
- خطاهای احتمالی
- پروژهها و پلاگین های PouchDB
- فایرفاکس 12 و بالاتر
- گوگل کروم 19 و بالاتر
- اپرا 12 و بالاتر
- سافاری 5 و بالاتر
- اینترنت اکسپلورر 10 و بالاتر
- NodeJs 0.10 و بالاتر
- و به صورت شگفت انگیزی در Apache Cordova
<script src="pouchdb-2.1.0.min.js"></script>
$ npm install pouchdb
هنگام ایجاد یک Type جدید باید سعی کنیم دیتای داخلی Type را تا حد ممکن Immutable کنیم. حتی اگر نیاز داریم یک شیء را برگردانیم، بهتر است که یک instance جدید را برگردانیم، نه اینکه همان شیء موجود را تغییر دهیم. نتیحه این کار نهایتا به شفافیت بیشتر و Thread-Safe بودن منجر خواهد شد.
مثال:
public class Rectangle { public int Length { get; set; } public int Height { get; set; } public void Grow(int length, int height) { Length += length; Height += height; } } Rectangle r = new Rectangle(); r.Length = 5; r.Height = 10; r.Grow(10, 10);// r.Length is 15, r.Height is 20, same instance of r
// After public class ImmutableRectangle { int Length { get; } int Height { get; } public ImmutableRectangle(int length, int height) { Length = length; Height = height; } public ImmutableRectangle Grow(int length, int height) => new ImmutableRectangle(Length + length, Height + height); } ImmutableRectangle r = new ImmutableRectangle(5, 10); r = r.Grow(10, 10);// r.Length is 15, r.Height is 20, is a new instance of r
یکی از موارد با اهمیت در سبک کد نویسی تابعی را در مثال زیر ببینید:
public static void Main() { Console.WriteLine(GetSalutation(DateTime.Now.Hour)); } // imparitive, mutates state to produce a result /*public static string GetSalutation(int hour) { string salutation; // placeholder value if (hour < 12) salutation = "Good Morning"; else salutation = "Good Afternoon"; return salutation; // return mutated variable }*/ public static string GetSalutation(int hour) => hour < 12 ? "Good Morning" : "Good Afternoon";
در قسمت قبلی درباره توابع HOF صحبت کردیم. به طور خلاصه توابعی که یک تابع را به عنوان ورودی میگیرند و یک تابع را به عنوان خروجی برمیگردانند. به مثال زیر توجه کنید:
public static int Count<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { int count = 0; foreach (TSource element in source) { checked { if (predicate(element)) { count++; } } } return count; }
ترکیب توابع به عمل پیوند دادن چند تابع ساده، برای ایجاد توابعی پیچیده گفته میشود. دقیقا مانند عملی که در ریاضیات انجام میشود. خروجی هر تابع به عنوان ورودی تابع بعدی مورد استفاده قرار میگیرد و در آخر ما خروجی آخرین فراخوانی را به عنوان نتیجه دریافت میکنیم. ما میتوانیم در #C به روش برنامه نویسی تابعی، توابع را با یکدیگر ترکیب کنیم. به مثال زیر توجه کنید:
public static class Extensions { public static Func<T, TReturn2> Compose<T, TReturn1, TReturn2>(this Func<TReturn1, TReturn2> func1, Func<T, TReturn1> func2) { return x => func1(func2(x)); } } public class Program { public static void Main(string[] args) { Func<int, int> square = (x) => x * x; Func<int, int> negate = x => x * -1; Func<int, string> toString = s => s.ToString(); Func<int, string> squareNegateThenToString = toString.Compose(negate).Compose(square); Console.WriteLine(squareNegateThenToString(2)); } }
یکی از روشهای مهم در سبک برنامه نویسی تابعی، فراخوانی متدها به صورت زنجیرهای و پاس دادن خروجی یک متد به متد بعدی، به عنوان ورودی است. به عنوان مثال کلاس String Builder یک مثال خوب از این نوع پیاده سازی است. کلاس StringBuilder از پترن Fluent Builder استفاده میکند. ما میتوانیم با اکستنشن متد هم به همین نتیجه برسیم. نکته مهم در مورد کلاس StringBuilder این است که این کلاس، شیء string را mutate نمیکند؛ به این معنا که هر متد، تغییری در object ورودی نمیدهد و یک خروجی جدید را بر میگرداند.
string str = new StringBuilder() .Append("Hello ") .Append("World ") .ToString() .TrimEnd() .ToUpper();
public static class Extensions { public static StringBuilder AppendWhen(this StringBuilder sb, string value, bool predicate) => predicate ? sb.Append(value) : sb; } public class Program { public static void Main(string[] args) { // Extends the StringBuilder class to accept a predicate string htmlButton = new StringBuilder().Append("<button").AppendWhen(" disabled", false).Append(">Click me</button>").ToString(); } }
نوعهای اضافی درست نکنید ، به جای آن از کلمهی کلیدی yield استفاده کنید!
گاهی ما نیاز داریم لیستی از آیتمها را به عنوان خروجی یک متد برگردانیم. اولین انتخاب معمولا ایجاد یک شیء از جنس List یا به طور کلیتر Collection و سپس استفاده از آن به عنوان نوع خروجی است:
public static void Main() { int[] a = { 1, 2, 3, 4, 5 }; foreach (int n in GreaterThan(a, 3)) { Console.WriteLine(n); } } /*public static IEnumerable<int> GreaterThan(int[] arr, int gt) { List<int> temp = new List<int>(); foreach (int n in arr) { if (n > gt) temp.Add(n); } return temp; }*/ public static IEnumerable<int> GreaterThan(int[] arr, int gt) { foreach (int n in arr) { if (n > gt) yield return n; } }
در قسمت قبلی به طور کلی درباره برنامه نویسی Imperative صحبت کردیم. در مثال زیر یک نمونه از تبدیل یک متد که با استایل Imperative نوشته شده به declarative را میبینید. شما میتوانید ببینید که چقدر کوتاهتر و خواناتر شده:
List<int> collection = new List<int> { 1, 2, 3, 4, 5 }; // Imparative style of programming is verbose List<int> results = new List<int>(); foreach(var num in collection) { if (num % 2 != 0) results.Add(num); } // Declarative is terse and beautiful var results = collection.Where(num => num % 2 != 0);
Immutable Collection
در مورد اهمیت immutable قبلا صحبت کردیم؛ Immutable Collection ها، کالکشنهایی هستند که به جز زمانیکه ایجاد میشنود، اعضای آنها نمیتوانند تغییر کنند. زمانیکه یک آیتم به آن اضافه یا کم شود، یک لیست جدید، برگردانده خواهد شد. شما میتوانید انواع این کالکشنها را در این لینک ببینید.
به نظر میرسد که ایجاد یک کالکشن جدید میتواند سربار اضافی بر روی استفاده از حافظه داشته باشد، اما همیشه الزاما به این صورت نیست. به طور مثال اگر شما f(x)=y را داشته باشید، مقادیر x و y به احتمال زیاد یکسان هستند. در این صورت متغیر x و y، حافظه را به صورت مشترک استفاده میکنند. به این دلیل که هیچ کدام از آنها Mutable نیستند. اگر به دنبال جزییات بیشتری هستید این مقاله به صورت خیلی جزییتر در مورد نحوه پیاده سازی این نوع کالکشنها صحبت میکند. اریک لپرت یک سری مقاله در مورد Immutable ها در #C دارد که میتوانید آن هار در اینجا پیدا کنید.
Thread-Safe Collections
Collection | توضیحات |
ConcurrentDictionary | پیاده سازی thread safe از دیکشنری key-value |
ConcurrentQueue | پیاده سازی thread safe از صف (اولین ورودی ، اولین خروجی) |
ConcurrentStack | پیاده سازی thread safe از پشته (آخرین ورودی ، اولین خروجی) |
ConcurrentBag | پیاده سازی thread safe از لیست نامرتب |
این کلاسها در واقع همه مشکلات ما را حل نخواهند کرد؛ اما بهتر است که در ذهن خود داشته باشیم که بتوانیم به موقع و در جای درست از آنها استفاده کنیم.
در این قسمت از مقاله سعی شد با روشهای خیلی ساده، با مفاهیم اولیه برنامه نویسی تابعی درگیر شویم. در ادامه مثالهای بیشتری از الگوهایی که میتوانند به ما کمک کنند، خواهیم داشت.
مثال: نیاز به نگاشت کلمهی عبور، به کلمهی عبور هش شده
فرض کنید موجودیت کاربری که قرار است در بانک اطلاعاتی ذخیره شود، چنین ساختاری را دارد:
namespace AutoMapperInjection.Entities { public class User { public int Id { set; get; } public string HashedPassword { set; get; } } }
namespace AutoMapperInjection.Models { public class UserDto { public string Password { set; get; } } }
namespace AutoMapperInjection.Controllers { [ApiController] [Route("[controller]")] public class HomeController : ControllerBase { private readonly IMapper _mapper; public HomeController(IMapper mapper) { _mapper = mapper ?? throw new NullReferenceException(nameof(mapper)); } [HttpPost("[action]")] public IActionResult RegisterUser(UserDto model) { var user = _mapper.Map<User>(model); // TODO: Save user return Ok(); } } }
using System; using System.Security.Cryptography; using System.Text; namespace AutoMapperInjection.Services { public interface IPasswordHasherService { string GetSha256Hash(string input); } public class PasswordHasherService : IPasswordHasherService { public string GetSha256Hash(string input) { using var hashAlgorithm = new SHA256CryptoServiceProvider(); var byteValue = Encoding.UTF8.GetBytes(input); var byteHash = hashAlgorithm.ComputeHash(byteValue); return Convert.ToBase64String(byteHash); } } }
روش اول: IValueResolverها قابلیت تزریق وابستگی را در سازندهی خود دارند
توسط یک IValueResolver سفارشی، میتوانیم مشخص کنیم که برای مثال اطلاعات یک خاصیت خاص، چگونه باید از منبع دریافتی تامین شود:
public class HashedPasswordResolver : IValueResolver<UserDto, User, string> { private readonly IPasswordHasherService _hasher; public HashedPasswordResolver(IPasswordHasherService hasher) { _hasher = hasher ?? throw new ArgumentNullException(nameof(hasher)); } public string Resolve(UserDto source, User destination, string destMember, ResolutionContext context) { return _hasher.GetSha256Hash(source.Password); } }
پس از آن، روش استفادهی از این تامین کنندهی مقدار سفارشی، به صورت زیر است:
public class UserDtoMappingsProfile : Profile { public UserDtoMappingsProfile() { // Map from User (entity) to UserDto, and back this.CreateMap<User, UserDto>() .ReverseMap() .ForMember(user => user.HashedPassword, exp => exp.MapFrom<HashedPasswordResolver>()); } }
namespace AutoMapperInjection { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddScoped<IPasswordHasherService, PasswordHasherService>(); services.AddAutoMapper(typeof(UserDtoMappingsProfile).Assembly); services.AddControllers(); }
روش دوم: IMappingActionها قابلیت تزریق وابستگی را در سازندهی خود دارند
میتوان پیش و یا پس از عملیات نگاشت، منطقی را توسط یک IMappingAction سفارشی بر روی آن اجرا کرد که در اینجا نیز امکان تزریق وابستگی در سازندهی IMappingActionهای پیاده سازی شده، وجود دارد:
public class UserDtoMappingsAction : IMappingAction<UserDto, User> { private readonly IPasswordHasherService _hasher; public UserDtoMappingsAction(IPasswordHasherService hasher) { _hasher = hasher ?? throw new ArgumentNullException(nameof(hasher)); } public void Process(UserDto source, User destination, ResolutionContext context) { destination.HashedPassword = _hasher.GetSha256Hash(source.Password); } }
در این حالت روش استفادهی از کلاس UserDtoMappingsAction به صورت زیر است:
public class UserDtoMappingsProfile : Profile { public UserDtoMappingsProfile() { // Map from User (entity) to UserDto, and back this.CreateMap<User, UserDto>() .ReverseMap() .AfterMap<UserDtoMappingsAction>(); } }
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: AutoMapperInjection.zip
مروری سریع بر neo4j
در زیر برخی دستورات ابتدایی آن آورده شده است.
CREATE (VariableName:objectType { guid: {keyInMainDB }, property1 :value1 ,property2 : value2 ,... )
MERGE (VariableName:objectType { guid: keyInMainDB }) SET VariableName +={property1: value1,property2: value2,...}
MERGE (object:User { guid: 1353554 }) SET object +={username:"nasser" ,time_created: 1522480294 }
بازیابی یک آبجکت
برای بازیابی یک آبجکت، از فرم ساده زیر استفاده میشود:
match (VariableName:objectType ) return VariableName
match (object:User { guid: 1353554 }) return object
match (object:User ) where object.time_created>1522480293 return object
ایجاد رابطه بین دو شیء
برای ایجاد رابطه بین دو شیء، از فرم زیر استفاده میکنیم:
MATCH (v1:objectType1 {guid: guid1}), (v2:objectType2 {guid: guid2}) MERGE (v1)-[:RelationshipName]->(v2)
MATCH (usr:User {guid: 1353554 }),(img:Image {guid: 88554 }) MERGE (usr)-[:LIKE]->(img)
MATCH (usr:User)-[r:LIKE]-() Return usr
MATCH ()-[r:LIKE]-(n) Return n
MATCH (usr:User{guid:1353554 })-[r:LIKE]-(n) Return n
MATCH p=()-[r:LIKE]->() RETURN p
MATCH (usr:User )-[r:LIKE]-(n) where usr.time_created>1522480293 Return usr