مطالب
انقیاد داده‌ها در WPF (بخش دوم)
در ادامه‌ی بخش اول از سری انقیاد داده‌ها در WPF، نحوه‌ی انقیاد داده‌ها در لیست را بررسی می‌کنیم.
• One Way Binding بخش اول
• INPC  بخش اول
• Tow Way Binding بخش اول
• List Binding  بخش دوم
• Element Binding بخش دوم
• Data Conversion بخش دوم

انقیاد در لیست List Binding
در ابتدا متدی با نام GetEmployees را با ساختار زیر، به کلاس Employee ایجاد شده‌ی در بخش اول این سری آموزشی، اضافه می‌کنیم: 
public static ObservableCollection<Employee> GetEmployees()
        {
            var employees = new ObservableCollection<Employee>();
            employees.Add(new Employee() { Name = "Mahdi", Title = "Manager" });
            employees.Add(new Employee() { Name = "Nima", Title = "Teacher" });
            employees.Add(new Employee() { Name = "Rahim", Title = "Assistant" });
            employees.Add(new Employee() { Name = "Saeed", Title = "Administrator" });
            return employees;
        }
در کد بالا از نوع داده‌ی جنریک ObservableCollection برای برگردان لیست کارمندان استفاده کردیم.
توجه ObservableCollection در فضای نام System.Collections.ObjectModel قرار دارد.

ObservableCollection  چیست؟
یک مجموعه‌ی پویا (Dynamic Collection) است که بر اثر عملیات‌هایی همچون به‌روز رسانی، حذف و ایجاد اشیاء در آن، یک اعلان صادر می‌شود و View از این اعلان مطلع می‌شود؛ شبیه به کاری که INotifyPropertyChanged انجام می‌دهد. 
در اینجا کلاس Employee با پیاده سازی اینترفیس INPC (معرفی شده در قسمت قبل) به یک کلاس Observable تبدیل شده است. بدین معنی که هر تغییری در وضعیت خصوصیات خود را اعلان می‌کند. با قرار دادن این شیء Observable در یک مجموعه که خود نیز از نوع Observable می‌باشد، از این پس هر تغییری در مجموعه نیز مستقیما View ما را تحت تاثیر قرار می‌دهد.
برای درک بهتر این موضوع در بخش markup، یک Combobox را قرار می‌دهیم:
<ComboBox Name="President" ItemsSource="{Binding}" FontSize="30"
                  Height="50"
                  Width="550">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}"/>
                        <TextBlock Text="{Binding Title}" Margin="5,0,0,0"/>
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
 </ComboBox>
در کد xaml بالا چند نکته اهمیت دارد:
• در Tag مربوط به تعریف Combobox از طریق خصوصیت ItemSource اعلام کردیم که عملیات DataBinding اتفاق خواهد افتاد. پس Combobox ما به منبع داده‌ی پیش فرض در WPF که همان DataContext است مرتبط می‌شود. برای پر کردن منبع داده نیز همانند بخش قبل از طریق سازنده اقدام می‌کنیم.
 private ObservableCollection<Employee> employees;
        public MainWindow()
        {
            InitializeComponent();
            employees = Employee.GetEmployees();
            DataContext = employees;
        }
• برای نمایش عناصر در ComboBox، کار کمی متفاوت‌تر از عملیات انقیاد در یک TextBlock است. در کنترل‌هایی که قرار است لیستی از داده‌ها را پس از عملیات انقیاد نمایش دهند، می‌بایستی قالب نمایش داده‌ها مشخص شود.
حال باید نحوه‌ی نمایش و اعضایی از مجموعه که قرار است، در کنترل به نمایش در آیند مشخص شوند. در اینجا از Combobox.ItemTemplate برای مشخص کردن قالب و همچنین از DataTemplate، برای مشخص کردن داده‌های منتخب ما از مجموعه، استفاده شده است.
بعد از اجرای برنامه اطلاعات نام و عنوان، در Combobox نمایش داده می‌شوند. برای تست ویژگی Observable بودن مجموعه هم کافی است یک دکمه را بر روی صفحه قرار دهید و یک آیتم جدید را به لیست employees واقع در بخش CodeBehind اضافه کنید. مشاهده خواهید کرد که View ما با تغییر منبع داده، بطور اتوماتیک به‌روز می‌شود.

 انقیاد عناصر Element Binding 
در این بخش قصد داریم از یک کنترل به‌عنوان منبع داده استفاده کنیم. کنترل منتخب ما در این مثال یک Slider می‌باشد. در بخش markup کد زیر را اضافه می‌کنیم:
<Grid>
        <StackPanel Orientation="Horizontal">
            <Slider Name="mySlider" Minimum="0" Maximum="100"
                    Width="300"/>
            <TextBlock Margin="5" Text="{Binding Value,ElementName=mySlider}"/>
        </StackPanel>
    </Grid>
Value خصوصیتی است که مقدار Slider را برمی گرداند. پس از اجرای برنامه و حرکت ولوم اسلایدر مشاهده می‌کنید که مقدار جاری اسلایدر در textblock نمایش داده می‌شود.

Data Conversion 
برای درک بهتر مفهوم تبدیل داده در Data Binding با یک مثال کار را شروع می‌کنیم. به کلاس Employee موجود در بخش قبل، یک خصوصیت جدید را به نام تاریخ تولد، اضافه می‌کنیم:
public DateTime BornDate
        {
            get { return _bornDate; }
            set
            {
                _bornDate = value;
                OnPropertyChanged();
            }
        }
و متدی که لیستی از پرسنل را برای ما تولید می‌کرد، به شکل زیر بازنویسی می‌کنیم:
public static ObservableCollection<Employee> GetEmployees()
        {
            var employees = new ObservableCollection<Employee>();
            employees.Add(new Employee()
            { Name = "Mahdi", Title = "Manager", BornDate = DateTime.Parse("2008/8/8") });
            employees.Add(new Employee()
            { Name = "Nima", Title = "Teacher", BornDate = DateTime.Parse("2012/3/14") });
            employees.Add(new Employee()
            { Name = "Rahim", Title = "Assistant", BornDate = DateTime.Parse("2009/11/18") });
            employees.Add(new Employee()
            { Name = "Saeed", Title = "Administrator", BornDate = DateTime.Parse("2014/7/28") });
            return employees;
        }
حال قصد داریم اطلاعات را در یک ListBox، در بخش Markup نمایش دهیم:
<ListBox ItemsSource="{Binding}"
                 BorderThickness="1" >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}" Width="100"/>
                        <TextBlock Text="{Binding Title}" Width="100" Margin="5,0,0,0"/>
                        <TextBlock Text="{Binding BornDate}"  Margin="5,0,0,0"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
 همانطور که قبلا اشاره شد، در نمایش لیست‌ها باید قالب و داده‌های مورد نظر برای نمایش، مشخص شوند.
پس از اجرا، خروجی برنامه به شکل زیر است:
 

 همه چیز همانطور که انتظار داشتیم به نمایش درآمد؛ اما اگر بخواهیم تاریخ میلادی، در زمان نمایش در View، بصورت شمسی نمایش داده شود، چطور؟
عملیات تبدیل داده یا همان Data Conversion در اینجا به کمک ما می‌آید.
به شکل زیر دقت کنید:

در زمانیکه در عملیات Data Binding نوع داده‌ی خصوصیت ما در Source (منبع داده) با نوع داده‌ی خصوصیت ما در target  (کنترل یا View) متفاوت است، به یک مبدل در حین Binding نیاز داریم. این کار را از طریق یک کلاس که اینترفیس IValueConvertor را پیاده سازی کرده است، انجام می‌دهیم.

  Converter به معنای مبدل است و اینجا وظیفه‌ی تبدیل مقدار گرفته شده‌ی از منبع داده را به نوع مورد نظر ما در View، دارد.
در مثال ذکر شده می‌خواهیم تاریخ میلادی موجود در منبع داده را به یک رشته (تاریخ شمسی) تبدیل کنیم و در View نمایش دهیم. (تبدیل نوع داده‌ی میلادی به رشته)
کلاسی را با نام DateConverter ایجاد می‌کنیم و اینترفیس IValueConverter را به شکل زیر پیاده سازی می‌کنیم:
public class DateConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            DateTime date = (DateTime)value;
            PersianCalendar pc = new PersianCalendar();
            var persianDate = string.Format
                ($"{pc.GetYear(date)}/{pc.GetMonth(date)}/{pc.GetDayOfMonth(date)}");
            return persianDate;
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
اینترفیس IValueConverter دو متد دارد:
• Convert جهت تبدیل اطلاعات از مبداء به مقصد 
• ConvertBack برای تبدیل اطلاعات از مقصد به مبداء
در متد Convert همانطور که می‌بینید مقدار تاریخ میلادی ارسال شده، به یک رشته تبدیل شده و بازگردانده می‌شود.

حال برای استفاده از این مبدل باید مراحل زیر انجام شود: 
• اضافه کردن فضای نام مبدل به بخش فضاهای نام در View؛ که در اینجا همان آدرس پروژه‌ی جاری است:
 xmlns:local="clr-namespace:DataConversion"
• ایجاد یک شیء از مبدل و اضافه کردن آن به بخش Resource‌ها در view جاری:
<Window.Resources>
        <local:DateConverter x:Key="MyConverter"/>
    </Window.Resources>
markup مربوط به Resource یک پارامتر می‌گیرد و آن هم Key  است. Key کلید آیتم موجود در دیکشنری Resource است. اینجا کلید را MyConverter تعریف کردیم تا در بخش بعدی به‌راحتی بتوانیم از طریق آن اطلاعات را از Resource بازیابی کنیم.
• ارجاع به Static Resource که در مرحله‌ی قبل مقدار دهی کردیم:
<TextBlock Text="{Binding BornDate,Converter={StaticResource MyConverter}}"  Margin="5,0,0,0"/>
پس از طی مراحل بالا، برنامه را مجددا اجرا کنید. اینبار خروجی به شکل زیر است:

مطالب
توسعه سرویس‌های Angular به روش OOP
یک نکته‌ای که در توسعه سیستم‌ها و نرم افزار‌ها تاکید فراوانی به آن می‌شود استفاده مجدد از کد‌های نوشته شده قبلی است. یعنی تا جای ممکن باید ساختار پروژه به گونه‌ای نوشته شود که از تکرار کد‌ها در جای جای پروژه جلوگیری شود. این مورد به خوبی در زبان‌های شیء‌گرا نظیر #C رعایت می‌شود اما در پروژه‌هایی که مبتنی بر Javascript هستند نظیر angular، باید با استفاده از خاصیت prototype جاوا اسکریپ این مورد را رعایت نمود. در  مقاله  Dr. Axel Rauschmayer،  قدم به قدم و به خوبی روش‌های وراثت در Javascript توضیح داده شده است.
در این پست با روش‌های وراثت در کنترلر‌های انگولاری آشنا شدید. این وراثت محدود به ارث بری scope‌ها می‌شود. اما یکی از بخش‌های بسیار مهم پروژه‌های انگولار نوشتن سرویس‌هایی با قابلیت توسعه مجدد در سایر بخش‌های پروژه می‌باشد. معادل آن، مفهوم Overriding در OOP است. با ذکر مثالی این مورد را با هم بررسی خواهیم کرد.
ابتدا یک سرویس به نام BaseService ایجاد کنید:
angular.module('myApp').service('BaseService', function() {

    var BaseService = function(title) {
        this.title = title;
    };

    BaseService.prototype.getMessage = function() {
        var self = this;
        return 'Hello ' + self.title;
    };

    return BaseService;
});
سرویس بالا دارای سازنده‌ای است که مقدار title باید در اختیار آن قرار گیرد. با استفاده از خاصیت prototype تابعی تعریف می‌کنیم که این تابع خروجی مورد نظر را برای ما تامین خواهد نمود.
حال اگر ماژول و کنترلری جهت نمایش خروجی به صورت زیر ایجاد کنیم:
var app= angular.module('myApp', []);


app.controller('myCtrl', function ($scope,BaseService) {

    var instance = new BaseService('Masoud');
    $scope.title = instance.getMessage();

});
با کدهای Html زیر:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="myApp">
<head>
    <title></title>
</head>
    <body ng-controller="myCtrl">

        <div>
            {{title}}
        </div>

    </body>
<script src="Scripts/jquery-2.1.1.min.js"></script>
<script src="Scripts/angular.js"></script>
<script src="App/app.js"></script>
</html>
در نهایت خروجی به صورت زیر قابل مشاهده است:

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

app.service('ExtService', function(BaseService) {

    var ExtService = function() {
        BaseService.apply(this, arguments);
    };

    ExtService.prototype = new BaseService();
    
    ExtService.prototype.getMessage = function() {
        var self = this;
        return BaseService.prototype.getMessage.apply(this, arguments) + ' From Ext Service';
        
    };

    return ExtService;
});
حال می‌توان کنترلر را به صورت زیر بازنویسی کرد.
app.controller('myCtrl', function ($scope,BaseService , ExtService) {

    var baseInstance = new BaseService('Masoud');
    var extInstance = new ExtService('Dotnettips');
    $scope.title = baseInstance.getMessage() + ' and ' + extInstance.getMessage();

});
در کنترلر بالا هر دو سرویس تزریق شده‌اند. خروجی سرویس دوم متن From Ext Service را نیز به همراه خواهد داشت. پس از اجرای برنامه خروجی زیر قابل مشاهده است:

مطالب
استفاده از Kendo UI TreeView به همراه یک منبع داده راه دور
یکی دیگر از ویجت‌های Kendo UI، ویجت نمایش ساختارهای درختی است به نام TreeView. در ادامه قصد داریم با نحوه‌ی نمایش آن، به کمک اطلاعات JSON دریافتی از سرور آشنا شویم.



ساختار مورد نیاز یک Kendo UI Tree View

فرض کنید قصد دارید نظرات تو در توی مطلبی را توسط Kendo UI Tree View نمایش دهید. مدل خود ارجاع دهنده‌ی آن می‌تواند چنین شکلی را داشته باشد:
namespace KendoUI11.Models
{
    public class BlogComment
    {
        public int Id { set; get; }
 
        public string Body { set; get; }
 
        public int? ParentId { get; set; }
 
        // مخصوص کندو یو آی هستند
        public bool HasChildren { get; set; }
        public string imageUrl { get; set; }
    }
}
سه خاصیت اول این کلاس همواره در تمام کلاس‌های خود ارجاع دهنده حضور دارند؛ شماره ردیف، متن و شماره Id والد احتمالی.
چند خاصیت بعدی مانند HasChildren و imageUrl مخصوص Kendo UI هستند. از imageUrl اختیاری می‌توان جهت نمایش آیکنی در کنار یک آیتم استفاده کرد و HasChildren به این معنا است که آیا گره جاری دارای عناصر فرزندی می‌باشد یا خیر.


تهیه یک منبع داده نمونه

شکل ابتدای مطلب، از طریق منبع داده ذیل تهیه شده‌است:
using System.Collections.Generic;
 
namespace KendoUI11.Models
{
    /// <summary>
    /// منبع داده فرضی جهت سهولت دموی برنامه
    /// </summary>
    public static class BlogCommentsDataSource
    {
        private static readonly IList<BlogComment> _cachedItems;
        static BlogCommentsDataSource()
        {
            _cachedItems = createBlogCommentsDataSource();
        }
 
        public static IList<BlogComment> LatestComments
        {
            get { return _cachedItems; }
        }
 
        /// <summary>
        /// هدف صرفا تهیه یک منبع داده آزمایشی ساده تشکیل شده در حافظه است
        /// </summary>
        private static IList<BlogComment> createBlogCommentsDataSource()
        {
            var list = new List<BlogComment>();
 
            var comment1 = new BlogComment
            {
                Id = 1, Body = "نظر من این است که", HasChildren = true, ParentId = null
            };
            list.Add(comment1);
 
            var comment12 = new BlogComment
            {
                Id = 2, Body = "پاسخی به نظر اول", HasChildren = true, ParentId = 1
            };
            list.Add(comment12);
 
            var comment12A = new BlogComment
            {
                Id = 3, Body = "پاسخی دیگری به نظر اول", HasChildren = false, ParentId = 1
            };
            list.Add(comment12A);
 
            var comment121 = new BlogComment
            {
                Id = 4, Body = "پاسخی به پاسخ به نظر اول", HasChildren = false, ParentId = 2
            };
            list.Add(comment121);
 
            var comment2 = new BlogComment
            {
                Id = 5, Body = "نظر 2", HasChildren = true, ParentId = null, imageUrl= "images/search.png"
            };
            list.Add(comment2);
 
            var comment21 = new BlogComment
            {
                Id = 6, Body = "پاسخ به نظر 2", HasChildren = false, ParentId = 5
            };
            list.Add(comment21);
 
            return list;
        }
    }
}
در اینجا نحوه‌ی مقدار دهی ParentId و HasChildren را جهت تو در تو سازی اطلاعات، مشاهده می‌کنید.
در این لیست دو رکورد، دارای ParentId مساوی null هستند. از این null بودن‌ها جهت کوئری گرفتن و نمایش ریشه‌های TreeView در ادامه استفاده خواهیم کرد.


بازگشت نظرات با فرمت JSON به سمت کلاینت

در ادامه یک کنترلر ASP.NET MVC را مشاهده می‌کنید که توسط اکشن متد GetBlogComments، رکوردهای مورد نظر را با فرمت JSON به سمت کلاینت ارسال می‌کند:
using System.Linq;
using System.Web.Mvc;
using KendoUI11.Models;
 
namespace KendoUI11.Controllers
{
 
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View(); // shows the page.
        }
 
        [HttpGet]
        public ActionResult GetBlogComments(int? id)
        {
            if (id == null)
            {
                //دریافت ریشه‌ها
                return Json(
                    BlogCommentsDataSource.LatestComments
                        .Where(x => x.ParentId == null) // ریشه‌ها
                        .ToList(),
                    JsonRequestBehavior.AllowGet);
            }
            else
            {
                //دریافت فرزندهای یک ریشه
                return Json(
                    BlogCommentsDataSource.LatestComments
                              .Where(x => x.ParentId == id)
                              .ToList(),
                              JsonRequestBehavior.AllowGet);
            }
        }
    }
}
اگر از سمت Kendo UI، مقدار id تنظیم نشود، به معنای درخواست نمایش ریشه‌ها است. در این حالت رکوردها را بر اساس مواردی که دارای ParentId مساوی null هستند، فیلتر خواهیم کرد.
اگر مقدار id به سمت سرور ارسال شود، یعنی کاربر گره و نودی را گشوده‌است. بر این اساس، تمامی فرزندان این گره را یافته و بازگشت می‌دهیم.


کدهای سمت کاربر نمایش Kendo UI Tree View

برای کار با Kendo UI TreeView نیاز است از منبع داده خاصی به نام HierarchicalDataSource به نحو ذیل استفاده کنیم. در قسمت transport آن مشخص می‌کنیم که اطلاعات باید از چه آدرسی خوانده شوند که در اینجا به آدرس اکشن متد  GetBlogComments اشاره می‌کند.
همچنین نیاز است مشخص کنیم کدامیک از خواص مدل بازگردانده شده، همان hasChildren است که در مثال فوق دقیقا به همین نام نیز تنظیم شده‌است.
<!--نحوه‌ی راست به چپ سازی -->
<div class="k-rtl k-header demo-section">
    <div id="my-treeview"></div>
</div>
 
@section JavaScript
{
    <script type="text/javascript">
        $(function () {
            var dataSource = new kendo.data.HierarchicalDataSource({
                transport: {
                    read: {
                        url: "@Url.Action("GetBlogComments", "Home")",
                        dataType: "json",
                        contentType: 'application/json; charset=utf-8',
                        type: 'GET'
                    }
                },
                schema: {
                    model: {
                        id: "Id",
                        hasChildren: "HasChildren"
                    }
                }
            });
 
            $("#my-treeview").kendoTreeView({
                //استفاده از قالب در صورت نیاز
                template: kendo.template($("#treeview-template").html()),
                checkboxes: {
                    checkChildren: false
                },
                dataSource: dataSource,
                dataTextField: "Body",
                //رخدادها
                select: function (e) { console.log("Selecting: " + this.text(e.node)); },
                check: function (e) { console.log("Checkbox changed :: " + this.text(e.node)); },
                change: function (e) { console.log("Selection changed"); },
                collapse: function (e) { console.log("Collapsing " + this.text(e.node)); },
                expand: function (e) { console.log("Expanding " + this.text(e.node)); }
            });
        });
    </script>
 
    <script id="treeview-template" type="text/kendo-ui-template">
        <strong> #: item.Body # </strong>
    </script>
 
    <style scoped>
        .demo-section {
            width: 100%;
            height: 300px;
        }
    </style>
}
 پس از تنظیم remote data source، اکنون نوبت به تعریف و تنظیم kendoTreeView است.
- در ابتدا به ازای هر ردیف این TreeView، از یک قالب استفاده شده‌است. تعریف این مورد اختیاری است. اگر نیاز به سفارشی سازی نحوه‌ی نمایش هر آیتم را داشتید، می‌توان از قالب‌ها استفاده کرد.
- قسمت checkboxes مشخص می‌کند که آیا نیاز است در کنار هر آیتم یک checkbox نیز نمایش داده شود یا خیر.
- dataSource را به HierarchicalDataSource تنظیم کرده‌ایم.
- dataTextField مشخص می‌کند که کدام فیلد دربرگیرنده‌ی متن هر آیتم TreeView است.
- تعدادی رخداد منتسب به TreeView نیز تنظیم شده‌اند که خروجی آن‌ها را در console تصویر ابتدای بحث مشاهده می‌کنید.


کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید.
مطالب
مدیریت هدایت خودکار صفحات در حین خطاهای عملیاتی ای‌جکسی در ASP.NET MVC
قطعه کد زیر را در نظر بگیرید :
     [HttpPost,AjaxOnly, ValidateAntiForgeryToken]
        public virtual JsonResult Create(AddDeviceGroupViewModel deviceGroupViewModel)
        {
        
            if (ModelState.IsNotValid())
            {
                Response.StatusCode = (int)HttpStatusCode.BadRequest;
                return Json(new { success = false, message = ModelState.FirstErrorMessage(), notificationType = NotificationType.Error }, JsonRequestBehavior.AllowGet);
            }
            var result = _deviceGroupService.Add(deviceGroupViewModel);

           // other codes

        }
اکشن متد فوق به صورت زیر فراخوانی می‌شود :
@using (Ajax.BeginForm(MVC.Admin.DeviceGroup.Create(), 
new AjaxOptions { HttpMethod = "POST", OnSuccess = "saveAjaxForm", OnFailure = "SaveFailure" }))
{
// form content
}
و تابع جاوا اسکریپت SaveFailure  به صورت زیر پیاده سازی شده بود :
function SaveFailure(data) {
  
    $("button[type=submit]").prop('disabled', false);
    var result = $.parseJSON(data.responseText);
    showMessage(result.message, result.notificationType);
}
کار تابع فوق، فعال کردن مجدد دکمه ثبت و نمایش پیغامی به کاربر می‌باشد. قطعه کد فوق بدون هیچ مشکلی اجرا می‌شد تا اینکه تمامی اکشن متد‌هایی که به صورت ای‌جکس به صورت اکشن متد فوق پیاده سازی شده بودند، از کار افتادند.
مشکل به وجود آمده حاصل اضافه شدن تگ‌های زیر به وب کانفیگ بود :
<httpErrors errorMode="Custom">
      <remove statusCode="404"/>
      <error statusCode="404" path="/Error/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
بعد از افزودن کد‌های فوق وقتی برنامه به خط زیر می‌رسید، سعی در انتقال به کنترلر Error می‌کرد:
Response.StatusCode = (int)HttpStatusCode.BadRequest;

و در خروجی تنها مقداری که به سمت کاربر برگشت داده می‌شد، مقدار BadRequest بود و خط زیر باعث خطا و توقف برنامه می‌شد:
    var result = $.parseJSON(data.responseText);
با کامنت کامنت کردن کدهای اضافه شده در Web.config مشکل فوق رفع خواهد شد.
همچنین در صورتیکه قصد داشتید تگ‌های فوق را در web.config داشته باشید (جهت هندل کردن صفحات پیدا نشده) می‌توانید از مقدار دهی TrySkipIISCustomError با true این مشکل را رفع کنید.
  Response.TrySkipIisCustomErrors = true;

روشی دیگر:
<system.webServer>
    <httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough" />
نظرات مطالب
معرفی System.Text.Json در NET Core 3.0.
یک نکته‌ی تکمیلی
روش تبدیل/سریالایز سریع یک شیء، به آرایه‌ای از بایت‌های UTF8:
var resultBytes = JsonSerializer.SerializeToUtf8Bytes(data,
                    new JsonSerializerOptions { WriteIndented = false, IgnoreNullValues = true });
و برعکس، تبدیل آرایه‌ای از بایت‌های UTF8 که به روش فوق سریالایز شده به شیء اصلی:
var data = JsonSerializer.Deserialize<T>(new ReadOnlySpan<byte>(resultBytes));
نظرات مطالب
غیرمعتبر شدن کوکی‌های برنامه‌های ASP.NET Core هاست شده‌ی در IIS پس از ری‌استارت آن
آیا به جای استفاده از قطعه کد
services.AddSingleton<IXmlRepository, DataProtectionKeyService>();
services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(serviceProvider =>
{
return new ConfigureOptions<KeyManagementOptions>(options =>
{
var scopeFactory = serviceProvider.GetRequiredService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
options.XmlRepository = scope.ServiceProvider.GetService<IXmlRepository>();
}
});
});

با در نظر گرفتن مستندات، استفاده از کد زیر صحیح است ؟
services.Configure<KeyManagementOptions>(options => options.XmlRepository = new DataProtectionKeyService(services.BuildServiceProvider()));
نظرات مطالب
چگونگی گزارشگیری از Business Objects مانند List توسط StimulSoft
این روش خیلی سرعت گزارش ساختن را افزایش میده منم قبلا یادمه از این روش استفاده می‌کردم

StiReport report = new StiReport();
var _context = new DBTestContext();
var model = _context.Books.ToList();
report.RegBusinessObject("Books", model);
report.Dictionary.SynchronizeBusinessObjects();
report.Dictionary.Synchronize();
report.DesignWithWpf();
کافی هست متد RegBusinessObject  را دوبار صدا بزنید. مثل اینجا
نظرات مطالب
افزودن یک DataType جدید برای نگه‌داری تاریخ خورشیدی - 1

یک try/catch بذار، تا بتونی تاریخ مشکل دار رو پیدا کنی:

var pers = new PersianCalendar();
var date = pers.ToDateTime(this.Year, this.Month, this.Day, this.Hour, this.Minute, this.Second, 0).ToString();
try
{
   return SqlDateTime.Parse(date);
}
catch(Exception ex)
{
  throw new InvalidOperationException("Can't parse "+ date);
}
نظرات مطالب
EF Code First #8
علت خطای این قسمت به علت کد زیر بود
 public ActionResult Index()
{
            NewsContext db = new NewsContext();
            var Query = db.Employee.ToList()
            return View(Query);
}
که با تغییر کد به شکل زیر حل شد 
public ActionResult Index(){
            NewsContext db = new NewsContext();
            var Query = db.Employee.ToList().Where(x=>x.ManagerID==null).ToList();
            return View(Query);
}
نظرات مطالب
مستند سازی ASP.NET Core 2x API توسط OpenAPI Swagger - قسمت ششم - تکمیل مستندات محافظت از API
این روش برای نوشتن دلیل شکست عملیات در response body، با بازنویسی متد HandleChallengeAsync، آزمایش شده:
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Options;

namespace OpenAPISwaggerDoc.Web.Authentication;

public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    private string _failReason;

    public BasicAuthenticationHandler(
        IOptionsMonitor<AuthenticationSchemeOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder,
        ISystemClock clock)
        : base(options, logger, encoder, clock)
    {
    }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        if (!Request.Headers.ContainsKey("Authorization"))
        {
            _failReason = "Missing Authorization header";
            return Task.FromResult(AuthenticateResult.Fail(_failReason));
        }

        try
        {
            var authenticationHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
            var credentialBytes = Convert.FromBase64String(authenticationHeader.Parameter);
            var credentials = Encoding.UTF8.GetString(credentialBytes).Split(':');
            var username = credentials[0];
            var password = credentials[1];

            if (string.Equals(username, "DNT", StringComparison.Ordinal) &&
                string.Equals(password, "123", StringComparison.Ordinal))
            {
                var claims = new[] { new Claim(ClaimTypes.NameIdentifier, username) };
                var identity = new ClaimsIdentity(claims, Scheme.Name);
                var principal = new ClaimsPrincipal(identity);
                var ticket = new AuthenticationTicket(principal, Scheme.Name);
                return Task.FromResult(AuthenticateResult.Success(ticket));
            }

            _failReason = "Invalid username or password";
            return Task.FromResult(AuthenticateResult.Fail(_failReason));
        }
        catch
        {
            _failReason = "Invalid Authorization header";
            return Task.FromResult(AuthenticateResult.Fail(_failReason));
        }
    }

    protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
    {
        await base.HandleChallengeAsync(properties);
        if (Response.StatusCode == StatusCodes.Status401Unauthorized &&
            !string.IsNullOrWhiteSpace(_failReason))
        {
            Response.Headers.Add("WWW-Authenticate", _failReason);
            Response.ContentType = "application/json";
            await WriteProblemDetailsAsync(_failReason);
        }
    }

    private Task WriteProblemDetailsAsync(string detail)
    {
        var problemDetails = new ProblemDetails { Detail = detail, Status = Context.Response.StatusCode };
        var result = new ObjectResult(problemDetails)
                     {
                         ContentTypes = new MediaTypeCollection(),
                         StatusCode = problemDetails.Status,
                         DeclaredType = problemDetails.GetType(),
                     };
        var executor = Context.RequestServices.GetRequiredService<IActionResultExecutor<ObjectResult>>();
        var routeData = Context.GetRouteData() ?? new RouteData();
        var actionContext = new ActionContext(Context, routeData, new ActionDescriptor());
        return executor.ExecuteAsync(actionContext, result);
    }
}