مطالب
متدهای الحاقی - Extension Methods
چقدر خوب می‌شد اگر،
 
نوع داده String دارای متدی جهت حذف تگ‌های HTML داشت:
string htmlStr = "<h1>.Net Tips</h1>";
htmlStr.ClearHtmlTags();
کلاس Image دارای متدی جهت تغییر اندازه (Resize) داشت:
image1.Resize(50, 80);
کنترل DropDownList متدی جهت انقیاد داده‌ها داشت:
dropDownList1.Bind((List<Category>)categories, "Name", "Id");
متدهای الحاقی به همین منظور متولد شده اند. در واقع هر زمان بدنه کلاسی (نوع داده، کنترل و تمام اشیاء دات نتی) در اختیار ما نباشد امکان اضافه کردن متدهای الحاقی به آنها وجود دارد. برای این منظور کافیست چند نکته را رعایت کنید:
  1. کلاس دربرگیرنده متد یا متدهای الحاقی باید Public و Static باشد.
  2. متد الحاقی باید Public و Static باشد.
  3. اولین پارامتر متد الحاقی باید با کلمه کلیدی this همراه باشد و این پارامتر اشاره به کلاسی دارد که متد جاری به آن الحاق (یا ضمیمه) خواهد شد.
یک مثال:
در این مثال متدالحاقی برای بهبود نوع داده String را خواهیم دید. وظیفه‌ی این متد شمارش تعداد کلمات موجود در رشته است.
public static class StringExtensions
{

        /// <summary>
        /// Count all words in a given string
        /// </summary>
        /// <param name="input">string to begin with</param>
        /// <returns>int</returns>
        public static int WordCount(this string input)
        {
            var count = 0;
            try
            {
                // Exclude whitespaces, Tabs and line breaks
                var re = new Regex(@"[^\s]+");
                var matches = re.Matches(input);
                count = matches.Count;
            }
            catch (Exception)
            {
                return -1;
            }
            return count;
        }
}
نحوه استفاده:
var s = "i Love Dot Net Tips.";
var wordCount = s.WordCount();
در ضمن وب سایتی جهت به اشتراک گذاری این متدها به عنوان یکی از بهترین مراجع در دسترس است: http://extensionmethod.net 
با توجه به این مطلب توسعه پروژه ای در همین سایت با عنوان "متدهای الحاقی " آغاز شده است. در این پروژه ضمن پوشش متدهای الحاقی پرکاربرد سعی به توسعه متدهای الحاقی داریم که بیشتر در برنامه‌های فارسی کاربرد دارند.
نظرات مطالب
امن سازی برنامه‌های ASP.NET Core توسط IdentityServer 4x - قسمت سیزدهم- فعالسازی اعتبارسنجی دو مرحله‌ای
مقدا User.Identity.IsAuthenticated همیشه false هست. بعد از لاگین فقط از طریق HttpContext.AuthenticateAsync می‌تونم بفهمم کاربر لاگین کرده.مقدار User.Identity.IsAuthenticated مگر بعد از لاگین نباید true شود؟
نظرات اشتراک‌ها
چرا از آنگولار به ری اکت + ری داکس سوئیچ کردم!
منظورتون رو از سرور ساید متوجه نمیشم. هیچ یک از کتابخانه‌های بالا سرورساید نیستن. همه کتابخانه‌های spa فقط سمت کاربر را پوشش میدهند و angular هم بدین شکل است . تنها موردی که انگیولار پوشش میدهد وجود کتابخانه‌های همراهی چون rxjs است که البته قابل تغییر نیز هست. در صورتی که در ری اکت وجود ندارد.دیگر فرقی نمیکند که سمت سرور با چه فناوری نوشته شده است تنها جنبه ای که سمت سرور ایفا میکند وجود یک سرویس پاسخگوست که REST Api یکی از آن هاست خواه php خواه .net و حتی node js و...
در حین توسعه نکات زیادی باید مورد توجه قرار بگیرد اول اینکه ری اکت  نیازمند و محتاج کتابخانه‌های متفرقه ای هست که باید با انتخاب خودتان استفادده شوند حال اگر در نظر بگیریم در یکی از آپدیت‌ها ناسازگاری صورت بگیرد میتواند کل پروژه را تحت تاثیر قرار بدهد ولی در انگیولار از آنجا یک دستی کار توسط انگیولار تامین میشود کمتر این مشکلات دیده میشود ، همین الانش هم گاها مشکلاتی در این حالت رخ میدهد وای به حال اینکه توسط هیچ منبعی این یک دستی صورت نگیرد. حال تصور کنید در آپدیت عظیم یک پروژه چگونه یک مشکل کوچک میتواند کل کار را برای مدتی بر زمین بزند با این ادعا که کتابخانه‌های متن باز و رایگان تحت لایسنس‌های مختلف داریم.
در لینکی که قرار دادید نوشته است که کامپوننت‌های خود را کوچک نگه دارید یعنی اینکه توسعه دهنده میداند که اگر یک کامپوننت بخواهد بزرگ شود به چه دردسر زیادی میرسد و چه مخلوطی از کدها را خواهد داشت.
استفاده از تایپ اسکریپت برای انگیولار یک نقطه ضعف نیست بلکه یک مزیت محسوب میشود. استفاده از تایپ اسکریپ باعث میشود نگهداری کد ساده‌تر باشد و کدها را در قالب ساده‌تر و با سرعت بیشتری میتوان نوشت. هر روز نسخه جدید از مرورگها با پشتیبانی از فناوری‌های جدید می‌آیند ولی بنا به مسائلی چون عدم پشتیبانی مرورگرها و یا قدیمی بودن مرورگر کاربر مجبور هستیم کدها را به شکل قدیمی بنویسیم و شاید این کدهای جدید باعث سرعت و کارایی بهتر باشند ولی با تایپ اسکریپت میتوان در آینده تنها یا یک ترانسپایل ساده به هر ورژن از ES تبدیل کنیم بدون اینکه نیاز به بازنویسی کد داشته باشیم که مستلزم وقت و هزینه خواهد بود. پس کدی که الان نوشته میشود در واقع کد به روز برای آینده هم محسوب میشود.
از نظر جنبه مالی همه پروژها به همین صورت هستند و ری اکت هم مستثنی نیست. همه کتابخانه هایی که متن باز هستند اگر به سود دهی نرسند و یا دیگر راضیشان نکند ان را رها میکنند. ابزرهای متن باز هم بدین صورت هستند هیچ شرکتی نمیآید پول و زمانش را صرف چیزی کند که برایش هیچ منفعتی به دنبال نداشته باشد و این قانون اول تجارت است. آیا فیس بوک همانند مایکروسافت یا گوگل نیست؟

ولی در نهایت هر دو ابزار و دیگر ابزارها هستند و تیم سازنده با توجه به نیازها باید ابزار خود را انتخاب کند.
مطالب دوره‌ها
ارتباطات بلادرنگ و SignalR
زمانیکه صحبت از برنامه‌های بلادرنگ می‌شود با کاربرانی سر و کار داریم که نیاز دارند تا اطلاعات مورد نیاز خود را همواره و بلافاصله در آخرین وضعیت به روز آن مشاهده کنند. در این بین، کلاینت می‌خواهد یک برنامه وب باشد یا سیلورلایت و یا یک برنامه نوشته شده با WPF. حتی برنامه‌های موبایل را نیز باید به این لیست اضافه کرد.
در اینجا کلمه بلادرنگ به معنای ارسال اطلاعات از طرف سرور به کلاینت‌ها با فاصله زمانی بسیار کوتاهی از به روز رسانی اطلاعات صورت گرفته در سمت سرور است.
نمونه‌ای از این برنامه‌ها شامل موارد ذیل هستند:
- اطلاع رسانی همزمان به گروهی از کاربران
- جستجوهای زنده و به روز رسانی‌هایی از این دست
- نمایش بلادرنگ قیمت‌ها و وضعیت تجاری محصولات و سهام‌ها
- بازی‌های تعاملی
- برنامه‌های گروهی و تعاملی (مانند برنامه‌های Chat)
- برنامه‌های شبکه‌های اجتماعی (برای مثال پیام جدیدی دارید؛ شخص خاصی آنلاین یا آفلاین شد و امثال آن)

بنابراین به صورت خلاصه قصد داریم به ارائه بازخوردها و اطلاع رسانی‌های بلادرنگ یا نسبتا سریع و به روز از سمت سرور به کلاینت‌ها برسیم.
برای مثال یک دیتاگرید را درنظر بگیرید. دو کاربر در شبکه صفحه یکسانی را گشوده‌اند و یکی از آن‌ها مشغول به ویرایش و یا حذف اطلاعات است. در ارتباطات بلادرنگ کاربر یا کاربران دیگر نیز باید (یا بهتر است) در زمانیکه گرید یکسانی را گشوده‌اند، بلافاصله آخرین تغییرات را ملاحظه کنند. یا حتی حالتی را درنظر بگیرید که شخصی SQL Server management studio را گشوده و در آنجا مشغول به تغییر اطلاعات گردیده است. در این حالت نیز بهتر است آخرین تغییرات بلافاصله به اطلاع کاربران رسانده شوند.

معرفی الگوی Push service

البته باید دقت داشت که الگوی push service یک الگوی رسمی ذکر شده در گروه‌های مرسوم الگوهای طراحی نیست، اما مفهوم آن سرویسی است که چندین کار ذیل را انجام می‌دهد:
الف) پذیرش اتصالات از چندین مصرف کننده. مصرف کننده‌ها در اینجا الزاما محدود به کلاینت‌های وب یا دسکتاپ نیستند؛ می‌توانند حتی یک سرور یا سرویس دیگر نیز باشند.
ب) قادر است اطلاعات را به مصرف کننده‌های خود ارسال کند. این سرویس می‌تواند یک برنامه ASP.NET باشد یا حتی یک سرویس متداول ویندوز.
ج) در اینجا چندین منبع خارجی مانند یک بانک اطلاعاتی یا تغییرات رخ داده توسط یک سخت افزار که می‌توانند سبب بروز رخدادهایی در push service گردند نیز می‌تواند وجود داشته باشند. هر زمان که تغییری در این منابع خارجی رخ دهد، مایل هستیم تا مصرف کننده‌ها را مطلع سازیم.


پروتکل HTTP و ارتباطات بلادرنگ

پروتکلی که در ارتباطات بلادرنگ مبتنی بر SignalR مورد استفاده قرار می‌گیرد، HTTP است و از قابلیت‌های Request و Response آن در اینجا بیشترین بهره برده می‌شود. پیاده سازی Push عموما بر مبنای یکی از روش‌های متداول زیر است:
1) Periodic polling
به این معنا که مثلا هر 10 ثانیه یکبار، کاری را انجام بده؛ مانند ارسال متناوب: آیا تغییری رخ داده؟ آیا تغییری رخ داده؟ و .... به همین ترتیب. این روش اصلا بهینه نبوده و منابع زیادی را خصوصا در سمت سرور مصرف خواهد کرد. برای مثال:
function getInfo() {
         $.ajax("url", function ( newInfo){
                  if ( newInfo != null) {
                      // do something with the data
                  }
         });
    // poll again after 20 seconds
    setTimeout(getInfo,20000);
}
// start the polling loop
getInfo();

2) Long polling
به آن HTTP Streaming یا Comet هم گفته می‌شود. این روش نسبتا هوشمند بوده و کلاینت اتصالی را به سرور برقرار خواهد کرد. سرور در این حالت تا زمانیکه اطلاعاتی را در دسترس نداشته باشد، پاسخی نخواهد داد. برای نمونه:
function getNewInfo(){
  $.ajax("url", function (newinfo) {
      // do something with the data
  // start the new request
      getNewINfo();
  });
}
// start the polling loop
getNewInfo();

این روش نسبت به حالت Periodic polling بهینه‌تر است اما نیاز به اتصالات زیادی داشته و همچنین تردهای بسیاری را در سمت سرور به خود مشغول خواهد کرد.

3) Forever frame
فقط در IE پشتیبانی می‌شود. در این روش یک Iframe مخفی توسط مرورگر تشکیل شده و از طریق آن درخواستی به سرور ارسال می‌شود. سپس سرور متناوبا با تزریق اسکریپت‌هایی به این Iframe سبب فراخوانی مجدد وضعیت خود می‌گردد. در این روش نیز به ازای هر درخواست و پاسخ، ارتباطات گشوده و بسته خواهند شد.

4) Server Sent Events یا SSE
این مورد جزو استاندارد HTML5 است. در اینجا اتصالی برقرار شده و داده‌ها از طریق اتصالات HTTP منتقل می‌شوند.
var eventSrc = new EventSource("url");
    // register event handler for the message
    eventSrc.addEventListener( "message",function (evt) {
    //process the data
});
این روش نیز بسیار شبیه به حالت long polling است. سرور تا زمانیکه اطلاعاتی را برای پاسخ دهی فراهم نداشته باشد، اتصال را باز نگه می‌دارد. به این ترتیب از لحاظ مقیاس پذیری گزینه بهتری است (نسبت به حالتیکه مدام اتصال برقرار و قطع می‌شود). اکثر مرورگرها منهای نگارش‌های قدیمی IE از این روش پشتیبانی می‌کنند.
تنها تفاوت آن با حالت long polling در این است که پس از ارائه پاسخ به کلاینت، اتصال را قطع نمی‌کند. Long polling نیز اتصال را باز نگه می‌دارد، اما این اتصال را بلافاصله پس از ارائه پاسخ، می‌بندد.

5) Web sockets
Web sockets در سکوی کاری ویندوز، تنها در ویندوز‌های 8، ویندوز سرور 2012 و دات نت 4 و نیم پشتیبانی می‌شود. هرچند این روش در حال حاضر به عنوان بهترین روش Push مطرح است اما به دلیل محدودیتی که یاد شد، مدتی طول خواهد کشید تا استفاده گسترده‌ای پیدا کند.
var socket = new WebSocket("url");
socket.onmessage = function (msg) {
var newInfo = msg.data;
// do something with the data
}
// client can also send request to server
socket.send(.... )
با این اوصاف آیا راه حل بهتر و میانه‌تری وجود دارد؟
بلی. اگر به وضعیت فعلی سکوی کاری ASP.NET نگاه کنیم:

SignalR را می‌توان مشاهده کرد که در گروه ساخت سرویس‌های آن قرار گرفته است. همانطور که ملاحظه می‌کنید، این سرویس جدید آنچنان وابستگی به سایر اجزای آن نداشته و می‌تواند خارج از ASP.NET نیز مورد استفاده قرار گیرد.

SignalR چیست؟

SignalR راه حلی است سمت سرور برای نوشتن push services. همچنین به همراه کتابخانه‌های سمت کاربری است که ارتباطات push services را در انواع و اقسام سکوهای کاری میسر می‌سازد. SignalR سورس باز بوده و برای اعمال غیرهمزمان (asynchronous) بهینه سازی شده است.
SignalR بر اساس مدل ذهنی اتصالات ماندگار (persistent connections) طراحی شده است. اتصالات ماندگار را باید به عنوان اتصالاتی سریع و غیرطولانی درنظر گرفت. در اینجا Signal یک اتصال است که اطلاعاتی به آن ارسال می‌گردد و هدف، انتقال قطعات کوچکی از اطلاعات است و هدف، ارسال حجم عظیمی از اطلاعات نیست. برای مثال اطلاع رسانی سریعی صورت گیرد که تغییراتی رخ داده است و سپس ادامه کار و دریافت اطلاعات واقعی توسط فرآیندهای متداول مثلا HTTP GET انجام شود. البته باید دقت داشت SignalR نیز نهایتا از یکی از 5 روش push بررسی شده در این قسمت استفاده می‌کند. اما بر اساس توانایی‌های کلاینت و سرور، به صورت هوشمند بهترین و بهینه‌ترین انتخاب را به کاربر ارائه می‌دهد.
اتصالات ماندگار قسمت سطح پایین SignalR را تشکیل می‌دهند. سطح بالاتر آن که این مفاهیم را به شکلی کپسوله شده ارائه می‌دهد، Hubs نام دارد که پایه اصلی دوره جاری را تشکیل خواهد داد.



همانطور که عنوان شد، SignalR سورس باز بوده و دارای مخزن کدی عمومی در GitHub است. همچنین بسته‌های تشکیل دهنده‌ی آن از طریق NuGet نیز قابل دریافت هستند. این بسته‌ها شامل هسته SignalR و کلاینت‌های آن مانند کلاینت‌های WinRT، سیلورلایت، jQuery، ویندوز فون8 و امثال آن هستند.

شروع کار با SignalR

تیم SignalR مثالی مقدماتی از نحوه کار با SignalR را به صورت یک بسته NuGet ارائه داده‌اند که از طریق آدرس و فرمان ذیل قابل دریافت است:
 PM> Install-Package Microsoft.AspNet.SignalR.Sample
قبل از اینکه این مثال را دریافت کنید نیاز است ابتدا یک برنامه ASP.NET جدید را آغاز نمائید (تفاوتی نمی‌کند که MVC باشد یا Web forms). سپس دستور فوق را فراخوانی کنید.

پس از دریافت مثال، یکبار پروژه را کامپایل کرده و سپس بر روی فایل StockTicker.html آن کلیک راست نموده و گزینه مشاهده در مرورگر را انتخاب کنید. همچنین برای اینکه این مثال را بهتر مشاهده کنید، بهتر است دو وهله از مرورگر را باز کرده و آدرس باز شده را در آن بررسی کنید تا اعمال تغییرات همزمان به کلاینت‌های متفاوت را بهتر بتوان بررسی و مشاهده کرد.

نظرات مطالب
امکان ساخت برنامه‌های دسکتاپ چندسکویی Blazor در دات نت 6
- این مطلب برای شروع کار مناسب نیست و یک مطلب تکمیلی است. برای آشنایی با معماری برنامه‌های Blazor از اینجا شروع کنید؛ از این جهت که Blazor Server خودش یک پروژه‌ی وب کامل هست و نیازی به پروژه‌ی وب مجزا ندارد. نحوه‌ی دسترسی به اطلاعات آن با Blazor WASM متفاوت است و خیلی موارد دیگر (که نیازی به تکرار آن‌ها در اینجا نیست). نمونه‌اش منوی fetch data در تصویر برنامه‌ی دسکتاپ هست که اطلاعات خودش را از وب سرور اجرا شده‌ی به همراه برنامه دریافت می‌کند (این اتصال هم از نوع Web socket مخصوص SignalR هست که در سری Blazor سایت در مورد آن بحث شده). همچنین این را هم مدنظر داشته باشید که زمانیکه بحث برنامه‌ی «دسکتاپ» هست، یعنی برنامه‌های «کوچک» و «تک کاربره» که توضیحات این مطلب برای پوشش آن‌ها کافی است.
- اگر هم Web API راه دور دارید، فقط کافی است سرویس HttpClient را ثبت کنید (در همان سازنده‌ی فرم برنامه‌ی وین‌فرمز مثال فوق):
serviceCollection.AddScoped<HttpClient>();
بعد هم در صفحات razor کتابخانه‌ی مثال می‌توان به نحو متداولی با این سرویس کار کرد (و نکات کار با این سرویس در سری Blazor سایت بررسی شده‌اند):
@inject HttpClient Http
نظرات مطالب
سفارشی سازی صفحه‌ی اول برنامه‌های Angular CLI توسط ASP.NET Core
در پروژه سفارشی سازی DNTIdentity  اومدید برای پیاده سازی دسترسی‌ها و نمایش منو‌ها به کاربر از تگ هلپر  SecurityTrimming   استفاده کردین  توی همون پروژه اگه بخوایم همچین چیزی رو با انگولار پیاده سازی کنیم پیشنهادتون چیه ؟ استفاده کردن تگ هلپر در انگولار مثل این پروژه https://github.com/RobertDyball/A2SPA   ( تو readme  لینکاشو نگاه کنید) یا روش دیگه ای سراغ دارین؟
توی همین پروژه DNTIdentity توی پارشیال ویو _UserMenu.cshtml   با razor اومدید  @inject IUsersPhotoService PhotoService
@{
    var displayName = User.Identity.GetUserDisplayName();
    var photoUrl = PhotoService.GetCurrentUserPhotoUrl();
}
 displayName کاربری که لاگین کرده رو گرفتید برای همچین کاری تو angular چیکار باید کرد؟ ممنون
مطالب
آشنایی با WPF قسمت اول : ساختار سلسله مراتبی


عناصر رابط کاربری WPF با یکدیگر یک رابطه‌ی سلسله مراتبی دارند. به این رابطه، درخت منطقی یا Logical Tree می‌گویند که به توصیف ارتباط اجزای رابط کاربری می‌پردازد. نوع دیگری از درخت نیز وجود دارد که به آن درخت بصری یا Visual Tree می‌گویند. این درخت شامل عناصری است که باعث نمایش کنترل پدر می‌شوند و کنترل پدر بدون آن‌ها هیچ ظاهر نمایشی ندارد. به عنوان مثال شما یک دکمه را در نظر بگیرید. این دکمه شامل عناصری چون Border,Block Text,Content Presenter می‌شود تا بتواند به عنوان یک دکمه نمایش یابد و بدون وجود این عناصر، کنترل دکمه هیچ ظاهری ندارد و در واقع با رندر شدن کنترل‌های فرزندان، دکمه معنا پیدا می‌کند. به تصویر بالا دقت کنید که به خوبی مرز بین درخت منطقی و درخت بصری را نمایش می‌دهد. شکل سلسله مراتبی بالا از طریق کد زیر به دست آمده است:
 
<Window>
    <Grid>
        <Label Content="Label" />
        <Button Content="Button" />
    </Grid>
</Window>
درخت بصری می‌تواند به ما کمک کند تا بتوانیم بر روی عناصر تشکیل دهنده، یک کنترل قدرت عمل داشته باشیم و آن‌ها را مورد تغییر قرار دهیم.


Dependency Properties

خاصیت‌های وابستگی همان خاصیت‌ها یا property هایی هستند در ویندوزفرم با آن‌ها سر و کله می‌زدید ولی در اینجا تفاوت‌هایی با پراپرتی‌های قبلی وجود دارد که باعث ایجاد مزایای زیادی شده است.

اول اینکه
بر خلاف پراپرتی‌های ویندوز فرم که در خود فیلدهای تعیین شده همان کنترل ذخیره می‌شدند، در این روش کلید (نام پراپرتی) و مقدار آن داخل یک شیء دیکشنری قرار می‌گیرند که از شیء DependencyObject ارث بری شده است و این شیء والد یک متد با نام GetValue برای دریافت مقادیر دارد. مزیت این روش این است که بیخود و بی‌جهت مانند روش قبلی، ما فیلدهایی را تعریف نمی‌کنیم که شاید به نصف بیشتر آن‌ها، حتی نیازی نداریم. در این حالت تنها فیلدهایی از حافظه را دریافت و ذخیره می‌کنیم که واقعا به آن‌ها نیاز داریم. فیلدها یا مقادیر پیش فرض موقع ایجاد شیء در آن ذخیره می‌شوند.

دومین مزیت این روش خاصیت ارث بری مقادیر از عناصر بالاتر درخت منطقی است. موقعی که از طرف شما برای فرزندان این عنصر مقداری تعیین نشده باشد، سیستم به  سمت گره‌ها یا عناصر بالا یا والد حرکت می‌کند و اولین عنصری را که مقدارش تنظیم شده باشد، برای فرزندان در نظر می‌گیرد. به این استراتژی یافتن یک مقدار، استراتژی Resolution می‌گویند.

سومین مزیت آن وجود یک سیستم اعلان یا گزارش آنی است. در صورتی که شما یک تابع callback را برای یک پراپرتی ست نمایید، با تغییر این پراپرتی تابع معرفی شده صدا زده خواهد شد.

Value Resolution Strategy
همانطور که در بالا اشاره کردیم دریافت مقادیر یک کنترل از طریق یک استراتژی به اسم Resolution انجام می‌شود که طبق تصویر زیر از بالا به پایین بررسی می‌شود. در هر کدام از مراحل زیر اگر مقداری یافت شد، همان مقدار را انتخاب می‌کند. از متد SetValue هم برای درج مقدار استفاده می‌شود. برای مثال در مرحله‌ی سوم بررسی می‌شود که آیا کاربر برای کنترل مورد نظر مقداری را تنظیم کرده است یا خیر؛ اگر آری، پس از آن استفاده می‌کند و اگر پاسخ خیر بود، بررسی می‌کند آیا style برای آن موجود است که مقداری برایش تنظیم شده باشد یا خیر و الی آخر...

جادوی پشت صحنه

مقادیر پراپرتی‌ها در کلاسی استاتیک به اسم Dependency Property ذخیره می‌شوند که این ذخیره در حالت نام و مقدار است و مقدار آن شامل callback و مقدار پیش فرض است. شکل زیر نتیجه‌ی شکل دقیق‌تری را نسبت به قبلی در هنگام پیمایش درخت منطقی به سمت بالا، نشان می‌دهد.

نحوه‌ی تعریف یک خاصیت وابسته که باید به صورت ایستا تعریف شود به صورت زیر است و برای دریافت و درج مقدار جدید از یک پراپرتی معمولی کمک می‌گیریم:

// Dependency Property
public static readonly DependencyProperty CurrentTimeProperty = 
     DependencyProperty.Register( "CurrentTime", typeof(DateTime),
     typeof(MyClockControl), new FrameworkPropertyMetadata(DateTime.Now));
 
// .NET Property wrapper
public DateTime CurrentTime
{
    get { return (DateTime)GetValue(CurrentTimeProperty); }
    set { SetValue(CurrentTimeProperty, value); }
}
یک قانون در WPF وجود دارد و آن اینست که نام خاصیت‌های وابسته را با کلمه Property به پایان ببرید مثل CurrentTimeProperty.
در مورد خاصیت‌های وابسته و کدنویسی آن ها در مطالب آینده بیشتر بحث خواهیم کرد.

نظرات مطالب
کتابخانه‌ی انواع و اقسام مدل‌های داده‌ای
سلام
بله. این سایت واقعا مفید است. خیلی ایده می‌شود از آن استخراج کرد.
و یک سری سایت هستند که به صورت تخصصی کار UI انجام می‌دن. برای مثال:
http://www.uxbooth.com/view/blog/
که چندی قبل در مورد آینده رابط‌های کاربری یک سری مطلب جالب منتشر کرده بود:
http://www.uxbooth.com/blog/the-future-of-interface-design/
نظرات مطالب
اجرای وظایف زمان بندی شده با Quartz.NET - قسمت دوم

- تولید درخواست به یک سایت کار سختی نیست. از این سرویس‌هایی که مدام سایت رو ping می‌کنند زیاد هست. مثل سرویس‌های فید خوان. مثل سایت‌هایی که بررسی می‌کنند سایت شما آپ است یا داون.

- نه الزاما. سرویس task scheduler ویندوز همیشه در حال اجرا است؛ دقیق و منظم. این سرویس می‌تونه خیلی راحت یک فایل exe معمولی یا حتی یک فایل bat رو در زمان‌های مشخصی اجرا کنه. برای کارهای مدیریت سیستم زیاد ازش استفاده می‌شه.

مطالب
سفارشی سازی ASP.NET Core Identity - قسمت اول - موجودیت‌های پایه و DbContext برنامه
با به پایان رسیدن مرحله‌ی توسعه‌ی ASP.NET Identity 2.x مخصوص نگارش‌های ASP.NETایی که از Full .NET Framework استفاده می‌کنند، نگارش جدید آن صرفا بر پایه‌ی ASP.NET Core تهیه شده‌است و در طی یک سری، نحوه‌ی سفارشی سازی تقریبا تمام اجزای آن‌را بررسی خواهیم کرد. جهت سهولت پیگیری این سری، پروژه‌ی کامل سفارشی سازی شده‌ی ASP.NET Core Identity را از مخزن کد DNT Identity می‌توانید دریافت کنید.


پیشنیازهای اجرای پروژه‌ی DNT Identity

 - ابتدا نیاز است حداقل ASP.NET Core Identity 1.1 را نصب کرده باشید.
 - همچنین بانک اطلاعاتی پایه‌ی آن که به صورت خودکار در اولین بار اجرای برنامه تشکیل می‌شود، مبتنی بر LocalDB است. بنابراین اگر قصد تغییری را در تنظیمات Context آن ندارید، بهتر است LocalDB را نیز بر روی سیستم نصب کنید. هرچند با تغییر تنظیم ActiveDatabase به SqlServer در فایل appsettings.json، برنامه به صورت خودکار از نگارش کامل SqlServer استفاده خواهد کرد. رشته‌ی اتصالی آن نیز در مدخل ConnectionStrings فایل appsettings.json ذکر شده‌است و قابل تغییر است. برای شروع به کار، نیازی به اجرای مراحل Migrations را نیز ندارید و همینقدر که برنامه را اجرا کنید، بانک اطلاعاتی آن نیز تشکیل خواهد شد.
 - کاربر پیش فرض Admin سیستم و کلمه‌ی عبور آن از مدخل AdminUserSeed فایل appsettings.json خوانده می‌شوند.
 - تنظیمات ایمیل پیش فرض برنامه به استفاده‌ی از PickupFolder در مدخل Smtp فایل appsettings.json تنظیم شده‌است. بنابراین تمام ایمیل‌های برنامه را جهت آزمایش محلی می‌توانید در مسیر PickupFolder آن یا همان c:\smtppickup مشاهده کنید. محتوای این ایمیل‌ها را نیز توسط مرورگر (drag&drop بر روی یک tab جدید) و یا برنامه‌ی Outlook می‌توان مشاهده کرد.


سفارشی سازی کلید اصلی موجودیت‌های ASP.NET Core Identity

ASP.NET Core Identity به همراه دو سری موجودیت است. یک سری ساده‌ی آن که از یک string به عنوان نوع کلید اصلی استفاده می‌کنند و سری دوم، حالت جنریک که در آن می‌توان نوع کلید اصلی را به صورت صریحی قید کرد و تغییر داد. در اینجا نیز قصد داریم از حالت جنریک استفاده کرده و نوع کلید اصلی جداول را تغییر دهیم. تمام این موجودیت‌های تغییر یافته را در پوشه‌ی src\ASPNETCoreIdentitySample.Entities\Identity نیز می‌توانید مشاهده کنید و شامل موارد ذیل هستند:

جدول نقش‌های سیستم
    public class Role : IdentityRole<int, UserRole, RoleClaim>, IAuditableEntity
    {
        public Role()
        {
        }

        public Role(string name)
            : this()
        {
            Name = name;
        }

        public Role(string name, string description)
            : this(name)
        {
            Description = description;
        }

        public string Description { get; set; }
    }
کار با ارث بری از نگارش جنریک کلاس IdentityRole شروع می‌شود. این کلاس پایه، حاوی تعاریف اصلی فیلدهای جدول نقش‌های سیستم است که اولین آرگومان جنریک آن، نوع کلید اصلی جدول مرتبط را نیز مشخص می‌کند و در اینجا به int تنظیم شده‌است. همچنین یک اینترفیس جدید IAuditableEntity را نیز در انتهای این تعریف‌ها مشاهده می‌کنید. در مورد این اینترفیس و Shadow properties متناظر با آن، در ادامه‌ی بحث با سفارشی سازی DbContext برنامه بیشتر توضیح داده خواهد شد.


در اولین بار اجرای برنامه، نقش Admin در این جدول ثبت خواهد شد.

جدول کاربران منتسب به نقش‌ها
    public class UserRole : IdentityUserRole<int>, IAuditableEntity
    {
        public virtual User User { get; set; }

        public virtual Role Role { get; set; }
    }
کلاس پایه‌ی جدول کاربران منتسب به نقش‌ها، کلاس جنریک IdentityUserRole است که در اینجا با تغییر آرگومان جنریک آن به int، نوع فیلدهای UserId و RoleId آن به int تنظیم می‌شوند. در کلاس سفارشی سازی شده‌ی فوق، دو خاصیت اضافه‌تر User و Role نیز را مشاهده می‌کنید. مزیت تعریف آن‌ها، دسترسی ساده‌تر به اطلاعات کاربران و نقش‌ها توسط EF Core است.


در اولین بار اجرای برنامه، کاربر شماره 1 یا همان Admin به نقش شماره 1 یا همان Admin، انتساب داده می‌شود.


جدول جدید  IdentityRoleClaim سیستم
public class RoleClaim : IdentityRoleClaim<int>, IAuditableEntity
{
   public virtual Role Role { get; set; }
}
در ASP.NET Core Identity، جدول جدیدی به نام RoleClaim نیز اضافه شده‌است. در این سری از آن برای پیاده سازی سطوح دسترسی پویای به صفحات استفاده خواهیم کرد. ابتدا یک سری نقش ثابت در جدول Roles ثبت خواهند شد. سپس تعدادی کاربر به هر نقش نسبت داده می‌شوند. اکنون می‌توان به هر نقش نیز تعدادی Claim را انتساب داد. برای مثال یک Claim سفارشی که شامل ID سفارشی area:controller:action باشد. به این ترتیب و با بررسی سفارشی آن می‌توان سطوح دسترسی پویا را نیز پیاده سازی کرد و مزیت آن این است که تمام این Claims به صورت خودکار به کوکی شخص نیز اضافه شده و دسترسی به اطلاعات آن بسیار سریع است و نیازی به مراجعه‌ی به بانک اطلاعاتی را ندارد.

جدول UserClaim سیستم
public class UserClaim : IdentityUserClaim<int>, IAuditableEntity
{
   public virtual User User { get; set; }
}
می‌توان به هر کاربر یک سری Claim مخصوص را نیز انتساب داد. برای مثال مسیر عکس ذخیره شده‌ی او در سرور، چه موردی است و این اطلاعات به صورت خودکار به کوکی او نیز توسط ASP.NET Core Identity اضافه می‌شوند. البته ما در این سری روش دیگری را برای سفارشی سازی Claims عمومی کاربران بکار خواهیم گرفت (با سفارشی سازی کلاس ApplicationClaimsPrincipalFactory آن).

جداول توکن و لاگین‌های کاربران
public class UserToken : IdentityUserToken<int>, IAuditableEntity
{
   public virtual User User { get; set; }
}

public class UserLogin : IdentityUserLogin<int>, IAuditableEntity
{
   public virtual User User { get; set; }
}
دراینجا نیز نحوه‌ی سفارشی سازی و تغییر جداول لاگین‌های کاربران و توکن‌های مرتبط با آن‌ها را مشاهده می‌کنید. این جداول بیشتر جهت دسترسی به حالت‌هایی مانند لاگین با حساب کاربری جی‌میل مورد استفاده قرار می‌گیرند و کاربرد پیش فرضی ندارند (اگر از تامین کننده‌های لاگین خارجی نمی‌خواهید استفاده کنید).

جدول کاربران سیستم
    public class User : IdentityUser<int, UserClaim, UserRole, UserLogin>, IAuditableEntity
    {
        public User()
        {
            UserUsedPasswords = new HashSet<UserUsedPassword>();
            UserTokens = new HashSet<UserToken>();
        }

        [StringLength(450)]
        public string FirstName { get; set; }

        [StringLength(450)]
        public string LastName { get; set; }

        [NotMapped]
        public string DisplayName
        {
            get
            {
                var displayName = $"{FirstName} {LastName}";
                return string.IsNullOrWhiteSpace(displayName) ? UserName : displayName;
            }
        }

        [StringLength(450)]
        public string PhotoFileName { get; set; }

        public DateTimeOffset? BirthDate { get; set; }

        public DateTimeOffset? CreatedDateTime { get; set; }

        public DateTimeOffset? LastVisitDateTime { get; set; }

        public bool IsEmailPublic { get; set; }

        public string Location { set; get; }

        public bool IsActive { get; set; } = true;

        public virtual ICollection<UserUsedPassword> UserUsedPasswords { get; set; }

        public virtual ICollection<UserToken> UserTokens { get; set; }
    }

    public class UserUsedPassword : IAuditableEntity
    {
        public int Id { get; set; }

        public string HashedPassword { get; set; }

        public virtual User User { get; set; }
        public int UserId { get; set; }
    }
در اینجا علاوه بر نحوه‌ی تغییر نوع کلید اصلی جدول کاربران سیستم، نحوه‌ی افزودن خواص اضافه‌تری مانند نام، تاریخ تولد، مکان، تصویر و غیره را نیز مشاهده می‌کنید. به علاوه جدولی نیز جهت ثبت سابقه‌ی کلمات عبور هش شده‌ی کاربران نیز تدارک دیده شده‌است تا کاربران نتوانند از 5 کلمه‌ی عبور اخیر خود (تنظیم NotAllowedPreviouslyUsedPasswords در فایل appsettings.json) استفاده کنند.
فیلد IsActive نیز از این جهت اضافه شده‌است تا بجای حذف فیزیکی یک کاربر، بتوان اکانت او را غیرفعال کرد.


تعریف Shadow properties ثبت تغییرات رکوردها

در #C ارث‌بری چندگانه‌ی کلاس‌ها ممنوع است؛ مگر اینکه از اینترفیس‌ها استفاده شود. برای مثال IdentityUser یک کلاس است و در اینجا دیگر نمی‌توان کلاس دومی را به نام BaseEntity جهت اعمال خواص اضافه‌تری اعمال کرد. به همین جهت است که اعمال اینترفیس خالی IAuditableEntity را در اینجا مشاهده می‌کنید. این اینترفیس کار علامت‌گذاری کلاس‌هایی را انجام می‌دهد که قصد داریم به آن‌ها به صورت خودکار، خواصی مانند تاریخ ثبت رکورد، تاریخ ویرایش آن و غیره را اعمال کنیم.
در Context برنامه، به اطلاعات src\ASPNETCoreIdentitySample.Entities\AuditableEntity مراجعه شده و متد AddAuditableShadowProperties بر روی تمام کلاس‌هایی از نوع IAuditableEntity اعمال می‌شود. این متد خواص مدنظر ما را مانند ModifiedDateTime به صورت Shadow properties به موجودیت‌های علامت‌گذاری شده اضافه می‌کند.
همچنین متد SetAuditableEntityPropertyValues، کار مقدار دهی خودکار این خواص را انجام خواهد داد. بنابراین دیگر نیازی نیست در برنامه برای مثال IP شخص ثبت کننده یا ویرایش کننده را به صورت دستی مقدار دهی کرد. هم تعریف و هم مقدار دهی آن توسط Change tracker سیستم به صورت خودکار انجام خواهند شد.


تاثیر افزودن Shadow properties را بر روی کلاس نقش‌های سیستم، در تصویر فوق ملاحظه می‌کنید. خواصی که به صورت معمول در کلاس‌های برنامه ظاهر نمی‌شوند و صرفا هدف بازبینی سیستم را برآورده می‌کنند و مدیریت آن‌ها نیز در اینجا کاملا خودکار است.


سفارشی سازی DbContext برنامه

نحوه‌ی سفارشی سازی DbContext برنامه را در پوشه‌ی src\ASPNETCoreIdentitySample.DataLayer\Context و src\ASPNETCoreIdentitySample.DataLayer\Mappings ملاحظه می‌کنید. پوشه‌ی Context حاوی کلاس ApplicationDbContextBase است که تمام سفارشی سازی‌های لازم بر روی آن انجام شده‌است؛ شامل:
 - تغییر نوع کلید اصلی موجودیت‌ها به همراه معرفی موجودیت‌های تغییر یافته:
 public abstract class ApplicationDbContextBase :
  IdentityDbContext<User, Role, int, UserClaim, UserRole, UserLogin, RoleClaim, UserToken>,
  IUnitOfWork
ما در ابتدای بحث، برای مثال کلاس Role را سفارشی سازی کردیم. اما برنامه از وجود آن بی‌اطلاع است. با ارث بری از IdentityDbContext و ذکر این کلاس‌های سفارشی به همراه نوع int کلید اصلی مورد استفاده، کار معرفی موجودیت‌های سفارشی سازی شده انجام می‌شود.

 - اعمال متد BeforeSaveTriggers به تمام نگارش‌های مختلف SaveChanges
protected void BeforeSaveTriggers()
{
  ValidateEntities();
  SetShadowProperties();
  this.ApplyCorrectYeKe();
}
در اینجا پیش از ذخیره‌ی اطلاعات، ابتدا موجودیت‌ها اعتبارسنجی می‌شوند. سپس مقادیر Shadow properties تنظیم شده و دست آخر، ی و ک فارسی نیز به اطلاعات ثبت شده، جهت یک دست سازی اطلاعات سیستم، اعمال می‌شوند.

- انتخاب نوع بانک اطلاعاتی مورد استفاده در متد OnConfiguring
در اینجا است که خاصیت ActiveDatabase تنظیم شده‌ی در فایل appsettings.json خوانده شده و اعمال می‌شوند. تعریف متد GetDbConnectionString را در کلاس SiteSettingsExtesnsions مشاهده می‌کنید. کار آن استفاده‌ی از بانک اطلاعاتی درون حافظه‌ای، جهت انجام آزمون‌های واحد و یا استفاده‌ی از LocalDb و یا نگارش کامل SQL Server می‌باشد. اگر علاقمند بودید تا بانک اطلاعاتی دیگری (مثلا SQLite) را نیز اضافه کنید، ابتدا enum ایی به نام ActiveDatabase را تغییر داده و سپس متد GetDbConnectionString و متد OnConfiguring را جهت درج اطلاعات این بانک اطلاعاتی جدید، اصلاح کنید.

پس از تعریف این DbContext پایه‌ی سفارشی سازی شده، کلاس جدید ApplicationDbContext را مشاهده می‌کنید. این کلاس ‍Context ایی است که در برنامه از آن استفاده می‌شود و از کلاس پایه ApplicationDbContextBase مشتق شده‌است:
 public class ApplicationDbContext : ApplicationDbContextBase
تعاریف موجودیت‌های جدید خود را به این کلاس اضافه کنید.
تنظیمات mapping آن‌ها نیز به متد OnModelCreating این کلاس اضافه خواهند شد. فقط نحوه‌ی استفاده‌ی از آن را به‌خاطر داشته باشید:
        protected override void OnModelCreating(ModelBuilder builder)
        {
            // it should be placed here, otherwise it will rewrite the following settings!
            base.OnModelCreating(builder);

            // Adds all of the ASP.NET Core Identity related mappings at once.
            builder.AddCustomIdentityMappings(SiteSettings.Value);

            // Custom application mappings


            // This should be placed here, at the end.
            builder.AddAuditableShadowProperties();
        }
ابتدا باید base.OnModelCreating را ذکر کنید. در غیراینصورت تمام سفارشی سازی‌های شما بازنویسی می‌شوند.
سپس متد AddCustomIdentityMappings ذکر شده‌است. این متد اطلاعات src\ASPNETCoreIdentitySample.DataLayer\Mappings را به صورت خودکار و یکجا اضافه می‌کند که در آن برای مثال نام جداول پیش فرض Identity سفارشی سازی شده‌اند.


در آخر باید AddAuditableShadowProperties فراخوانی شود تا خواص سایه‌ای که پیشتر در مورد آن‌ها بحث شد، به سیستم به صورت خودکار اضافه شوند.
تمام نگاشت‌های سفارشی شما باید در این میان و در قسمت «Custom application mappings» درج شوند.

در قسمت بعدی، نحوه‌ی سفارشی سازی سرویس‌های پایه‌ی Identity را بررسی خواهیم کرد. بدون این سفارشی سازی و اطلاعات رسانی به سرویس‌های پایه که از چه موجودیت‌های جدید سفارشی سازی شده‌ایی در حال استفاده هستیم، کار Migrations انجام نخواهد شد.


کدهای کامل این سری را در مخزن کد DNT Identity می‌توانید ملاحظه کنید.