نظرات مطالب
اعمال تزریق وابستگی‌ها به مثال رسمی ASP.NET Identity
ممنون از مطالب شما 
 اگر بخواهیم از IApplicationRoleManager و IApplicationUserManager  یا به طور کلی از ایترفیس‌ها در  AuthorizeAttribute سفارشی (یا فیلتر هایی) که ایجاد کرده ایم   استفاده کنیم ، تنظیمات strucutremap به چه صورت خواهد بود.

 public class CustomAuthorizeAttribute : AuthorizeAttribute
    {

        
        public IApplicationRoleManager _roleManager { get; set; }
        
        public IApplicationUserManager _userManager { get; set; }


        public CustomAuthorizeAttribute(IApplicationUserManager userManager,
                                    IApplicationRoleManager roleManager)
        {
            _userManager = userManager;
            _roleManager = roleManager;
        }
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            // Put your custom logic here, returning true for success and false for failure,
            // or return base.AuthorizeCore(httpContext) to defer to the base implementation
            IPrincipal user = httpContext.User;
            IIdentity identity = user.Identity;

            if (!identity.IsAuthenticated)
            {
                return false;
            }

            bool isAuthorized = true;
            // TODO: perform custom authorization against the App
            var qry = _userManager.Users.Where(u => u.UserName == identity.Name).ToList();

            return isAuthorized;
        }
    }

فایل‌های پروژه‌ها
DNTViewer.V1.2.zip
- بهبود کارآیی و سرعت نمایش لیست‌های طولانی
- نمایش لیست آخرین موارد در ابتدای کار برنامه
مطالب دوره‌ها
متدهای الحاقی و ترکیب کننده‌های اعمال غیرهمزمان
تعدادی متد جدید در دات نت 4.5 جهت ترکیب و کار با Taskها اضافه شده‌اند. نمونه‌ای از آن‌را در قسمت‌های قبل با معرفی متد WhenAll مشاهده کردید. در ادامه قصد داریم این متدها را  بیشتر بررسی کنیم.


متد WhenAll
کار آن ترکیب تعدادی Task است و اجرای آن‌ها. تنها زمانی خاتمه می‌یابد که کلیه‌ی Taskهای معرفی شده به آن خاتمه یافته باشند. هدف از آن اجرای همزمان و مستقل چندین Task است. برای مثال دریافت چندین فایل به صورت همزمان از اینترنت.
همچنین باید دقت داشت که در اینجا، هر Task کاری به نتایج Taskهای دیگر ندارد و کاملا مستقل اجرا می‌شود. اگر نیاز است Taskها مستقل اجرا شوند، از همان روش سریالی اجرای Taskها، توسط معرفی هر کدام به کمک await استفاده کنید.
به علاوه اگر در این بین استثنایی وجود داشته باشد، تنها پس از پایان عملیات تمام Taskها بازگشت داده می‌شود. این استثناء نیز از نوع Aggregate Exception است.
using System.Linq;
using System.Threading.Tasks;

namespace Async07
{
    public class EggBoiler
    {
        private const int BoilingTimeMs = 200;

        private static Task boilEgg()
        {
            var bolingTask = Task.Run(() =>
            {
                Task.Delay(BoilingTimeMs);
            });
            return bolingTask;
        }

        public async Task BoilEggsSequentialAsync(int count)
        {
            for (var i = 0; i < count; i++)
            {
                await boilEgg();
            }
        }

        public async Task BoilEggsSimultaneousAsync(int count)
        {
            var tasksList = from egg in new[] { 1, 2, 3, 4, 5 }
                            select boilEgg();
            await Task.WhenAll(tasksList);
            // ...
        }
    }
}
در این مثال عمل پختن تخم مرغ را در یک مدت زمان مشخصی ملاحظه می‌کنید. در متد BoilEggsSequentialAsync، پختن تخم مرغ‌ها، ترتیبی است. ابتدا مورد اول انجام می‌شود و پس از پایان آن، مورد دوم و الی آخر. در اینجا اگر نیاز باشد، می‌توان از نتیجه‌ی عملیات قبلی، در عملیات بعدی استفاده کرد.
 اما در متد BoilEggsSimultaneousAsync به علت بکارگیری Task.WhenAll پختن تمام تخم مرغ‌های مدنظر همزمان آغاز می‌شود و تا پایان عملیات (پخته شدن تمام تخم مرغ‌ها) صبر خواهد شد.


متد WhenAny

در حالت استفاده از متد WhenAny، هر کدام از Taskهای در حال پردازش که خاتمه یابند، کل عملیات خاتمه خواهد یافت. فرض کنید نیاز دارید تا دمای کنونی هوای منطقه‌ی خاصی را از چند وب سرویس مختلف دریافت کنید. می‌توان در این حالت تمام این‌ها را توسط WhenAny ترکیب کرد و هر کدام که زودتر خاتمه یابد، عملیات را پایان خواهد داد.
    public class Downloader
    {
        private Task<string> downloadTask(string url)
        {
            return new WebClient().DownloadStringTaskAsync(url);
        }

        public async Task<int> GetTemperature()
        {
            var sites = new[]
            {
                "http://www.site1.com/svc",
                "http://www.site2.com/svc",
                "http://www.site3.com/svc",
            };
            var tasksList = from site in sites
                            select downloadTask(site);
            try
            {
                var finishedTask = await Task.WhenAny(tasksList);
                var result = await finishedTask;

            }
            catch (Exception ex)
            {

            }

            // todo: process result, get temperature
            return 10; // for example.
        }
    }
در اینجا نحوه‌ی استفاده از WhenAny را مشاهده می‌کنید. نکته‌ی مهم این مثال، استفاده از await دوم بر روی Task بازگشت داده شده‌است. این مساله از این لحاظ مهم است که Task بازگشت داده شده الزامی ندارد که حتما با موفقیت پایان یافته باشد. فراخوانی await بر روی نتیجه‌ی آن سبب خواهد شد تا اگر استثنایی در این بین رخ داده باشد، قابل دریافت و پردازش شود.
در این حالت اگر نیاز بود وضعیت سایر Taskها، مثلا در صورت شکست آن‌ها، بررسی شوند، می‌توان از یکی از دو قطعه کد زیر استفاده کرد:
            foreach (var task in tasksList)
            {
                var ignored = task.ContinueWith(
                    t => Console.WriteLine(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
            }

            // or
            foreach (var task in tasksList)
            {
                var ignored = task.ContinueWith(
                    t =>
                    {
                        if (t.IsFaulted)
                            Console.WriteLine(t.Exception);
                    });
            }

کاربرد دیگر WhenAny زمانی است که برای مثال می‌خواهید تعداد زیادی Url را پردازش کنید، اما نمی‌خواهید برای نمایش اطلاعات، تا پایان عملیات تمامی آن‌ها مانند WhenAll صبر کنید. می‌خواهید به محض پایان کار یکی از Taskها، عملیات نمایش نتیجه‌ی آن‌را انجام دهید:
        public async Task ShowTemperatures()
        {
            var sites = new[]
            {
                "http://www.site1.com/svc",
                "http://www.site2.com/svc",
                "http://www.site3.com/svc",
            };
            var tasksList = sites.Select(site => downloadTask(site)).ToList();

            while (tasksList.Any())
            {
                try
                {
                    var tempTask = await Task.WhenAny(tasksList);
                    tasksList.Remove(tempTask);

                    var result = await tempTask;
                    //todo: show result
                }
                catch(Exception ex) { }
            }
        }
در اینجا در یک حلقه، هر Taskایی که زودتر پایان یابد، نمایش داده شده و سپس از لیست وظایف حذف می‌شود. در ادامه مجددا یک await روی آن انجام خواهد شد تا استثنای احتمالی آن بروز کند. سپس اگر مشکلی نبود، می‌توان نتیجه را نمایش داد.

کاربرد سوم WhenAny کنترل تعداد وظایف همزمان است. برای مثال اگر قرار است هزاران تصویر از اینترنت دریافت شوند، نباید تمام وظایف را یکجا راه اندازی کرد. شاید نیاز باشد هربار فقط 15 وظیفه‌ی همزمان عمل کنند و نه بیشتر. در این حالت، مثال قبلی دارای یک حلقه‌ی کنترل کننده tasksList ارائه شده خواهد شد. هر بار تعداد معینی وظیفه به tasksList اضافه و پردازش می‌شوند و این روند تا پایان کار تعداد Urlها ادامه خواهد یافت (یک Take و Skip است؛ مانند صفحه بندی اطلاعات).


متدهای Run و FromResult

متد Task.Run اضافه شده در دات نت 4.5 به این معنا است که می‌خواهید Task ایجاد شده بر روی Thread pool اجرا شود. پارامتر آن می‌تواند یک delegate یا عبارت lambda و یا حتی یک Task باشد. خروجی آن نیز یک Task است و به همین جهت با async و await سی شارپ 5 سازگاری بهتری دارد.
استفاده از Task.Run نسبت به عملیات Threading متداول کارآیی بهتری دارد، زیرا ایجاد Threadهای جدید زمانبر بوده و زمانیکه به صورت خودکار از Thread pool استفاده می‌شود، تا حد امکان، استفاده‌ی مجدد از تردهای بیکار در حال حاضر، مدنظر است.

متد Task.FromResult کار بازگشت یک Task را از نتایج متدهای مختلف فراهم می‌کند. فرض کنید یک متد async تعریف کرده‌اید که خروجی آن Task of T است. در اینجا اگر داخل متد، از یک متد معمولی که یک عدد int را ارائه می‌دهد استفاده کنیم، با استفاده از Task.FromResult بلافاصله می‌توان یک Task of int را بازگشت داد.


متد Delay

پیشتر برای به خواب فرو بردن یک ترد از متد Thread.Sleep استفاده می‌شد. کار Thread.Sleep بلاک کردن ترد جاری است. در دات نت 4.5، بجای آن باید از Task.Delay استفاده شود که یک مکانیزم غیر قفل کننده را جهت صبر کردن به همراه بازگشت یک Task، ارائه می‌دهد.
یکی از کاربردهای Delay منهای صبر کردن تا مدت زمانی مشخص، ایجاد مکانیزم timeout است. برای مثال حالت Task.WhenAny را درنظر بگیرید. اگر در اینجا timeout مدنظر ما 3 ثانیه باشد، می‌توان یکی از Taskها را Task.Delay با آرگومان مساوی 3000 معرفی کرد. اگر هر کدام از taskهای تعریف شده زودتر از 3 ثانیه پایان یافتند که بسیار خوب؛ در غیر اینصورت Task.Delay معرفی شده کار را تمام می‌کند.


متد Yield
متد Task.Yield بسیار شبیه به متد قدیمی DoEvents است که از آن برای اجازه دادن به سایر اعمال جهت اجرا، در بین یک عمل طولانی، استفاده می‌شد.


متد ConfigureAwait

به صورت پیش فرض ادامه یک عملیات همزمان، بر روی ترد ایجاد کننده‌ی آن اجرا می‌شود. برای نمونه اگر یک عملیات async در ترد UI آغاز شود، نتیجه‌ی آن نیز در همان ترد UI بازگشت داده می‌شود. به این ترتیب دیگر نیازی نخواهد بود تا نگرانی در مورد نحوه‌ی دسترسی به مقدار آن توسط عناصر UI داشته باشیم.
اگر به این مساله اهمیت نمی‌دهید، برای مثال اگر اعمال در حال انجام، کاری به عناصر UI ندارند، از متد ConfigureAwait با پارامتر false بر روی یک task پیش از فراخوانی await بر روی آن، استفاده کنید.
 byte [] buffer = new byte[0x1000];
int numRead;
while((numRead = await source.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
{
  await source.WriteAsync(buffer, 0, numRead).ConfigureAwait(false);
}
این مثال در طی یک حلقه، هر بار مقدار کوچکی از منبع ارائه شده به آن را می‌خواند. در اینجا تعداد await cycles قابل توجهی وجود دارند. در هر سیکل نیز از دو فراخوانی async استفاده می‌شود؛ یکی برای انجام عملیات و دیگری برای بازگشت نتیجه به Synchronization Context آغاز کننده آن. با استفاده از ConfigureAwait false زمان اجرای این حلقه به شدت بهبود خواهد یافت و کوتاه‌تر خواهد شد؛ زیرا فاز هماهنگی آن با Synchronization Context حذف می‌شود.



به صورت خلاصه در سی شارپ 5

- بجای task.Wait قدیمی، از await task برای صبر کردن تا پایان یک task استفاده کنید.
- بجای task.Result جهت دریافت یک نتیجه‌ی یک task از await task کمک بگیرید.
- بجای Task.WaitAll از await Task.WhenAll و بجای Task.WaitAny از await Task.WhenAny استفاده نمائید.
- همچنین Thread.Sleep در اعمال async با await Task.Delay جایگزین شده‌است.
- در اعمال غیرهمزمان همیشه متد ConfigureAwait false را بکار بگیرید، مگر اینکه به Context نهایی آن واقعا نیاز داشته باشید.
و برای ایجاد یک Task جدید از Task.Run یا TaskFactory.StartNew استفاده نمائید.
مطالب
استفاده از Kendo UI templates
در مطلب «صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid» در انتهای بحث، ستون IsAvailable به صورت زیر تعریف شد:
columns: [
               {
                   field: "IsAvailable", title: "موجود است",
                   template: '<input type="checkbox" #= IsAvailable ? checked="checked" : "" # disabled="disabled" ></input>'
                }
]
Templates، جزو یکی از پایه‌های Kendo UI Framework هستند و توسط آن‌ها می‌توان قطعات با استفاده‌ی مجدد HTML ایی را طراحی کرد که قابلیت یکی شدن با اطلاعات جاوا اسکریپتی را دارند.
همانطور که در این مثال نیز مشاهده می‌کنید، قالب‌های Kendo UI از Hash (#) syntax استفاده می‌کنند. در اینجا قسمت‌هایی از قالب که با علامت # محصور می‌شوند، در حین اجرا، با اطلاعات فراهم شده جایگزین خواهند شد.
برای رندر مقادیر ساده می‌توان از # =# استفاده کرد. از # :# برای رندر اطلاعات HTML-encoded کمک گرفته می‌شود و #  # برای رندر کدهای جاوا اسکریپتی کاربرد دارد. از حالت HTML-encoded برای نمایش امن اطلاعات دریافتی از کاربران و جلوگیری از حملات XSS استفاده می‌شود.
اگر در این بین نیاز است # به صورت معمولی رندر شود، در حالت کدهای جاوا اسکریپتی به صورت #\\ و در HTML ساده به صورت #\ باید مشخص گردد.


مثالی از نحوه‌ی تعریف یک قالب Kendo UI

    <!--دریافت اطلاعات از منبع محلی-->
    <script id="javascriptTemplate" type="text/x-kendo-template">
        <ul>
            # for (var i = 0; i < data.length; i++) { #
            <li>#= data[i] #</li>
            # } #
        </ul>
    </script>

    <div id="container1"></div>
    <script type="text/javascript">
        $(function () {
            var data = ['User 1', 'User 2', 'User 3'];
            var template = kendo.template($("#javascriptTemplate").html());
            var result = template(data); //Execute the template
            $("#container1").html(result); //Append the result
        });
    </script>
این قالب ابتدا در تگ script محصور می‌شود و سپس نوع آن مساوی text/x-kendo-template قرار می‌گیرد. در ادامه توسط یک حلقه‌ی جاوا اسکریپتی، عناصر آرایه‌ی فرضی data خوانده شده و با کمک Hash syntax در محل‌های مشخص شده قرار می‌گیرند.
در ادامه باید این قالب را رندر کرد. برای این منظور یک div با id مساوی container1 را جهت تعیین محل رندر نهایی اطلاعات مشخص می‌کنیم. سپس متد kendo.template بر اساس id قالب اسکریپتی تعریف شده، یک شیء قالب را تهیه کرده و سپس با ارسال آرایه‌ای به آن، سبب اجرای آن می‌شود. خروجی نهایی، یک قطعه کد HTML است که در محل container1 درج خواهد شد.
همانطور که ملاحظه می‌کنید، متد kendo.template، نهایتا یک رشته را دریافت می‌کند. بنابراین همینجا و به صورت inline نیز می‌توان یک قالب را تعریف کرد.


کار با منابع داده راه دور

فرض کنید مدل برنامه به صورت ذیل تعریف شده‌است:
namespace KendoUI04.Models
{
    public class Product
    {
        public int Id { set; get; }
        public string Name { set; get; }
        public decimal Price { set; get; }
        public bool IsAvailable { set; get; }
    }
}
و لیستی از آن توسط یک ASP.NET Web API کنترلر، به سمت کاربر ارسال می‌شود:
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using KendoUI04.Models;

namespace KendoUI04.Controllers
{
    public class ProductsController : ApiController
    {
        public IEnumerable<Product> Get()
        {
            return ProductDataSource.LatestProducts.Take(10);
        }
    }
}
در سمت کاربر و در View برنامه خواهیم داشت:
    <!--دریافت اطلاعات از سرور-->
    <div>
        <div id="container2"><ul></ul></div>
    </div>

    <script id="template1" type="text/x-kendo-template">
        <li> #=Id# - #:Name# - #=kendo.toString(Price, "c")#</li>
    </script>

    <script type="text/javascript">
        $(function () {
            var producatsTemplate1 = kendo.template($("#template1").html());

            var productsDataSource = new kendo.data.DataSource({
                transport: {
                    read: {
                        url: "api/products",
                        dataType: "json",
                        contentType: 'application/json; charset=utf-8',
                        type: 'GET'
                    }
                },
                error: function (e) {
                    alert(e.errorThrown);
                },
                change: function () {
                    $("#container2 > ul").html(kendo.render(producatsTemplate1, this.view()));
                }
            });
            productsDataSource.read();
        });
    </script>
ابتدا یک div با id مساوی container2 جهت تعیین محل نهایی رندر قالب template1 در صفحه تعریف می‌شود.
هرچند خروجی دریافتی از سرور نهایتا یک آرایه از اشیاء Product است، اما در template1 اثری از حلقه‌ی جاوا اسکریپتی مشاهده نمی‌شود. در اینجا چون از متد kendo.render استفاده می‌شود، نیازی به ذکر حلقه نیست و به صورت خودکار، به تعداد عناصر آرایه دریافتی از سرور، قطعه HTML قالب را تکرار می‌کند.
در ادامه برای کار با سرور از یک Kendo UI DataSource استفاده شده‌است. قسمت transport/read آن، کار تعریف محل دریافت اطلاعات را از سرور مشخص می‌کند. رویدادگران change آن اطلاعات نهایی دریافتی را توسط متد view در اختیار متد kendo.render قرار می‌دهد. در نهایت، قطعه‌ی HTML رندر شده‌ی نهایی حاصل از اجرای قالب، در بین تگ‌های ul مربوط به container2 درج خواهد شد.
رویدادگران change زمانیکه data source، از اطلاعات راه دور و یا یک آرایه‌ی جاوا اسکریپتی پر می‌شود، فراخوانی خواهد شد. همچنین مباحث مرتب سازی اطلاعات، صفحه بندی و تغییر صفحه، افزودن، ویرایش و یا حذف اطلاعات نیز سبب فراخوانی آن می‌گردند. متد view ایی که در این مثال فراخوانی شد، صرفا در روال رویدادگردان change دارای اعتبار است و آخرین تغییرات اطلاعات و آیتم‌های موجود در data source را باز می‌گرداند.


یک نکته‌ی تکمیلی: فعال سازی intellisense کدهای جاوا اسکریپتی Kendo UI

اگر به پوشه‌ی اصلی مجموعه‌ی Kendo UI مراجعه کنید، یکی از آن‌ها vsdoc نام دارد که داخل آن فایل‌های min.intellisense.js و vsdoc.js مشهود هستند.
اگر از ویژوال استودیوهای قبل از 2012 استفاده می‌کنید، نیاز است فایل‌های vsdoc.js متناظری را به پروژه اضافه نمائید؛ دقیقا در کنار فایل‌های اصلی js موجود. اگر از ویژوال استودیوی 2012 و یا بالاتر استفاده می‌کنید باید از فایل‌های intellisense.js متناظر استفاده کنید. برای مثال اگر از kendo.all.min.js کمک می‌گیرید، فایل متناظر با آن kendo.all.min.intellisense.js خواهد بود.
بعد از اینکار نیاز است فایلی به نام references.js_ را به پوشه‌ی اسکریپت‌های خود با این محتوا اضافه کنید (برای VS 2012 به بعد):
/// <reference path="jquery.min.js" />
/// <reference path="kendo.all.min.js" />
نکته‌ی مهم اینجا است که این فایل به صورت پیش فرض از مسیر Scripts/_references.js/~ خوانده می‌شود. برای اضافه کردن مسیر دیگری مانند js/_references.js/~ باید آن‌را به تنظیمات ذیل اضافه کنید:
 Tools menu –> Options -> Text Editor –> JavaScript –> Intellisense –> References
گزینه‌ی Reference Group را به (Implicit (Web تغییر داده و سپس مسیر جدیدی را اضافه نمائید.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید:
KendoUI04.zip
نظرات مطالب
Senior Developer به چه کسی گفته می شود؟
اصولا بهترین روش برای تشخیص اینکه شما در کدام سطح قرار دارید این است که خودتون به مسیری که طی کردید تا به جایگاه فعلی برسید یک نگاه دقیق داشته باشید. اصولا اکثر برنامه نویسانی که در شرکت‌های نرم افزاری مشغول به کار هستند در سطح Junior یا Mid Level هستند. در این پست تمرکز اصلی برای تشریح سطح برنامه نویس ارشد بود. متاسفانه در اکثر آگهی‌های استخدام شاهد این هستیم که برنامه نویس باید با انبوهی از تکنولوژی‌های آشنایی داشته باشد. مثلا حتما در آگهی‌ها دیده اید که برنامه نویس Asp.Net MVC مسلط به JQuery و HTML و CSS و JavaScript و EF و.... بعنی باید برنامه نویس هم در لایه‌های سطح پایین نظیر Business  و سرویس برنامه نویسی کند و هم به عنوان یک Front- End کار.
به صورت معمول زمانی که برنامه نویسان خودشون را در جایگاه Senior Developer نمی‌بینند از واژه Software Developer استفاده می‌کنند.
مطالب
آشنایی با Refactoring - قسمت 1

کارهای سورس باز قابل توجهی از برنامه نویس‌های ایرانی یافت نمی‌شوند؛ عموما کارهای ارائه شده در حد یک سری مثال یا کتابخانه‌های کوچک است و در همین حد. یا گاهی هم انگشت شمار پروژه‌هایی کامل. مثل یک وب سایت یا یک برنامه نصفه نیمه دبیرخانه و امثال آن. این‌ها هم خوب است از دیدگاه به اشتراک گذاری اطلاعات، ایده‌ها و هم ... یک مزیت دیگر را هم دارد و آن این است که بتوان کیفیت عمومی کد نویسی را حدس زد.
اگر کیفیت کدها رو بررسی ‌کنید به یک نتیجه‌ی کلی خواهید رسید: "عموم برنامه نویس‌های ایرانی (حداقل این‌هایی که چند عدد کار سورس باز به اشتراک گذاشته‌اند) با مفهومی به نام Refactoring هیچگونه آشنایی ندارند". مثلا یک برنامه‌ی WinForm تهیه کرده‌اند و کل سورس برنامه همان چند عدد فرم برنامه است و هر فرم بالای 3000 سطر کد دارد. دوستان عزیز! به این می‌گویند «فاجعه‌ای به نام کدنویسی!» صاحب اول و آخر این نوع کدها خودتان هستید! شاید به همین جهت باشد که عمده‌ی پروژه‌های سورس باز پس از اینکه برنامه نویس اصلی از توسعه‌ی آن دست می‌کشد، «می‌میرند». چون کسی جرات نمی‌کند به این کدها دست بزند. مشخص نیست الان این قسمت را که تغییر دادم، کجای برنامه به هم ریخت. تستی ندارند. ساختاری را نمی‌توان از آن‌ها دریافت. منطق قسمت‌های مختلف برنامه از هم جدا نشده است. برنامه یک فرم است با چند هزار سطر کد در یک فایل! کار شما شبیه به کد اسمبلی چند هزار سطری حاصل از decompile یک برنامه که نباید باشد!
به همین جهت قصد دارم یک سری «ساده» Refactoring را در این سایت ارائه دهم. روی سادگی هم تاکید کردم، چون اگر عموم برنامه نویس‌ها با همین موارد به ظاهر ساده آشنایی داشتند، کیفیت کد نویسی بهتری را می‌شد در نتایج عمومی شده، شاهد بود.
این مورد در راستای نظر سنجی انجام شده هم هست؛ درخواست مقالات خالص سی شارپ در صدر آمار فعلی قرار دارد.



Refactoring چیست؟

Refactoring به معنای بهبود پیوسته کیفیت کدهای نوشته شده در طی زمان است؛ بدون ایجاد تغییری در عملکرد اصلی برنامه. به این ترتیب به کدهایی دست خواهیم یافت که قابلیت آزمون پذیری بهتری داشته، در مقابل تغییرات مقاوم و شکننده نیستند و همچنین امکان به اشتراک گذاری قسمت‌هایی از آن‌ها در پروژه‌های دیگر نیز میسر می‌شود.


قسمت اول - مجموعه‌ها را کپسوله کنید

برای مثال کلاس‌های ساده زیر را در نظر بگیرید:

namespace Refactoring.Day1.EncapsulateCollection
{
public class OrderItem
{
public int Id { set; get; }
public string Name { set; get; }
public int Amount { set; get; }
}
}

using System.Collections.Generic;

namespace Refactoring.Day1.EncapsulateCollection
{
public class Orders
{
public List<OrderItem> OrderItems { set; get; }
}
}

نکته اول: هر کلاس باید در داخل یک فایل جدا قرار گیرد. «لطفا» یک فایل درست نکنید با 50 کلاس داخل آن. البته اگر باز هم یک فایل باشد که بتوان 50 کلاس را داخل آن مشاهده کرد که چقدر هم عالی! نه اینکه یک فایل باشد تا بعدا 50 کلاس را با Refactoring از داخل آن بیرون کشید!

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

Error, Certainty 95, for Do Not Expose Generic Lists

بله. لیست‌های جنریک را نباید به همین شکل در اختیار مصرف کننده قرار داد؛ چون به این صورت هر کاری را می‌توانند با آن انجام دهند، مثلا کل آن را تعویض کنند، بدون اینکه کلاس تعریف کننده آن از این تغییرات مطلع شود.
پیشنهاد FxCop این است که بجای List از Collection یا IList و موارد مشابه استفاده شود. اگر اینکار را انجام دهیم اینبار به خطای زیر خواهیم رسید:

Warning, Certainty 75, for Collection Properties Should Be ReadOnly

FxCop پیشنهاد می‌دهد که مجموعه تعریف شده باید فقط خواندنی باشد.

چکار باید کرد؟
بجای استفاده از List جهت ارائه مجموعه‌ها، از IEnumerable استفاده کنید و اینبار متدهای Add و Remove اشیاء به آن‌را به صورت دستی تعریف نمائید تا بتوان از تغییرات انجام شده بر روی مجموعه ارائه شده، در کلاس اصلی آن مطلع شد و امکان تعویض کلی آن‌را از مصرف کننده گرفت. برای مثال:

using System.Linq;
using System.Collections.Generic;

namespace Refactoring.Day1.EncapsulateCollection
{
public class Orders
{
private int _orderTotal;
private List<OrderItem> _orderItems;

public IEnumerable<OrderItem> OrderItems
{
get { return _orderItems; }
}

public void AddOrderItem(OrderItem orderItem)
{
_orderTotal += orderItem.Amount;
_orderItems.Add(orderItem);
}

public void RemoveOrderItem(OrderItem orderItem)
{
var order = _orderItems.Find(o => o == orderItem);
if (order == null) return;

_orderTotal -= orderItem.Amount;
_orderItems.Remove(orderItem);
}
}
}


اکنون اگر برنامه را مجددا با fxCop آنالیز کنیم، دو خطای ذکر شده دیگر وجود نخواهند داشت. اگر این تغییرات صورت نمی‌گرفت، امکان داشتن فیلد _orderTotal غیر معتبری در کلاس Orders به شدت بالا می‌رفت. زیرا مصرف کننده مجموعه OrderItems می‌توانست به سادگی آیتمی را به آن اضافه یا از آن حذف کند، بدون اینکه کلاس Orders از آن مطلع شود یا اینکه بتواند عکس العمل خاصی را بروز دهد.


نظرات مطالب
تبدیل یک View به رشته و بازگشت آن به همراه نتایج JSON حاصل از یک عملیات Ajax ایی در ASP.NET MVC
بهتر است کدهای زیر:
$("#divAllComments").html(jsData.data + $("#divAllComments").html());

با این کد جایگزین شود:
$("#divAllComments").append(jsData.data);

تفاوت کد بالا با پایین در اینست که در کد بالا تمام محتوای dom باید دوباره پردازش و جایگزین شود در حالیکه کد پایین تنها html دریافتی پردازش و به انتهای المنت مورد نظر اضافه می‌شود.
در سیستمهایی که میزان ارسال کامنت زیاد باشد (مانند شبکه‌های اجتماعی) کد بالا کارایی صفحه را به شدت پایین می‌آورد.
مطالب
پیش پردازنده ها Preprocessors
احتمالا شما با پیش پردازنده ها کم و بیش آشنایی دارید؛ برای آشنایی با پیش پردازنده‌های موجود در سی شارپ می‌توانید به این آدرس بروید.
البته این پیش پردازنده‌ها به قدرتمندی سایر پیش پردازنده هایی که در زبان‌های دیگر مانند سی یا سی پلاس پلاس دیده‌اید نیستند. مثلا نمی‌توانند مقدار دیگری جز مقدارهای بولین دریافت کنند، یا از حافظه‌ی مصرفی استفاده کنند. همچنین باید به یاد داشته باشید که حتما باید قبل از شروع کد، از پیش پردازنده‌های استفاده کنید.

برای تعریف یک سمبل symbol می‌توانید از پیش پردازنده‌ی define# استفاده و برای حذف آن هم از undef# استفاده کنید. رسم هست که سمبل‌ها با حروف بزرگ تعریف شوند.
عبارات #if,#else,#elif,#endif هم عبارات شرطی هستند که می‌توان برای چک کردن یک سمبل از آن‌ها استفاده کرد:
#define DEBUG
...
#if DEBUG
    Console.WriteLine("You have defined DEBUG symbol");
#endif
نتیجه آن را می‌توانید در تصویر زیر مشاهده کنید:

بدیهی است که همین سمبل DEBUG را undef کنید متن بالا نمایش داده نخواهد شد.
بهتر است به پیش پردازنده‌های دیگر هم نگاهی بیندازیم:
#if STANDARD
    Console.WriteLine("You have defined STANDARD symbol");
#elif PROFESSIONAL
    Console.WriteLine("You have defined PROFESSIONAL symbol");
#elif ULTIMATE
    Console.WriteLine("You have defined ULTIMATE symbol");
#endif
حتی می‌توانید از عملگرهای شرطی چون && یا || یا == یا != و... هم استفاده کنید. تکه کد زیر، از این عملگرها بهره جسته است:
#if STANDARD && EVAL
    Console.WriteLine("You have defined STANDARD and EVAL symbols");
#endif

پیش پردازنده‌های #warning و #error
در پیش پردازنده #warning می‌توانید یک پیام هشدار یا اخطار را به پنجره‌ی warning ارسال کنید؛ ولی برنامه کماکان به اجرای خود ادامه می‌دهد. اما با #error برنامه هم پیام خطا را در پنجره مربوطه نمایش می‌دهد و هم باعث halt شدن برنامه می‌شود.
#if STANDARD && EVAL
    Console.WriteLine("You have defined STANDARD and EVAL symbols");
#endif

در کد بالا #warning را با #error جابجا می‌کنیم:


#region و #endregion
از این دو عبارت در بین کدها استفاده می‌کنیم. برای بلوک بندی کد‌ها می‌توان از آن‌ها استفاده کرد. برای مثال دسته بندی کدهای نوشته شده مثل جدا کردن property‌ها یا رویدادها یا متدها و ...، با محصور شدن تکه کدهای بین این دو، یک علامت + یا - برای انجام عمل expand و collapsed ایجاد می‌شود.


#line
برای تغییر نام فایل و شماره خطوط در هنگام دیباگ (نمایش خطا و هشدارها در پنجره‌ی نمایش خطاها) به کار می‌رود.
مثلا به تکه کد زیر دقت کنید و همچنین به تصویر بعد از آن، بدون نوشتن #line  دقت کنید:
namespace CSPreProcessorDirectivesDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            inta a = 100;
            Console.ReadLine();
        }
    }
}

خطای ما در خط 14 فایل program.cs رخ داده است. در تکه کد زیر پیش پردازنده #line را اضافه کردیم:
#line 400 "MyFile.cs"
inta a = 100;

همانطور که می‌بینید آدرس تکه کد یا خط بعد از آن تغییر پیدا کرد و از آنجا به بعد از 400 به بعد شمرده می‌شود.
طبق منابع نوشته شده این پیش پردازنده موقعی بیشتر سودمند هست که تکه کد، توسط ابزارهای خارجی یا سیستمی ویرایش شده باشد.
در صورتیکه از #line default استفاده کنید، از آن نقطه به بعد، نام فایل و شماره خطاها به صورت عادی اعلام می‌شوند و #line قبلی در نظر گرفته نمی‌شود تا شاید اگر دوباره به #line جدیدی برخورد کند.
#line hidden هم تکه کدهای مربوطه را از دید دیباگر مخفی می‌کند مثل موقعیکه برنامه نویس، کد به کد یا خط به خط برنامه را دیباگ می‌کند ولی از اینجا به بعد از روی  این خطوط رد می‌شود تا به یک #line دیگر برسد. منظور از رد شدن، عدم اجرای خطوط نیست؛ بلکه دیباگ خط به خط می‌باشد.

#progma
این پیش پردازنده از دو بخش نام دستور و آگومان‌ها تشکیل شده است:
#pragma pragma-name pragma-arguments
دات نت از دو نام دستور warning و checksum پشتیبانی می‌کند؛ آرگومان‌هایی که با دستور warning می‌پذیرد:
#pragma warning disable
#pragma warning restore
با آرگومان disabled تمامی هشدارهای خطوط بعد از آن نادیده گرفته شده و اعلام نمی‌شوند و از restore برای بازگشت از حالت disabled به کار می‌رود. همچنین برای غیر فعال کردن هشدار برای خط یا خطوط خاص هم میتوانید به صورت زیر بنویسید:
#pragma warning disable 414
#pragma warning disable 414, 3021

#checksum
#pragma checksum "filename" "{guid}" "checksum bytes"
از این یکی برای ذحیره هشدارها و خطاها در program database یا PDB استفاده می‌شود (برای مواقعیکه پروژه شما قرار است به یک com یا dll تبدیل شود؛ کاربردی زیادی دارد). آرگومان اول نام فایل که بعدا برای مانیتور کردن به راحتی بین کلاس‌ها تشخیص داده شود و دومی که GUID است و همین GUID را باید برای فایل مشخص کنید.
// Guid for the interface IMyInterface.
[Guid("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4")]
interface IMyInterface
{
    void MyMethod();
}

// Guid for the coclass MyTestClass.
[Guid("936DA01F-9ABD-4d9d-80C7-02AF85C822A8")]
public class MyTestClass : IMyInterface
{
    public void MyMethod() {}
}
و checksum _bytes که باید به صورت هگزادسیمال در حالت رشته‌ای نوشته شود و باید بیانگر یک عدد زوج باشد؛ در صورتیکه یک عدد فرد را مشخص کنید، کمپایلر پیش پردازنده شما را در نظر نمی‌گیرد. نهایتا به صورت زیر نوشته می‌شود:
class TestClass
{
    static int Main()
    {
        #pragma checksum "file.cs" "{3673e4ca-6098-4ec1-890f-8fceb2a794a2}" "{012345678AB}" // New checksum
    }
}

منابع :
مطالب
انتخاب layoutهای متفاوت در برنامه‌های Angular
شاید برای شما هم پیش آمده باشد که در یک برنامه‌ی Angular بخواهید layoutهای مختلفی داشته باشید؛ مثلا هنگام لاگین، طبق عرف کار باید هدر و فوتر صفحه از بین بروند و فقط فرم لاگین نمایش داده شود و یا بخواهید هنگام لاگین، یک layout مخصوص پنل مدیریتی داشته باشید و یا …

قبل از شروع، فرض را بر آن می‌گیریم که حداقل نیاز‌های یک پروژه‌ی Angular را آماده کرده اید. سپس یک پوشه‌ی جدید را به نام layout می‌سازیم و layout‌های مربوطه را در آن ایجاد میکنیم. با دستور زیر یک کامپوننت جدید را که layout ما خواهد شد، با نام دلخواهی ایجاد می‌کنیم:
ng g c Loginlayout
 و همچنین یک کامپوننت دیگر را برای صفحه‌ی اصلی به نام homelayout می‌سازیم:
ng g c homelayout

در ادامه Loginlayout را باز کرده و تنظیمات زیر را لحاظ کنید:
<div style="width: 100%;height: 250px;background-color: aquamarine">
   <h1>Header</h1>
</div>

<router-outlet></router-outlet>

<div style="width: 100%;height: 250px;background-color: brown">
  <h1>Foother</h1>
</div>
در اینجا یک هدر و یک فوتر را ساخته و <router-outlet></router-outlet> را در آن قرار می‌دهیم که قسمت پویای ما خواهد شد.

اکنون وارد کامپوننت home layout شوید و دقیقا مانند قبل، تنظیمات دلخواه خود را انجام داده و همچنین <router-outlet></router-outlet> راهم درون جائیکه می‌خواهید به صورت پویا باشد بگذارید.
تا اینجا ما فقط layoutها را طراحی کردیم. در ادامه در ریشه‌ی پروژه، سه کامپوننت را به نام‌های Home , Login, About میسازیم. Home و About دارای یک قالب و Login هم داری قالب مخصوص به خود میباشد.

سپس وارد کامپوننت آغازین برنامه (app.component.html) شوید و در آن <router-outlet></router-outlet> را وارد کنید. در اینجا دیگر نیازی به نوشتن تگ‌های خاص دیگری نیست.

در ادامه به اصلی‌ترین قسمت، یعنی مسیریابی می‌رسیم. وارد app.module.ts شوید و آن را به صورت زیر تنظیم کنید:
export const routes: Routes = [    
           { 
                path: 'Loginlayout', 
                component: LoginlayoutComponent ,
                children: [
                  { path: 'Login', component: LoginComponent, pathMatch: 'full'}                 
                ]
            },
            { 
                path: 'Homelayout', 
                component: HomelayoutComponent,
                children: [
                  { path: 'About', component: AbouComponent, pathMatch: 'full'},
                  { path: 'Home', component: HomeComponent, pathMatch: 'full'}
                ]
            }          
];
همانطورکه ملاحظه می‌کنید، مسیریابی بالا شامل مسیریابی‌های تو در تویی است. در اینجا کامپوننت‌های Home و About درون HomelayoutComponent بارگذاری می‌شوند و خود HomelayoutComponent  نیز درون app.component.
همچنین برای اینکه مشخص شود کدام کامپوننت به عنوان کامپوننت پیشفرض نمایش داده شود، به صورت زیر عمل میکنیم:
path: '', 
component: HomelayoutComponent,
children: [
  { path: '', component:HomeComponent, pathMatch: 'full'}         
]
به  این روش میتوانید هر تعداد layout ایی را که میخواهید، ایجاد کنید.

کدهای کامل این مطلب را می‌توانید از اینجا دریافت و یا به صورت آنی آزمایش کنید.