پاسخ به بازخورد‌های پروژه‌ها
تگ a در گزارش
- بهترین مکان برای طرح سؤالات مرتبط با خود کتابخانه iTextSharp سایت stack overflow و انتخاب tag ایی به همین نام در آنجا است. بر اساس برچسب iTextSharp خود نویسندگان این کتابخانه حضور دارند و به شما پاسخ خواهند داد.
- سایت جاری امکان ارسال کد به همراه syntax highlighting خودکار آن‌را دارد و نیازی به ارسال تصویر نیست. فقط بر روی دکمه کد، در نوار ابزار ادیتور آن کلیک کنید.
- امکانات HTMLWorker محدود است. به همین جهت آن‌را بازنشسته کرده‌اند (دیگر پشتیبانی نمی‌شود) و با نمونه جدیدتری به نام XML Worker آن‌را جایگزین کرده‌اند که امکانات پردازش CSS ایی بهتری دارد.
مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 20 - بررسی تغییرات فیلترها
پیشنیازها

- فیلترها در 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)
        {
            // انجام کاری پس از اجرای اکشن متد
        }
    }
}
در اینجا اینترفیس IAsyncActionFilter نیز معرفی شده‌است که توسط آن می‌توان فراخوانی‌های غیرهمزمان و async را نیز مدیریت کرد:
namespace FiltersSample.Filters
{
    public class SampleAsyncActionFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(
            ActionExecutingContext context,
            ActionExecutionDelegate next)
        {
            // انجام کاری پیش از اجرای اکشن متد
            await next();
            // انجام کاری پس از اجرای اکشن متد
        }
    }
}
به کامنت‌های نوشته شده‌ی در بدنه‌ی متد OnActionExecutionAsync دقت کنید. در اینجا کدهای پیش از await next معادل OnActionExecuting و کدهای پس از await next معادل OnActionExecuted حالت همزمان و یا همان حالت متداول هستند. بنابراین جایی که اکشن متد اجرا می‌شود، همان 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
    });
}
در اینجا دو روش معرفی فیلترهای سراسری را در متد ConfigureServices کلاس آغازین برنامه مشاهده می‌کنید:
الف) اگر توسط ارائه‌ی 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();
}
ویژگی جدید ServiceFilter، نوع کلاس فیلتر را دریافت می‌کند و سپس هر زمانیکه نیاز به اجرای این فیلتر خاص بود، کار وهله سازی‌های وابستگی‌های آن، در پشت صحنه توسط IoC Container توکار ASP.NET Core انجام خواهد شد.
همچنین باید دقت داشت که در این حالت ثبت کلاس فیلتر در متد 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}");
}
فیلتر و ویژگی TypeFilter بسیار شبیه است به عملکرد ServiceFilter، با این تفاوت که:
- نیازی نیست تا وابستگی آن‌را در متد 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));
در اینجا از typeof استفاده شده‌است تا کار تزریق وابستگی‌های این فیلتر به صورت خودکار انجام شود.
در ادامه با این فرض که پیشتر تنظیمات ثبت وقایع صورت گرفته‌است:
public void Configure(ILoggerFactory loggerFactory)
{
   loggerFactory.AddDebug(minLevel: LogLevel.Debug);
اکنون اگر یک چنین اکشن متدی فراخوانی شود:
public IActionResult GetData()
{
  throw new Exception("throwing an exception!");
}
در پنجره‌ی دیباگ ویژوال استودیو، این استثناء قابل مشاهده خواهد بود:

مطالب
Roslyn #6
معرفی Analyzers

پیشنیاز این بحث نصب مواردی است که در مطلب «شروع به کار با Roslyn » در قسمت دوم عنوان شدند:
الف) نصب SDK ویژوال استودیوی 2015
ب) نصب قالب‌های ایجاد پروژه‌های مخصوص Roslyn

البته این قالب‌ها چیزی بیشتر از ایجاد یک پروژه‌ی کلاس Library جدید و افزودن ارجاعاتی به بسته‌ی نیوگت Microsoft.CodeAnalysis، نیستند. اما درکل زمان ایجاد و تنظیم این نوع پروژه‌ها را خیلی کاهش می‌دهند و همچنین یک پروژه‌ی تست را ایجاد کرده و تولید بسته‌ی نیوگت و فایل VSIX را نیز بسیار ساده می‌کنند.


هدف از تولید Analyzers

بسیاری از مجموعه‌ها و شرکت‌ها، یک سری قوانین و اصول خاصی را برای کدنویسی وضع می‌کنند تا به کدهایی با قابلیت خوانایی بهتر و نگهداری بیشتر برسند. با استفاده از Roslyn و آنالیز کننده‌های آن می‌توان این قوانین را پیاده سازی کرد و خطاها و اخطارهایی را به برنامه نویس‌ها جهت رفع اشکالات موجود، نمایش داده و گوشزد کرد. بنابراین هدف از آنالیز کننده‌های Roslyn، سهولت تولید ابزارهایی است که بتوانند برنامه نویس‌ها را ملزم به رعایت استانداردهای کدنویسی کنند.
همچنین معلم‌ها نیز می‌توانند از این امکانات جهت ارائه‌ی نکات ویژه‌‌ای به تازه‌کاران کمک بگیرند. برای مثال اگر این قسمت از کد اینگونه باشد، بهتر است؛ مثلا بهتر است فیلدهای سطح کلاس، خصوصی تعریف شوند و امکان دسترسی به آن‌ها صرفا از طریق متدهایی که قرار است با آن‌ها کار کنند صورت گیرد.
این آنالیز کنند‌ها به صورت پویا در حین تایپ کدها در ویژوال استودیو فعال می‌شوند و یا حتی به صورت خودکار در طی پروسه‌ی Build پروژه نیز می‌توانند ظاهر شده و خطاها و اخطارهایی را گزارش کنند.


بررسی مثال معتبری که می‌تواند بهتر باشد

در اینجا یک کلاس نمونه را مشاهده می‌کنید که در آن فیلدهای کلاس به صورت public تعریف شده‌اند.
    public class Student
    {
        public string FirstName;
        public string LastName;
        public int TotalPointsEarned;

        public void TakeExam(int pointsForExam)
        {
            TotalPointsEarned += pointsForExam;
        }

        public void ExtraCredit(int extraPoints)
        {
            TotalPointsEarned += extraPoints;
        }


        public int PointsEarned { get { return TotalPointsEarned; } }
    }
هرچند این کلاس از دید کامپایلر بدون مشکل است و کامپایل می‌شود، اما از لحاظ اصول کپسوله سازی اطلاعات دارای مشکل است و نباید جمع امتیازات کسب شده‌ی یک دانش آموز به صورت مستقیم و بدون مراجعه‌ی به متدهای معرفی شده، از طریق فیلدهای عمومی آن قابل تغییر باشد.
بنابراین در ادامه هدف ما این است که یک Roslyn Analyzer جدید را طراحی کنیم تا از طریق آن هشدارهایی را جهت تبدیل فیلدهای عمومی به خصوصی، به برنامه نویس نمایش دهیم.


با اجرای افزونه‌ی View->Other windows->Syntax visualizer، تصویر فوق نمایان خواهد شد. بنابراین در اینجا نیاز است FieldDeclaration‌ها را یافته و سپس tokenهای آن‌ها را بررسی کنیم و مشخص کنیم که آیا نوع یا Kind آن‌ها public است (PublicKeyword) یا خیر؟ اگر بلی، آن مورد را به صورت یک Diagnostic جدید گزارش می‌دهیم.


ایجاد اولین Roslyn Analyzer

پس از نصب پیشنیازهای بحث، به شاخه‌ی قالب‌های extensibility در ویژوال استودیو مراجعه کرده و یک پروژه‌ی جدید از نوع Analyzer with code fix را آغاز کنید.


قالب Stand-alone code analysis tool آن دقیقا همان برنامه‌های کنسول بحث شده‌ی در قسمت‌های قبل است که تنها ارجاعی را به بسته‌ی نیوگت Microsoft.CodeAnalysis به صورت خودکار دارد.
قالب پروژه‌ی Analyzer with code fix علاوه بر ایجاد پروژه‌های Test و VSIX جهت بسته بندی آنالایزر تولید شده، دارای دو فایل DiagnosticAnalyzer.cs و CodeFixProvider.cs پیش فرض نیز هست. این دو فایل قالب‌هایی را جهت شروع به کار تهیه‌ی آنالیز کننده‌های مبتنی بر Roslyn ارائه می‌دهند. کار DiagnosticAnalyzer آنالیز کد و ارائه‌ی خطاهایی جهت نمایش به ویژوال استودیو است و CodeFixProvider این امکان را مهیا می‌کند که این خطای جدید عنوان شده‌ی توسط آنالایزر، چگونه باید برطرف شود و راه‌کار بازنویسی Syntax tree آن‌را ارائه می‌دهد.
همین پروژه‌ی پیش فرض ایجاد شده نیز قابل اجرا است. اگر بر روی F5 کلیک کنید، یک کپی جدید و محصور شده‌ی ویژوال استودیو را باز می‌کند که در آن افزونه‌ی در حال تولید به صورت پیش فرض و محدود نصب شده‌است. اکنون اگر پروژه‌ی جدیدی را جهت آزمایش، در این وهله‌ی محصور شده‌ی ویژوال استودیو باز کنیم، قابلیت اجرای خودکار آنالایزر در حال توسعه را فراهم می‌کند. به این ترتیب کار تست و دیباگ آنالایزرها با سهولت بیشتری قابل انجام است.
این پروژه‌ی پیش فرض، کار تبدیل نام فضاهای نام را به upper case، به صورت خودکار انجام می‌دهد (که البته بی‌معنا است و صرفا جهت نمایش و ارائه‌ی قالب‌های شروع به کار مفید است).
نکته‌ی دیگر آن، تعریف تمام رشته‌های مورد نیاز آنالایزر در یک فایل resource به نام Resources.resx است که در جهت بومی سازی پیام‌های خطای آن می‌تواند بسیار مفید باشد.

در ادامه کدهای فایل DiagnosticAnalyzer.cs را به صورت ذیل تغییر دهید:
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
 
namespace CodingStandards
{
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public class CodingStandardsAnalyzer : DiagnosticAnalyzer
    {
        public const string DiagnosticId = "CodingStandards";

        // You can change these strings in the Resources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat.
        internal static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AnalyzerTitle), Resources.ResourceManager, typeof(Resources));
        internal static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
        internal static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AnalyzerDescription), Resources.ResourceManager, typeof(Resources));
        internal const string Category = "Naming";

        internal static DiagnosticDescriptor Rule = 
            new DiagnosticDescriptor(
                DiagnosticId, 
                Title, 
                MessageFormat, 
                Category, 
                DiagnosticSeverity.Error, 
                isEnabledByDefault: true, 
                description: Description);
 
        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
        {
            get { return ImmutableArray.Create(Rule); }
        }

        public override void Initialize(AnalysisContext context)
        {
            // TODO: Consider registering other actions that act on syntax instead of or in addition to symbols
            context.RegisterSyntaxNodeAction(analyzeFieldDeclaration, SyntaxKind.FieldDeclaration);
        }

        static void analyzeFieldDeclaration(SyntaxNodeAnalysisContext context)
        {
            var fieldDeclaration = context.Node as FieldDeclarationSyntax;
            if (fieldDeclaration == null) return;
            var accessToken = fieldDeclaration
                                .ChildTokens()
                                .SingleOrDefault(token => token.Kind() == SyntaxKind.PublicKeyword);

            // Note: Not finding protected or internal
            if (accessToken.Kind() != SyntaxKind.None)
            {
                // Find the name of the field:
                var name = fieldDeclaration.DescendantTokens()
                              .SingleOrDefault(token => token.IsKind(SyntaxKind.IdentifierToken)).Value;
                var diagnostic = Diagnostic.Create(Rule, fieldDeclaration.GetLocation(), name, accessToken.Value);
                context.ReportDiagnostic(diagnostic);
            }
        }
    }
}
توضیحات:

اولین کاری که در این کلاس انجام شده، خواندن سه رشته‌ی AnalyzerDescription (توضیحی در مورد آنالایزر)، AnalyzerMessageFormat (پیامی که به کاربر نمایش داده می‌شود) و AnalyzerTitle (عنوان پیام) از فایل Resources.resx است. این فایل را گشوده و محتوای آن‌را مطابق تنظیمات ذیل تغییر دهید:


سپس کار به متد Initialize می‌رسد. در اینجا برخلاف مثال‌های قسمت‌های قبل، context مورد نیاز، توسط پارامترهای override شده‌ی کلاس پایه DiagnosticAnalyzer فراهم می‌شوند. برای مثال در متد Initialize، این فرصت را خواهیم داشت تا به ویژوال استودیو اعلام کنیم، قصد آنالیز فیلدها یا FieldDeclaration را داریم. پارامتر اول متد RegisterSyntaxNodeAction یک delegate یا Action است. این Action کار فراهم آوردن context کاری را برعهده دارد که نحوه‌ی استفاده‌ی از آن‌را در متد analyzeFieldDeclaration می‌توانید ملاحظه کنید.
سپس در اینجا نوع نود در حال آنالیز (همان نودی که کاربر در ویژوال استودیو انتخاب کرده‌است یا در حال کار با آن است)، به نوع تعریف فیلد تبدیل می‌شود. سپس توکن‌های آن استخراج شده و بررسی می‌شود که آیا یکی از این توکن‌ها کلمه‌ی کلیدی public هست یا خیر؟ اگر این فیلد عمومی تعریف شده بود، نام آن‌را یافته و به عنوان یک Diagnostic جدید بازگشت و گزارش می‌دهیم.


ایجاد اولین Code fixer

در ادامه فایل CodeFixProvider.cs پیش فرض را گشوده و تغییرات ذیل را به آن اعمال کنید. در اینجا مهم‌ترین تغییر صورت گرفته نسبت به قالب پیش فرض، اضافه شدن متد makePrivateDeclarationAsync بجای متد MakeUppercaseAsync از پیش موجود آن است:
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
 
namespace CodingStandards
{
    [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CodingStandardsCodeFixProvider)), Shared]
    public class CodingStandardsCodeFixProvider : CodeFixProvider
    {
        public sealed override ImmutableArray<string> FixableDiagnosticIds
        {
            get { return ImmutableArray.Create(CodingStandardsAnalyzer.DiagnosticId); }
        }

        public sealed override FixAllProvider GetFixAllProvider()
        {
            return WellKnownFixAllProviders.BatchFixer;
        }

        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

            // TODO: Replace the following code with your own analysis, generating a CodeAction for each fix to suggest
            var diagnostic = context.Diagnostics.First();
            var diagnosticSpan = diagnostic.Location.SourceSpan;

            // Find the type declaration identified by the diagnostic.
            var declaration = root.FindToken(diagnosticSpan.Start)
                                   .Parent.AncestorsAndSelf().OfType<FieldDeclarationSyntax>()
                                   .First();

            // Register a code action that will invoke the fix.
            context.RegisterCodeFix(
                CodeAction.Create("Make Private", 
                c => makePrivateDeclarationAsync(context.Document, declaration, c)),
                diagnostic);
        }

        async Task<Document> makePrivateDeclarationAsync(Document document, FieldDeclarationSyntax declaration, CancellationToken c)
        {
            var accessToken = declaration.ChildTokens()
                .SingleOrDefault(token => token.Kind() == SyntaxKind.PublicKeyword);

            var privateAccessToken = SyntaxFactory.Token(SyntaxKind.PrivateKeyword);

            var root = await document.GetSyntaxRootAsync(c);
            var newRoot = root.ReplaceToken(accessToken, privateAccessToken);

            return document.WithSyntaxRoot(newRoot);
        }
    }
}
اولین کاری که در یک code fixer باید مشخص شود، تعیین FixableDiagnosticIds آن است. یعنی کدام آنالایزرهای از پیش تعیین شده‌ای قرار است توسط این code fixer مدیریت شوند که در اینجا همان Id آنالایزر قسمت قبل را مشخص کرده‌ایم. به این ترتیب ویژوال استودیو تشخیص می‌دهد که خطای گزارش شده‌ی توسط CodingStandardsAnalyzer قسمت قبل، توسط کدام code fixer موجود قابل رفع است.
کاری که در متد RegisterCodeFixesAsync انجام می‌شود، مشخص کردن اولین مکانی است که مشکلی در آن گزارش شده‌است. سپس به این مکان منوی Make Private با متد متناظر با آن معرفی می‌شود. در این متد، اولین توکن public، مشخص شده و سپس با یک توکن private جایگزین می‌شود. اکنون این syntax tree بازنویسی شده بازگشت داده می‌شود. با Syntax Factory در قسمت سوم آشنا شدیم.

خوب، تا اینجا یک analyzer و یک code fixer را تهیه کرده‌ایم. برای آزمایش آن دکمه‌ی F5 را فشار دهید تا وهله‌ای جدید از ویژوال استودیو که این آنالایزر جدید در آن نصب شده‌است، آغاز شود. البته باید دقت داشت که در اینجا باید پروژه‌ی CodingStandards.Vsix را به عنوان پروژه‌ی آغازین ویژوال استودیو معرفی کنید؛ چون پروژه‌ی class library آنالایزرها را نمی‌توان مستقیما اجرا کرد. همچنین یکبار کل solution را نیز build کنید.
پس از اینکه وهله‌ی جدید ویژوال استودیو شروع به کار کرد (بار اول اجرای آن کمی زمانبر است؛ زیرا باید تنظیمات وهله‌ی ویژه‌ی اجرای افزونه‌ها را از ابتدا اعمال کند)، همان پروژه‌ی Student ابتدای بحث را در آن باز کنید.


نتیجه‌ی اعمال این افزونه‌ی جدید را در تصویر فوق ملاحظه می‌کنید. زیر سطرهای دارای فیلد عمومی، خط قرمز کشیده شده‌است (به علت تعریف DiagnosticSeverity.Error). همچنین حالت فعلی و حالت برطرف شده را نیز با رنگ‌های قرمز و سبز می‌توان مشاهده کرد. کلیک بر روی گزینه‌ی make private، سبب اصلاح خودکار آن سطر می‌گردد.


روش دوم آزمایش یک Roslyn Analyzer

همانطور که از انتهای بحث قسمت دوم به‌خاطر دارید، این آنالایزرها را می‌توان به کامپایلر نیز معرفی کرد. روش انجام اینکار در ویژوال استودیوی 2015 در تصویر ذیل نمایش داده شده‌است.


نود references را باز کرده و سپس بر روی گزینه‌ی analyzers کلیک راست نمائید. در اینجا گزینه‌ی Add analyzer را انتخاب کنید. در صفحه‌ی باز شده بر روی دکمه‌ی browse کلیک کنید. در اینجا می‌توان فایل اسمبلی موجود در پوشه‌ی CodingStandards\bin\Debug را به آن معرفی کرد.


بلافاصله پس از معرفی این اسمبلی، آنالایزر آن شناسایی شده و همچنین فعال می‌گردد.


در این حالت اگر برنامه را کامپایل کنیم، با خطاهای جدید فوق متوقف خواهیم شد و برنامه کامپایل نمی‌شود (به علت تعریف DiagnosticSeverity.Error).
مطالب
PersianToolkit تقویم و DatePicker شمسی به همراه مناسبت‌ها با استایل زیبا برای WPF
همانطور که اطلاع دارید، کنترل‌های Calendar و DatePicker در WPF، از تقویم‌های مختلف پشتیبانی نمی‌کنند و نمونه‌هایی که در سطح اینترنت موجود است، ظاهر و استایل مناسبی ندارند. بنابر این تصمیم گرفتم تا خودم دست به کار شوم و این کمبود را حل کنم. نتیجه‌ی آن شد کتابخانه‌ی PersianToolkit که بصورت استاندارد تقویم شمسی را به کنترل‌های Calendar و DatePicker اضافه می‌کند و استایل‌های زیبایی را هم به همراه خود دارد. این کتابخانه شامل تمام مناسبت‌های شمسی، قمری و میلادی بوده و امکان نمایش روزهای تعطیل را نیز داراست.
همچنین پرشین تولکیت شامل توابع قدرتمندی جهت دریافت تاریخ بصورت شمسی، قمری و میلادی است. لازم به ذکر است که توابع محاسبه تاریخ قمری بسیار دقیق بوده و خطای بسیار کمی دارد. علاوه بر موارد گفته شده، پرشین تولکیت شامل استایل‌ها و براش‌های پیشفرض متنوعی می‌باشد که کاربر می‌تواند با توجه به سلیقه‌ی خویش، رنگ بندی تقویم را تغییر دهد.
بروزرسانی:
نمونه مثال کامل به گیتهاب پروژه اضافه شد
کنترل تاریخ زمان به این مجموعه اضافه شد

پرشین تولکیت در 3 استایل مختلف موجود است که بصورت Runtime هم قابلیت تغییر استایل را دارد (روشن، تاریک، بنفش):



نحوه‌ی نصب و استفاده
  ابتدا پرشین تولکیت را از نیوگت نصب کنید:
  Install-Package PersianToolkit
سپس منابع برنامه را در فایل App.xaml بارگزاری کنید:
<ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <ResourceDictionary.MergedDictionaries>
                        <ResourceDictionary Source="pack://application:,,,/PersianToolkit;component/Themes/SkinDefault.xaml"/>
                        <ResourceDictionary Source="pack://application:,,,/PersianToolkit;component/Themes/Theme.xaml"/>
                    </ResourceDictionary.MergedDictionaries>
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>  
در هر کجا که نیاز به تقویم دارید ابتدا فضای نام برنامه را فراخوانی کنید سپس از اجزای آن استفاده کنید
 
  xmlns:pc="http://github.com/ghost1372/PersianToolkit"
         <pc:Calendar/>
    <pc:DatePicker/>  
تغییر پوسته برنامه
پرشین تولکیت شامل 3 پوسته پیشفرض است که میتوانید به راحتی در زمان اجرا، پوسته برنامه را تغییر دهید. قبل از آن نیاز است تا تابع تغییر پوسته را پیاده سازی کنید:
internal void UpdateSkin(SkinType skin)
        {
            ResourceDictionary skins0 = Resources.MergedDictionaries[0];
            skins0.MergedDictionaries.Clear();
            skins0.MergedDictionaries.Add(ResourceHelper.GetSkin(skin));
            skins0.MergedDictionaries.Add(new ResourceDictionary
            {
                Source = new Uri("pack://application:,,,/PersianToolkit;component/Themes/Theme.xaml")
            });
            Current.MainWindow?.OnApplyTemplate();
        }
ورودی تابع از نوع SkinType می‌باشد که شامل Dark, Violet و Default است:
UpdateSkin(SkinType.Violet);


تغییر تقویم به حالت میلادی یا شمسی
برای تغییر نوع تقویم میتوانید از کلاس ConfigHelper استفاده کنید (به صورت پیشفرض تقویم شمسی فعال است و نیازی به تغییر تقویم به شمسی نیست):
ConfigHelper.Instance.SetLanguage(ConfigHelper.Language.Persian);
نکته: فقط یکبار آن هم در زمان شروع شدن برنامه میتوانید نوع تقویم را تغییر دهید. در زمان اجرا نمیتوانید نوع تقویم را تغییر دهید.

گزینه‌های موجود

ShowHoliday :مناسبت‌ها
جهت نمایش مناسبت‌ها و روز‌های تعطیل بر روی تقویم، میتوانید آن را فعال کنید:
 <pc:Calendar pc:Holiday.ShowHoliday="True"/>

رنگ‌ها : روز جاری، روز انتخاب شده، روزهای تعطیل، کادر مناسبت‌ها
شما میتوانید براحتی رنگ روز فعلی، روز انتخاب شده و روزهای تعطیل را تغییر دهید:
<pc:Calendar pc:ColorStyle.HolidayDayBrush="{DynamicResource SuccessBrush}"
    pc:ColorStyle.SelectedDateBrush="{DynamicResource WarningBrush}" 
    pc:ColorStyle.TodayDateBrush="{DynamicResource InfoBrush}"/>
بصورت پیشفرض رنگ‌های زیر موجود است و با نوشتن آنها میتوانید از رنگ‌های پیشفرض استفاده کنید:
PrimaryBrush
SuccessBrush
InfoBrush
DangerBrush
WarningBrush
AccentBrush

برای تغییر رنگ کادر عنوان مناسبت‌ها باید از پراپرتی HolidayContentStyle استفاده کنید. دقت کنید که این پراپرتی ورودی از نوع Style را برای کنترل Label دریافت می‌کند. بصورت پیشفرض استایل‌های زیر موجود است:
 <pc:Calendar pc:ColorStyle.HolidayContentStyle="{StaticResource LabelPrimary}"/>
LabelDefault
LabelPrimary
LabelSuccess
LabelInfo
LabelDanger
LabelWarning

تغییر رنگ‌ها و استایل به وسیله کدهای سی شارپ
شما میتوانید رنگ‌ها و استایل‌های موجود را با سی شارپ هم تغییر دهید برای این منظور وارد کلاس ColorStyle شوید و پراپرتی موردنظر را انتخاب کنید و مقدار دلخواه را تنظیم کنید. برای سادگی کار، استایل‌ها و رنگ‌های پیشفرض توسط کلاس ResourceHelper و ResourceBrushToken یا ResourceHolidayContentStyleToken قابل دسترسی هستند.
ColorStyle.SetHolidayDayBrush(pc, ResourceHelper.GetResource<Brush>(ResourceBrushToken.SuccessBrush)); 
ColorStyle.SetHolidayContentStyle(pc, ResourceHelper.GetResource<Style>(ResourceHolidayContentStyleToken.LabelPrimary));
 
مطالب
آموزش (jQuery) جی کوئری 7#
پس از انواع روش‌های انتخاب عناصر در jQuery اکنون زمان آشنایی با متدها و توابعی جهت پردازش مجموعه انتخاب شده رسیده است.
٢-٣- مدیریت مجموعه انتخاب شده
هز زمان که مجموعه ای از عناصر انتخاب انتخاب می‌شوند، خواه این عناصر از طریق انتخاب کننده‌ها انتخاب شده باشند و یا تابع ()$ در صدد ایجاد آن باشد، مجموعه ای در اختیار داریم که آماده دستکاری و اعمال تغییر با استفاده از متدهای jQuery می‌باشد. این متدها را در پست‌های آتی بررسی خواهیم کرد. اما اکنون به این نکته می‌پردازیم که اگر بخواهیم از همین مجموعه انتخاب شده زیر مجموعه ای ایجاد کنیم و یا حتی آن را گسترش دهیم، چه باید کرد؟ به طور کلی در این پست پیرامون این مورد بحث خواهد شد که چگونه می‌توانیم مجموعه انتخاب شده را به آن صورت که می‌خواهیم بهیود دهیم.
برای درک مطالبی که قصد توضیح آنها را در این قسمت داریم، یک صفحه کارگاهی دیگر نیز در فایل قابل دانلود این کتاب موجود می‌باشد که با نام chapter2/lab.wrapped.set.html قابل دسترسی می‌باشد. نکته مهم در مورد این صفحه کارگاهی آن است که می‌بایست عبارات و دستورهای کامل را با ساختار صحیح وارد کنیم در غیر این اینصورت این صفحه کاربردی نخواهد داشت.


٢-٣-١-تعیین اندازه یک مجموعه عناصر
قبلا اشاره کردیم که مجموعه عناصر jQuery شباهت هایی با آرایه دارد. یکی از این شباهت‌ها داشتن ویژگی length می‌باشد که مانند آراه در جاوااسکریپت ، تعداد عناصر موجود در مجموعه را شامل می‌شود.
افزون بر این ویژگی، jQueryیک متد را نیز معرفی کرده است که دقیقا شبیه به length عمل می‌کند. این متد ()size می‌باشد که استفاده از آن را در مثال زیر مشاهده می‌کنید.
$('#someDiv')
       .html('There are '+$('a').size()+' link(s) on this page.');
این مثال تمام لینک‌های موجود در صفحه را شناسایی می‌کند و سپس بااستفاده از متد ()size تعداد آنها را بر می‌گرداند. در واقع یک رشته ایجاد می‌شود و در یک عنصر با شناسه someDiv قرار داده می‌شود. متد html در پست‌های آتی بررسی می‌شود. فرم کلی متد ()size را در زیر مشاهده می‌کنید.
()size
تعداد عناصر موجود در مجموعه را محاسبه می‌کند
پارامترها
بدون پارامتر
خروجی
تعداد عناصر مجموعه
اکنون که تعداد عناصر مجموعه را می‌دانیم چگونه می‌توانیم به هریک از آنها دسترسی مستقیم داشته باشیم؟

٢-٣-٢-بکارگیری عنصرهای مجموعه
به طور معمول پس از انتخاب یک مجموعه با استفاده از متدهای jQuery، عملی را بروی آن عناصر انتخاب شده انجام می‌دهیم، مانند مخفی کردن آنها با متد ()hide، اما گاهی اوقات می‌خواهیم بروی یک یا چند مورد خاص از عناصر انتخاب شده عملی را اعمال کنیم. jQuery چند روش مختلف را به منظور اینکار ارایه می‌دهد.

از آنجا که مجموعه عناصر انتخاب شده در jQuery مانند آرایه در جاوااسکریپت می‌باشد، بنابراین به سادگی می‌توانیم از اندیس برای دستیابی به عناصر مختلف مجموعه استفاده کنیم. برای مثال به منظور دسترسی به اولین عکس از مجموعه عکس‌های انتخاب شده که دارای صفت alt می‌باشند از دستور زیر استفاده می‌کنیم:
$('img[alt]')[0]
اما اگر ترجیح می‌دهید به جای اندیس از یک متد استفاده کنید، jQuery متد ()get را در نظر گرفته است:
(get(index
برای واکشی یک یا تمام عناصر موجود در مجموعه استفاده می‌شود. اگر برای این متد پارامتری ارسال نشود، تمام عناصر را در قالب یک آرایه جاوااسکریپت بر می‌گرداند، اما در صورت ارسال یک پارامتر، تنها آن عنصر را بر می‌گرداند.
پارامتر
شماره اندیس یک عنصر که می‌بایست یک مقدار عددی باشد.
خروجی
یک یا آرایه ای از عناصر
دستور زیر مانند دستور قبلی عمل می‌کند:
$('img[alt]').get(0)
متد ()get می‌تواند برای بدست آوردن یک ارایه از عناصر پیچیده نیز استفاده شود. مثلا:
var allLabeledButtons = $('label+button').get();
خروجی دستور بالا لیست تمام button‌های موجود در صفحه است که بعد از عنصر label قرار گرفته اند، در نهایت این آرایه در متغیری به نام allLabeledButtons قرار خواهد گرفت.

در متد ()get دیدیم که با دریافت شماره اندیس یک عنصر، آن عنصر را برای ما برمی گرداند، عکس این عمل نیز امکان پذیر می‌باشد. فرض کنید می‌خواهیم از میان تمام عناصر عکس، شماره اندیس عکسی با شناسه findMe را بدست آوریم. برای این منظور می‌توانیم از کد زیر بهره ببریم:

var n = $('img').index($('img#findMe')[0]);
فرم کلی متد ()index به صورت زیر است:
(index(element
عنصر ارسالی را در مجموعه عناصر پیدا می‌کند، سپس شماره اندیس ان را بر می‌گرداند. اگر چنین عنصری در مجموعه یافت نشد خروجی 1- خواهد بود.
پارامتر
پارامتر این متد می‌تواند یک عنصر و یا یک انتخاب کننده باشد که خروجی انتخاب کننده نیز در نهایت یک عنصر خواهد بود.
خروجی
شماره اندیس عنصر در مجموعه

٢-٣-٣-برش و کوچک کردن مجموعه ها
ممکن است شرایطی پیش آید که پس از بدست آوردن یک مجموعه عناصر انتخاب شده نیاز باشد که عنصری به آن مجموعه اضافه و یا حتی عنصری را از آن حذف کنیم تا در نهایت مجموعه ای باب میل ما بدست آید. برای انجام چنین تغییرهایی در یک مجموعه jQuery کلکسیون بزرگی از متدها را برای ما به همراه دارد. اولین موردی که به آن می‌پردازیم، افزودن یک عنصر به مجموعه می‌باشد.

اضافه کردن عناصر بیشتر به یک مجموعه عنصر انتخاب شده
همواره ممکن است شرایطی پیش آید که پس از ایجاد یک مجموعه عناصر انتخاب شده، بخواهیم عنصری را به آن اضافه کنیم. یکی از دلایلی که باعث می‌شود این امر در jQuery بیشتر مورد نیاز باشد توانایی استفاده از متدهای زنجیره ای در jQuery است.
ابتدا یک مثال ساده را بررسی می‌کنیم. فرض کنید می‌خواهیم تمام عناصر عکس که دارای یکی از دو خصوصیت alt و یا title می‌باشند را انتخاب کنیم، با استفاده از انتخاب کننده‌های قدرتمند jQuery دستوری مانند زیر خواهیم نوشت:
$('img[alt],img[title]')
اما برای آنکه با متد ()add که به منظور افزودن عنصر به مجموعه عناصر می‌باشد آشنا شوید این مثال را به صورت زیر می‌نویسیم:
$('img[alt]').add('img[title]')
استفاده از متد ()add به این شکل موجب می‌شود تا بتوانیم مجموعه‌های مختلف را به یکدیگر متصل کنیم و یک مجموعه کلی‌تر از عناصر انتخاب شده ایجاد کنیم. متد ()add در این حالت مانند متد ()end عمل می‌کند که در قسمت ٢-٣-٦شرح داده خواهد شد.
ساختار کلی متد ()add به صورت زیر است:
َ(add(expression
ابتدا یک کپی از مجموعه انتخاب شده ایجاد می‌کند، سپس با افزودن محتویات پارامتر expression به آن نمونه، یک مجموعه جدید تشکیل می‌دهد. پارامتر expression می‌تواند حاوی یک انتخاب کننده، قطعه کد HTML، یک عنصر و یا آرایه ای از عناصر باشد.
پارامتر
در این پارامتر مواردی (مانند رشته، آرایه، المان) که می‌خواهیم به مجموعه عناصر انتخاب شده اضافه شوند قرار می‌گیرد. که می‌تواند انتخاب کننده، قطعه کد HTML، یک عنصر و یا ارایه ای از عناصر باشد.
خروجی
یک کپی از مجموعه اصلی به علاوه موارد اضافه شده.
اصلاح عناصر یک مجموعه عنصر انتخاب شده
در قسمت قبل دیدیم که چگونه با استفاده از متد ()add و با بکار گیری آن در توابع زنجیره ای، توانستیم عناصری جدید به مجموعه انتخاب شده اضافه کنیم. عکس این عمل را نیز می‌توان با ستفاده از متد ()not در توابع زنجیره ای انجام داد. این متد عملکرید شبیه به فیلتر not: دارد، اما با این تفاوت که بکار گیری آن مانند متد ()add می‌باشد و می‌توان در هر جایی از زنجیره از آن استفاده کرد تا عناصر مورد نظر را از مجموعه انتخاب شده حذف کنیم.
فرض کنید می‌خواهیم تمامی عناصر عکسی را که دارای خصوصیت title می‌باشند به استثنای آن موردی که واژه puppy در مقدار مربوط به این صفت استفاده کرده اند را انتخاب کنیم. این کار به سادگی و با استفاده از دستوری مانند([ "img[title]:not([title*="puppy می‌توان انجام داد. اما برای آن که مثالی از چگونگی کار متد ()not ببینید، این کار را به شکل زیر انجام می‌دهیم:
$('img[title]').not('[title*=puppy]')
این دستور تمام عکس‌های دارای خصوصیت title را به استثنا titleهایی که مقدار puppy در آنها وجود دارد را انتخاب می‌کند.
شکل کلی متد ()not مانند زیر است:
(not(expression
ابتدا یک کپی از مجموعه انتخاب شده ایجاد می‌کند، سپس از آن کپی عناصری را که expression مشخص می‌کند را حذف می‌نماید.
پارامتر
این پارامتر تعیین کننده عناصر در نظر گرفته شده برای حذف می‌باشد. این پارامتر می‌تواند یک عنصر، ارایه ای از عناصر، انتخاب کننده و یا یک تابع باشد.
اگر این پارامتر تابع باشد، تک تک عناصر مجموعه به آن ارسال می‌شوند و هر یک که خروجی تابع را برابر با مقدار true کند، حذف می‌شود.
خروجی
یک کپی از مجموعه اصلی بدون موارد حذف شده. 
این شیوه برای ایجاد مجموعه هایی که انتخاب کننده‌ها قادر به ساخت آن‌ها نمی‌باشند، کاربرد بسیار مناسبی دارد، زیرا از تکنیک‌های برنامه نویسی استفاده می‌کند و دست ما را برای اعمال انتخاب‌های گوناگون باز می‌کند.
اگر در شرایطی خاص با حالتی روبرو شدید که احساس کردید عکس این انتخاب برای شما کارایی دارد، باز می‌توانید از یکی دیگر از متدهای jQuery استفاده کنید، متد ()filter عملکردی مشابه با متد ()not دارد با این تفاوت که عناصری از مجموعه حذف می‌شوند که خروجی تابع را false کنند.
فرض کنید می‌خواهیم تمام عناصر td که دارای یک عنصر عددی می‌باشند را انتخاب کنیم. با وجود قدرت فوق العاده انتخاب کننده‌های jQuery به ما ارایه می‌دهند، انجام چنین کاری با استفاده از انتخاب کننده‌ها غیر ممکن است. در این حالت از متد ()filter را به شکل زیر استفاده می‌کنیم:
$('td').filter(function(){return this.innerHTML.match(/^\d+$/)})
دستور فوق یک مجموعه از تمام عناصر td انتخاب می‌کند، سپس تک تک عناصر مجموعه انتخاب شده را به تابعی که پارامتر متد ()filter می‌باشد، ارسال می‌کند. این تابع با استفاده از عبارت منظم مقدار عنصر کنونی را می‌سنجد. اگر این مقدار یک یا زنجیره ای از ارقام بود، خروجی تابع true خواهد بود، و ان عنصر از مجموعه حذف نمی‌شود، اما اگر این مقدار عددی نبود، خروجی تابع false بوده و عنصر از مجموعه کنار گذاشته می‌شود.
شکل کلی متد ()filter به شکل زیر است.
(filter(expression
ابتدا یک کپی از مجموعه انتخاب شده ایجاد می‌کند، سپس از آن کپی عناصری را که expression مشخص می‌کند را حذف می‌نماید.
پارامتر
این پارامتر تعیین کننده عناصر در نظر گرفته شده برای حذف می‌باشد. این پارامتر می‌تواند یک عنصر، ارایه ای از عناصر، انتخاب کننده و یا یک تابع باشد.
اگر این پارامتر تابع باشد، تک تک عناصر مجموعه به آن ارسال می‌شوند و هر یک که خروجی تابع را برابر با مقدار false کند، حذف می‌شود.
خروجی
یک کپی از مجموعه اصلی بدون عناصر حذف شده.  

ایجاد یک زیر مجموعه از مجموعه عناصر انتخاب شده
گاهی اوقات داشتن یک زیر مجموعه از عناصر یک مجموعه، چیزی است که دنبال آن هستیم. برای این منظور jQuery متد ()slice را ارایه می‌کند که عناصر را بر اساس جایگاه آن‌ها به زیر مجموعه هایی کوچکتر تقسیم می‌کند. نتیجه استفاده از این متد یک مجموعه جدید برگرفته از تعدادی عناصر پشت سر هم،از یک مجموعه انتخاب شده خواهد بود:
شکل کلی متد ()slice مانند زیر است:
(slice(begin, end
ایجاد و برگرداندن یک مجموعه جدید از بخشی از عناصر پشت سر هم در یک مجموعه اصلی.
پارامتر
begin: پارامتر begin که یک پارامتر عددی می‌باشد و مقدار اولیه آن از صفر آغاز می‌شود، نشان دهنده اولین عنصری است که می‌خواهیم در مجموعه جدید حضور داشته باشد.
end: پارامتر دوم که آن هم یک پارامتر عددی می‌باشد و از صفر آغاز می‌شود، در این متد اختیاری است. این پارامتر اولین عنصری است که نمی‌خواهیم از آن به بعد در مجموعه جدید حضور داشته باشد را مشخص می‌کند. اگر مقداری برای این پارامتر ننویسیم، به صورت پیش فرض تا انتهای مجموعه انتخاب می‌شود.
خروجی
یک مجموعه عنصر جدید.
 اگر بخواهیم از یک مجموعه کلی، تنها یک عنصر را در قالب یک مجموعه انتخاب کنیم می‌توانیم از متد ()slice استفاده کنیم و مکان آن عنصر در مجموعه را به آن ارسال کنیم. دستور زیر مثالی از این حالت می‌باشد:
$('*').slice(2,3);
این مثال ابتدا تمام عناصر موجود در صفحه را انتخاب می‌کند، سپس سومین عنصر از آن مجموعه را در یک مجموعه جدید باز می‌گرداند. دقت کنید که دستور فوق با دستور (2)get.('*')$ کاملا متفاوت است، چرا که خروجی این دستور تنها یک عنصر است، در حالی که خروجی دستور فوق یک مجموعه است.
از همین رو دستور زیر باعث ایجاد یک مجموعه که شامل چهار عنصر اولیه صفحه می‌باشد، می‌شود.
$('*').slice(0,4);
برای ایجاد یک مجموعه از عناصر انتهایی موجود در صفحه نیز می‌توان از دستوری مانند زیر استفاده کرد:
$('*').slice(4);
این دستور تمام عناصر موجود در صفحه را انتخاب می‌کند، سپس مجموعه ای جدید می‌سازد که تمام عناصر به استثنای چهار عنصر اول را در خود جای می‌دهد.


٢-٣-٤-ایجاد مجموعه بر اساس روابط
jQuery به ما این توانایی را داده است تا مجموعه هایی را انتخاب کنیم، که اساس انتخاب عناصر، رابطه سلسله مراتبی آنها با عناصر HTML صفحه باشد. اکثر این متدها یک پارامتر اختیاری از نوع انتخاب کننده دریافت می‌کنند که می‌تواند برای انتخاب عناصر مجموعه استفاده شود. در صورتی که چنین پارامتری ارسال نگردد، تمام عناصر واجد شرایط متد در مجموعه انتخاب می‌شوند.


جدول ٢-٤-متدهای موجود برای ایجاد مجموعه‌های جدید بر اساس روابط
 توضیح متد
 مجموعه ای را برمی گرداند که شامل تمام فرزندان بدون تکرار از عناصر مجموعه می‌باشد.
() children
 مجموعه ای شامل محتویات تمام عناصر برمی گرداند. (از این متد معمولا برای عناصر iframe استفاده می‌شود)
() contents
 مجموعه ای شامل فرزندان پدرش که بعد از خود این عنصر می‌باشند را برمی گرداند. این مجموعه عنصر تکراری ندارد.
() next
 مجموعه ای شامل تمام فرزندان پدرش که بعد از خود این عنصر می‌باشند را بر می‌گرداند.
() nextAll
 مجموعه ای شامل نزدیک‌ترین پدر اولین عنصر مجموعه را بر می‌گرداند.
() parent
 مجموعه ای شامل تمام پدران مستقیم عناصر مجموعه را بر می‌گرداند. این مجموعه عنصر تکراری ندارد.
() parents
 مجموعه ای شامل فرزندان پدرش که قبل از خود این عنصر می‌باشند را برمی گرداند. این مجموعه عنصر تکراری ندارد. () prev
  مجموعه ای شامل تمام فرزندان پدرش که قبل از خود این عنصر می‌باشند را بر می‌گرداند. () prevAll
 مجموعه ای بدون عنصر تکراری را بر می‌گرداند که شامل تمام فرزندان پدر خود عنصر خواهد بود.
() siblings
تمامی جدول بالا غیر از متد ()contents پارامتری از نوع رشته که انتخاب کننده برای متد می‌باشند، استفاده می‌کند.

٢-٣-٥-استفاده از مجموعه‌های انتخاب شده برای انتخاب عناصر
با وجود اینکه تاکنون با شمار زیادی از توانایی‌های انتخاب و انتخاب کننده‌ها در jQuery آشنا شده اید، هنوز چند مورد دیگر نیز برای افزایش قدرت انتخاب باقی مانده است.
متد ()find بروی یک مجموعه عناصر انتخاب شده به کار گرفته می‌شود و یک پارامتر ورودی نیز دارد. این پارامتر که یک انتخاب کننده است تنها بروی فرزندان این مجموعه اعمال می‌شود. برای مثال فرض کنید یک مجموعه از عناصر انتخاب و در متغیر wrapperSet قرار گرفته است. با دستور زیر می‌توانیم تمام عناصر (تگ) cite را که درون یک تگ p قرار گرفته اند را انتخاب کنیم، به شرطی که آن‌ها فرزندان عناصر مجموعه wrapperSet باشند:
wrappedSet.find('p cite')
البته می‌توانیم این تکه کد را به صورت زیر هم بنویسیم:
$('p cite', wrapperSet)
مانند سایر متدهای معرفی شده قدرت اصلی این متد نیز هنگام استفاده در متدهای زنجیره ای مشخص می‌شود.
شکل کلی متد ()findمانند زیر است:
(find(selector
یک مجموعه عنصر جدید ایجاد می‌کند که شامل فرزندان عناصر مجموعه قبل می‌شود.
پارامتر
یک انتخاب کننده است که در قالب یک رشته به این متد ارسال می‌شود.
خروجی
یک مجموعه عنصر جدید
جهت پیدا کردن عناصری که داخل یک wrapperSet می‌توانیم از متد دیگری به نام ()contains نیز استفاده کنیم. این متد مجموعه ای را بر می‌گرداند که شامل تمام عناصری است که در انتخاب کننده پارامتر ورودی است. مثلا
$('p').contains('Lorem ipsum')
این دستور تمامی عناصر p را که شامل Lorem ipsum است را بر می‌گرداند. قالب کلی متد مانند زیر است:
(contains(text
مجموعه ای از عناصر که شامل متن ورودی می‌باشند را بر می‌گرداند.
پارامتر
رشته ورودی که می‌خواهیم در عنصر فراخوان متد جستجو شود.
خروجی
مجموعه ای از عناصر از نوع فراخوان متد را بر می‌گرداند که شامل متن ورودی باشد.
آخرین متدی که به بررسی آن می‌پردازیم متد ()is می‌باشد. با استفاده از این متد می‌توانیم اطمینان حاصل کنیم که دست کم یک عنصر از مجموعه عناصر، شرایط مشخص شده توسط ما را دارا باشد. یک انتخاب کننده به این متد ارسال می‌شود، اگر عنصری از مجموعه عناصر انتخاب شد، خروجی متد true می‌شود و در غیر این صورت مقدار false بر گردانده خواهد شد. برای مثال:
var hasImage = $('*').is('img');
در صورت وجود دست کم یک عنصر عکس در کل عناصر صفحه، دستور بالا مقدار متغیر hasImage را برابر true قرار می‌دهد.
قالب کلی متد ()is مانند زیر است:
(is(selector
بررسی می‌کند که آیا عنصری در مجموعه وجود دارد که انتخاب کننده ارسالی آن را انتخاب کند؟
پارامتر
یک انتخاب کننده است که در قالب یک رشته به این متد ارسال می‌شود.
خروجی
مقدار true در صورت وجود دست کم یک عنصر و false در صورت عدم وجود توسط تابع برگردانده می‌شود.

٢-٣-٦-مدیریت زنجیره‌های jQuery
تاکنون در مورد استفاده از متدها و توابع زنجیره ای زیاد بحث کرده ایم و انجام چندین عمل در یک دستور را به عنوان یک قابلیت بزرگ معرفی کرده ایم و البته از آن هم استفاده کردیم و در ادامه نیز استفاده خواهیم کرد. به کار گیری متدها به صورت زنجیره ای نه تنها موجب نوشتن کدهای قدرتمند و قوی به صورت مختصر و خلاصه می‌شود، بلکه از لحاظ کارایی نیز نکته مثبتی محسوب می‌شود، زیرا برای اعمال هر متد نیازی به محاسبه و انتخاب مجدد مجموعه نخواهد بود.
بنابراین متدهای مختلفی که در زنجیره استفاده می‌کنیم، برخی از آنها ممکن است مجموعه‌های جدیدی تولید کنند. برای مثال استفاده از متد ()clone موجب می‌شود تا مجموعه ای جدید از کپی عناصر در مجموعه اول ایجاد شود. زمانی که یکی از متدهای زنجیره یک مجموعه جدید را تولید می‌کند، دیگر راهی برای استفاده از مجموعه پیشین در زنجیره نخواهیم داشت و این نکته زنجیره ما را به خطر می‌اندازد. عبارت زیر را در نظر بگیرید:
$('img').clone().appendTo('#somewhere');
این مثال دو مجموعه ایجاد می‌کندو نخست مجموعه ای شامل تمام عناصر عکس صفحه ایجاد می‌شود و مجموعه دوم کپی مجموعه اول است که به انتهای عنصری با شناسه somewhere اضافه می‌شود. حال اگر بخواهیم پس از اعمال کپی بروی مجموعه اصلی عملی مانند افزودن یک کلاس را بروی آن انجام دهیم چه باید بکنیم؟ همچنین نمی‌توانیم مجموعه اصلی را به انتهای زنجیره انتقال دهیم، چون بروی قسمتی دیگر اثر خواهد گذاشت.
برای مرتفع کردن چنین نیازی، jQuery متد ()end را معرفی کرده است. زمانی از این متد استفاده می‌شود،  یک نسخه پشتیبان از مجموعه کنونی ایجاد می‌شود . همان مجموعه برگردانده می‌شود. بنابراین اگر متدی پس از آن ظاهر شودف اثرش بروی مجموعه اولیه خواهد بود. مثال زیر را در نظر بگیرید:
$('img').clone().appendTo('#somewhere').end().addClass('beenCloned');
این مثال دو مجموعه ایجاد می‌کندو نخست مجموعه ای شامل تمام عناصر عکس صفحه ایجاد می‌شود و مجموعه دوم کپی مجموعه اول است که به انتهای عنصری با شناسه somewhere اضافه می‌شود. اما با استفاده از متد ()end  همان مجموعه اولیه در ادامه زنجیره قرار خواهد گرفت و سپس متد ()addClass بروی تمامی عناصر عکس اعمال می‌شود، نه تنها عکس‌های موجود در مجموعه اول، اگر از متد ()end  استفاده نشود متد ()addClass برویعناصر مجموعه دوم اعمال خواهد شد.
قالب کلی متد ()end به شکل زیر است:
()end
در متدهای زنجیره ای استفاده می‌شود و از مجموعه کنونی یک پشتیبان می‌گیرد تا همان مجموعه در زنجیره جریان داشته باشد.
پارامتر
ندارد
خروجی
مجموعه عنصر قبلی
شاید در نظر گرفتن مجموعه‌ها در متدهای زنجیره ای به شکل یک پشته به درک بهتر از متد ()end  کمک کند. هر زمان که یک مجموعه جدید در زنجیره ایجاد می‌شود، آن مجموعه به بالای پشته افزوده می‌شود، اما با فراخوانی متد ()end، بالاترین مجموعه از این پشته برداشته می‌شود و مجدادا مجموعه پیشین در زنجیره قرار می‌گیرد.
متد دیگری که توانایی ایجاد تغییر در این پشته خیالی را دارد، متد ()andSelf می‌باشد. این متد دو مجموعه بالای پشته را با یکدیگر ادغام می‌کند و آن‌ها را به یک مجموعه تبدیل می‌کند.
شکل کلی متد ()andSelf به صورت زیر است:
()andSelf
دو مجموعه پیشین در یک زنجیره را با یکدیگر ادغام می‌کند.
پارامتر
ندارد
خروجی
مجموعه عنصری ادغام شده
در مباحث بعدی کار با صفت‌ها و ویژگی‌های عناصر بحث خواهد شد.

موفق و موید باشید
مطالب
امکان استفاده‌ی مستقیم از کتابخانه‌های Full .NET Framework در NET Core 2.0.
یکی از مواردی که به همراه NET Core 1.x. وجود دارد، کمبود کتابخانه‌های ثالث مخصوص آن است. برای مثال کتابخانه‌ی log4net در اوایل ارائه‌ی NET Core. نگارش مخصوص به آن‌را نداشت (البته هم اکنون دارد). باید درنظر داشت، این مورد صرفا در حالت توزیع چندسکویی برنامه‌های مبتنی بر NET Core. مشکل ایجاد می‌کرد. از این جهت که می‌توان full .NET framework را به عنوان Target Framework برنامه‌های NET Core. معرفی کرد و در این حالت برنامه بدون هیچگونه مشکلی تنها بر روی ویندوز و سرورهای ویندوزی اجرا می‌شود (و امکان دسترسی به تمامی کتابخانه‌های مخصوص full .NET framework را نیز دارا خواهد بود)؛ اما قابلیت توزیع بر روی لینوکس و مک را از دست خواهد داد.
در NET Core 2.0. از یک اصطلاحا «compatibility shim» مخصوص استفاده می‌شود که امکان افزودن ارجاعات به full framework library‌ها را بدون نیاز به تغییر target framework برنامه میسر می‌کند. یعنی در اینجا می‌توان یک کتابخانه‌ی قدیمی دات نتی را در برنامه‌های مبتنی بر NET Core. بر روی لینوکس نیز اجرا کرد و در این حالت نیازی به تبدیل اجباری این کتابخانه به نسخه‌ی NET Core. آن نیست.


NET Core 2.0. پیاده سازی کننده‌ی NET Standard 2.0. است

NET Standard‌. در حقیقت یک قرار داد است که سکوهای کاری مختلف دات نتی مانند Full .NET Framework ، Xamarin ، Mono ، UWP و غیره می‌توانند آن‌را پیاده سازی کنند. یک نمونه‌ی دیگر این پیاده سازی‌ها نیز NET Core. است. برای مثال دات نت 4.6.1، استاندارد و قرار داد شماره‌ی 2 دات نت را پیاده سازی می‌کند. به همین صورت NET Core 2.0. نیز پیاده سازی کننده‌ی این استاندارد شماره 2 است.
 با تغییرات اخیر، اکنون NuGet می‌تواند کتابخانه‌های مبتنی بر NET Standard 2. را در برنامه‌های مبتنی بر سکوهای کاری که آن‌را پیاده سازی می‌کنند، بدون مشکل اضافه کند. برای مثال می‌توان اسمبلی‌های دات نت 4.6.1 را به برنامه‌های ASP.NET Core 2.0 اضافه کرد (کاری که در نگارش 1x آن به صورت مستقیم میسر نیست) و یا می‌توان اسمبلی‌های کامپایل شده‌ی برای دات نت استاندارد 2 را به برنامه‌های مبتنی بر دات نت 4.6.1 اضافه کرد.


آیا واقعا کتابخانه‌های قدیمی دات نتی توسط برنامه‌های NET Core 2.0. در لینوکس نیز اجرا خواهند شد؟

دات نت استاندارد، بیش از یک قرار داد چیزی نیست و پیاده سازی کنندگان آن می‌توانند سطح بیشتری را نسبت به این قرار داد نیز لحاظ کنند. برای مثال دات نت 4.6.1 شامل سطح API بیشتری از دات نت استاندارد 2 است.
 به همین جهت باید درنظر داشت که امکان اضافه کردن یک بسته‌ی نیوگت از یک کتابخانه‌ی نوشته شده‌ی برای دات نت کامل در برنامه‌های دات نت Core به معنای تضمینی برای کار کردن آن در زمان اجرا نخواهد بود. از این جهت که دات نت کامل، به همراه قسمت‌هایی است که در NET Standard. وجود خارجی ندارند. بنابراین اگر کتابخانه‌ی استفاده شده صرفا این API مشترک را هدف قرار داده‌است، هم قابلیت اتصال و هم قابلیت اجرا را خواهد داشت؛ اما اگر برای مثال کسی بسته‌ی NServiceBus را به پروژه‌ی ASP.NET Core 2.0 اضافه کند، بدون مشکل کامپایل خواهد شد. اما از آنجائیکه این کتابخانه از MSMQ استفاده می‌کند که خارج از میدان دید این استاندارد است، در زمان اجرا با شکست مواجه خواهد شد.


«compatibility shim» در NET Standard 2.0. چگونه کار می‌کند؟

در NET Core.، پیاده سازی Object در System.Runtime قرار دارد و کد تولید شده‌ی توسط آن یک چنین ارجاعی را [System.Runtime]System.Object تولید می‌کند. اما در دات نت کلاسیک، System.Object در mscorlib قرار دارد. به همین جهت زمانیکه سعی کنید اسمبلی‌های دات نت کلاسیک را در NET Core 1.x. استفاده کنید، پیام یافتن نشدن نوع‌ها را دریافت خواهید کرد. اما در NET Core 2.0. یک پیاده سازی صوری (facade) از mscorlib وجود دارد که کار آن هدایت نوع درخواستی، به نوع واقعی پیاده سازی شده‌ی در NET Core. است.


در این تصویر استفاده‌ی از یک کتابخانه‌ی ثالث را مشاهده می‌کنید که ارجاعی را به [mscorlib]Microsoft.Win32.RegistryKey دارد (مبتنی بر دات نت کلاسیک است).  همچنین یک mscorlib مشخص شده‌ی به صورت facade را نیز مشاهده می‌کنید. کار آن هدایت درخواست نوع واقع شده‌ی در mscorlib، به نوع موجود [Microsoft.Win32.Registry] Microsoft.Win32.RegistryKey است و تنها زمانی کار خواهد کرد که Microsoft.Win32.RegistryKey.dll وجود خارجی داشته باشد. به این معنا که رجیستری، یک مفهوم ویندوزی است و این کتابخانه بر روی ویندوز بدون مشکل کار می‌کند. اما تحت لینوکس، این قسمت خاص با پیام PlatformNotSupportedException خاتمه خواهد یافت. اما اگر قسمت‌هایی از این کتابخانه را استفاده کنید که در تمام سکوهای کاری وجود داشته باشند، بدون مشکل قادر به استفاده‌ی از آن خواهید بود.


یک مثال: استفاده از کتابخانه‌ی رمزنگاری اطلاعات Inferno

آخرین نگارش کتابخانه‌ی رمزنگاری اطلاعات Inferno مربوط به NET 4.5.2. است. مراحل ذیل را پس از نصب SDK جدید NET Core 2.0. در خط فرمان طی می‌کنیم:
الف) ایجاد پوشه‌ی UseNET452InNetCore2 و سپس ایجاد یک پروژه‌ی کنسول جدید
dotnet new console

ب) افزودن بسته‌ی نیوگت Inferno به پروژه
 dotnet add package Inferno
این بسته بدون مشکل اضافه می‌شود؛ البته پیام اخطار ذیل نیز صادر خواهد شد (چون مبتنی بر NET 4.6.1. که پیاده سازی کننده‌ی NET Standard 2.0. است، نیست):
 log  : Installing Inferno 1.4.0.
warn : Package 'Inferno 1.4.0' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v2.0'. This package may not be fully compatible with your project.
info : Package 'Inferno' is compatible with all the specified frameworks in project 'D:\UseNET452InNetCore2\UseNET452InNetCore2.csproj'.
info : PackageReference for package 'Inferno' version '1.4.0' added to file 'D:\UseNET452InNetCore2\UseNET452InNetCore2.csproj'.
ابتدا پیام می‌دهد که این بسته ممکن است با NET Core 2.0. سازگار نباشد. سپس عنوان می‌کند که سازگاری کاملی را با پروژه‌ی جاری دارد و بسته را اضافه می‌کند.

ج) استفاده از کتابخانه‌ی Inferno جهت تولید یک عدد تصادفی thread safe
using System;
using SecurityDriven.Inferno;

namespace UseNET452InNetCore2
{
    class Program
    {
        static CryptoRandom random = new CryptoRandom();
        static void Main(string[] args)
        {
            Console.WriteLine($"rnd: {random.NextLong()}");
        }
    }
}

د) اجرای برنامه
در ادامه اگر دستور dotnet run را صادر کنیم، ابتدا اخطاری را صادر می‌کند که این بسته ممکن است دارای قسمت‌هایی باشد که با NET core 2.0. سازگار نیست و سپس خروجی نهایی را بدون مشکل اجرا کرده و نمایش می‌دهد.
 >dotnet run
warning NU1701:  This package may not be fully compatible with your project.
rnd: 8167886599578111106
نظرات مطالب
بهبود امنیت CSP با استفاده از معرفی هش‌های اسکریپت‌های Inline
یک نکته‌ی تکمیلی: استفاده از nonce بجای هش

روش دیگری هم برای مشخص کردن اسکریپت‌ها و شیوه‌نامه‌های inline وجود دارد که nonce نامیده می‌شود. nonce، یک مقدار منحصربفرد است که باید به ازای هر درخواست، یکبار دیگر به صورت خودکار، مجددا تولید شود (اگر ثابت باشد، مهاجم می‌تواند مقدار مشخص آن‌را به اسکریپت‌های خودش اضافه کند):
script-src 'nonce-rAnd0m'
یعنی قبل از هرکاری باید میان‌افزاری که کار تولید CSP Headers فوق را انجام می‌دهد، این مقدار را تولید کند. سپس می‌توان این مقدار را به ویژگی nonce برای مثال تگ اسکریپت، اضافه کرد:
<script nonce="rAnd0m">
</script>
مزیت آن، عدم نیاز به محاسبه و یا درج هش این قطعه اسکریپت، مطابق نکات مطلب جاری است؛ اما باید به صورت پویا به ازای هر درخواستی، مجددا در سمت سرور، تولید شود. همچنین تولید مجدد این مقدار، با کش شدن اطلاعات صفحه در تضاد است و باید به آن دقت داشت.

اگر از کتابخانه‌ی NetEscapades.AspNetCore.SecurityHeaders استفاده می‌کنید، فراخوانی متد WithNonce آن:
builder.AddScriptSrc().Self().WithNonce()
به صورت خودکار هدر مرتبط را تولید می‌کند. همچنین مقدار تولیدی آن‌را نیز در HttpContext.Items، درج می‌کند:
HttpContext.Items["NETESCAPADES_NONCE"]
به این روش، برای مثال یک Tag Helper و یا قسمت دیگری از برنامه که کار مقدار دهی nonce را به عهده دارد، می‌تواند به مقدار خودکار تولید شده‌ی توسط میان‌افزار، دسترسی داشته باشد (ابتدا میان‌افزار CSP اجرا می‌شود و سپس کار رندر صفحه به صورت جداگانه‌ای انجام می‌شود).

یک نکته: هنگام درج مقدار nonce در attributes، به HTML encoding آن دقت داشته باشید؛ این مقدار نباید encode شود (یا تغییر کند).
بازخوردهای پروژه‌ها
انقضای اهراز هویت کاربر پس از رفرش کردن صفحه در پروژه ای مشابه
ابتدا تشکر میکنم بابت ارائه این پروژه.
برای یادگیری من دارم پروژه ای شبیه به پروژه شما میسازم. یعنی به عبارتی مراحل شمارو یکی ، یکی طی میکنم. حالا به جایی رسیدم که هرچقدر هم تلاش کردم متاسفانه پاسخی براش پیدا نکردم.
مشکل من اینه. زمانی که کاربر دکمه ورود رو میزنه و وارد سیستم میشه ، زمانی که صفحه رو رفرش کنه یا از صفحه ای به صفحه‌ی دیگه بره اهراز هویتیش تموم میشه. با اینکه "مرا به خاطر داشته باش" رو هم تیک میزنم ولی باز این مشکل پیش میاد. جالب اینجاست کدهای خودتون به درستی در پروژه خودتون کار میکنه ولی وقتی میارمشون تو پروژه‌ی خودم این مشکل پیش میاد. نمیدونم کجارو اشتباه کردم ولی میدونم یک چیزی کمه.
توجه کنید زمانی که کاربر ورود میکنه مقدار @User.Identity.IsAuthenticated  برابر با true هستش. پس قطعا کاربر ورود میکنه ولی زمانی که صفحه تغییر میکنه این مقدار برابر false میشه.
کدهای کلاس Startup دقیقا همون کدهای شما و من تغییری بهشون ندادم فقط اسم کوکی رو عوض کردم یعنی اینطوری :
public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
            app.MapSignalR();
        }

        private static void ConfigureAuth(IAppBuilder appBuilder)
        {
            const int twoWeeks = 14;
            ProjectObjectFactory.Container.Configure(config => config.For<IDataProtectionProvider>()
                .HybridHttpOrThreadLocalScoped()
                .Use(() => appBuilder.GetDataProtectionProvider()));

            appBuilder.CreatePerOwinContext(
                () => ProjectObjectFactory.Container.GetInstance<ApplicationUserManager>());

            appBuilder.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                ExpireTimeSpan = TimeSpan.FromDays(twoWeeks),
                SlidingExpiration = true,
                CookieName = "MyFirstCms",
                Provider = new CookieAuthenticationProvider
                {
                    OnValidateIdentity =
                            ProjectObjectFactory.Container.GetInstance<IApplicationUserManager>().OnValidateIdentity()
                }
            });

            ProjectObjectFactory.Container.GetInstance<IApplicationRoleManager>()
           .SeedDatabase();

            ProjectObjectFactory.Container.GetInstance<IApplicationUserManager>()
               .SeedDatabase();

            appBuilder.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

            // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
            //appBuilder.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));

            // Enables the application to remember the second login verification factor such as phone or email.
            // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
            // This is similar to the RememberMe option when you log in.
            // appBuilder.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);


            appBuilder.UseFacebookAuthentication(
               appId: "fdsfdsfs",
               appSecret: "fdfsfs");

            appBuilder.UseGoogleAuthentication(
                clientId: "fdsfsdfs",
                clientSecret: "fdsfsf");


        }
    }

این هم کدهای صفحه ورود :

    [HttpPost]
        [AllowAnonymous]
        //[CheckReferrer]
        [ValidateAntiForgeryToken]
        public virtual async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }

            if (!_userManager.CheckUserNameExist(model.UserName,null))
            {
                this.AddErrors("UserName", "نام کاربری یا کلمه عبور وارد شده نادرست است");
                return View(model);
            }
            if (_userManager.CheckIsUserBannedOrDelete(model.UserName))
            {
                this.AddErrors("UserName", "حساب کاربری شما مسدود شده است");
                return View(model);
            }
            if (!_userManager.IsEmailConfirmedByUserNameAsync(model.UserName))
            {
                this.NotyWarning("برای ورود به سایت لازم است حساب خود را فعال کنید");
                return RedirectToAction(MVC.Account.ActionNames.ReceiveActivatorEmail, MVC.Account.Name);
            }


            var result = await _signInManager.PasswordSignInAsync
                (model.UserName.ToLower(), model.Password, model.RememberMe, shouldLockout: true);

            switch (result)
            {
                case SignInStatus.Success:
                    this.NotySuccess("شما با موفقیت وارد سیستم شدید");
                    return RedirectToLocal(returnUrl);
                case SignInStatus.LockedOut:
                    this.NotyError(
                        $"دقیقه دوباره امتحان کنید {_userManager.DefaultAccountLockoutTimeSpan} حساب شما قفل شد ! لطفا بعد از ");
                    return View(model);
                case SignInStatus.Failure:
                    this.NotyError(ModelState.GetListOfErrors());
                    return View(model);
                default:
                    this.NotyError(
                        "در این لحظه امکان ورود به  سابت وجود ندارد . مراتب را با مسئولان سایت در میان بگذارید");
                    return View(model);
            }
        }

ممنون میشم اگر میدونید کجارو اشتباه کردم بهم بگید.
با سپاس
مطالب
بازسازی msdb تخریب شده

حاصل قطع برق و یا یک ری استارت دستی ناصحیح را در نظر بگیرید:



Database 'msdb' cannot be opened. It has been marked SUSPECT by recovery. See the SQL Server errorlog for more information. (Microsoft SQL Server, Error: 926)

Msdb از نوع دیتابیس‌های سیستمی است و نمی‌شود مطابق روال متداول دیتابیس‌های SUSPECT شده آن‌را بازیابی کرد. این روش متداول به صورت زیر است:

ALTER DATABASE DBName SET EMERGENCY
DBCC checkdb('DBname')
ALTER DATABASE DBName SET SINGLE_USER WITH ROLLBACK IMMEDIATE
DBCC CheckDB ('DBName', REPAIR_ALLOW_DATA_LOSS)
ALTER DATABASE DBName SET MULTI_USER

در ابتدای کار دیتابیس در حالت اورژانسی قرار می‌گیرد. بعد وضعیت و میزان تخریب نمایش داده شده، سپس تک کاربره می‌شود. در ادامه به اس کیوال سرور اجازه داده می‌شود که دیتابیس را با هر وضعی (حتی به قیمت از دست رفتن تعدادی رکورد) ترمیم کند و در آخر دیتابیس مجددا به حالت چند کاربره بازگشت داده می‌شود.
این روشی است که سال قبل با قطعی‌های مکرر برق زیاد کاربرد داشت.

اما دیتابیس سیستمی msdb را نمی‌شود در حالت اورژانسی قرار داد؛ بنابراین باید به دنبال راه چاره‌ی دیگری بود. پس از مدتی جستجو در وبلاگ‌های msdn ، راه حل زیر یافت شد و کاملا عملی است (تست شده!) :

روش زیر در مورد اس کیوال سرور 2008 ، 2005 و حتی 2000 نیز قابل استفاده است.
ابتدا خونسردی خودتان را حفظ کنید! الان فقط دیگر با management studio نمی‌توانید دیتابیس‌ها را مرور کنید و همچنین تمام job های تعریف شده شما نابود شده‌اند! اما سرور به کار عادی خودش می‌تواند ادامه دهد. سپس :
الف) تمام سرویس‌های مربوط به اس کیوال سرور را stop کنید. به کنسول سرویس‌ها مراجعه کرده و هر آنچه که در نام آن sql را مشاهده می‌کنید، stop کنید.
ب) با استفاده از خط فرمان، ابتدا به مسیر زیر وارد شوید:
cd "C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Binn\"

و سپس دستور زیر را اجرا نمائید:
start sqlservr.exe -c -m -T3608

به این ترتیب اس کیوال سرور در یک حالت حداقل که بتوان دیتابیس msdb تخریب شده را detach کرد راه اندازی می‌شود. (پرچم 3608 مجوز detach کردن این دیتابیس را می‌دهد)
ج) management studio را اجرا کنید. زمانیکه پنجره کانکت ظاهر می‌شود آن‌را کنسل کرده و در نوار ابزار بالای صفحه روی دکمه new query کیک کنید (چون حالت راه اندازی سرور در حالت تک کاربره است نمی‌خواهیم اتصال دیگری برقرار شود و در کار اخلال کند). با کلیک بر روی new query پنجره connect to server ظاهر می‌شود. در همین پنجره بر روی دکمه options کلیک کرده در برگه connection properties در قسمت connect to database نام master را وارد نمود و اکنون بر روی دکمه connect کلیک نمائید.
ج) سپس دستور زیر را وارد کنید تا دیتابیس msdb را بتوان detach کرد.
Use master;
sp_detach_db 'msdb'

مراحلی که عنوان شد مهم است. اگر به این صورت عمل نکنید با پیغام خطای زیر مواجه خواهید شد:
Cannot detach an opened database when the server is in minimally configured mode

اگر به این خطا برخوردید، یکبار دیگر از صفر شروع کنید. تمام سرویس‌های مرتبط با sql را استاپ کنید (حتی در صورت نیاز کارت شبکه سرور را نیز غیرفعال کنید). و از مرحله الف مجددا شروع نمائید تا حتما حالت تک کاربره‌ی اتصال برقرار شود. (همچنین پنجره‌ی کوئری جدیدی را نیز باز نکنید چون در این حالت فقط و فقط یک اتصال مجاز است)

تا اینجا موفق شدیدم که دیتابیس msdb را detach کنیم. اکنون به پوشه دیتابیس‌ها مراجعه کرده و mdf و ldf این دیتابیس تخریب شده را rename کنید (به هر اسمی که مایل بودید).
د) اکنون نوبت بازسازی مجدد این دیتابیس است.
محتویات فایل instmsdb.sql را که در مسیر C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\install قرار دارد، در پنجره‌ی کوئری تک کاربره‌ای که در مرحله قبل بازکرده‌ایم، copy/paste کرده و دکمه F5 را فشار دهید. پس از مدتی دیتابیس msdb باز سازی شده و مشکل برطرف می‌شود.
ه) اکنون سرور را stop و start کنید یا کلا کامپیوتر سرور را restart‌ کنید تا تمامی سرویس‌های stop شده راه اندازی مجدد شوند.


نظرات مطالب
React 16x - قسمت 29 - احراز هویت و اعتبارسنجی کاربران - بخش 4 - محافظت از مسیرها
فراخوانی history.push به معنای پایان اجرای کدهای این قسمت نیست. به همین جهت یک return history.push نیاز است. نمونه‌اش در اینجا بحث شده: «... همچنین به return ای هم که به همراه متد replace استفاده شده، دقت کنید. کار redirect به یک صفحه‌ی دیگر، به معنای عدم اجرای کدهای پس از آن نیست. بنابراین اگر می‌خواهیم کار این متد با redirect، به پایان برسد، ذکر return الزامی است... »