نظرات مطالب
اهمیت Controller های ساده در ASP.NET MVC
اگر طبق راهنمایی‌های همین پست پیش بریم ، من می‌تونم این روش رو پیشنهاد بدم که مقدار متغیر status اگر برابر با successful نبود . به یک متد دیگه ای ارسال بشه که مسئولیت ساخت و برگرداندن پیام مناسب رو برعهده داره . اون پیام‌ها هم بهتره که به جای اینکه در قالب یک سری if یا switch محاسبه بشن در قالب یک dictionary نگهداری بشن .  
public RedirectToRouteResult Ship(int orderId)
{
   var status = _orderShippingService.Ship(orderId);
   if (status.Successful)
   {
      return RedirectToAction("Shipped", "Order", new {orderId});
   }
   return RedirectToAction("NotShipped", "Order", new {id = orderId, desc = status});
}
ولی محل فراخوانی این تابع دوم کجا باید باشه ؟ نظر من اینه که نباید توی این اکشن باشه چون وظیفه‌ی این اکشن چیز دیگری است . بهتره که مقدار status به اکشن NotShipped ارسال بشه و در اونجا پیام استخراج و به view ارسال بشه . چون در اون اکشن احتمالا دلیل ship نشدن سفارش باید به کاربر نمایش داده بشه.
مطالب
بررسی Bad code smell ها: فیلدهای موقتی
فیلد موقتی یا Temporary field در دسته بندی الگوهای «بد استفاده کنندگان از شیء گرایی» قرار می‌گیرد. در این الگوی بد، فیلدها یا خصوصیات یک کلاس، در شرایط خاصی مقدار گرفته و مورد استفاده قرار می‌گیرند و در بقیه شرایط خالی هستند. 
زمانیکه در یک کلاس، متدی برای انجام فعالیت خود، تعدادی پارامتر ورودی زیادی نیاز داشته باشد، ممکن است برنامه نویس برای مواجه نشدن با تعداد پارامترهای زیاد ورودی، فیلدها یا خصوصیاتی را در کلاس مربوط به آن متد ایجاد کند. این فیلدها عملا فقط زمان صدا زدن آن متد مقدار گرفته و در بقیه شرایط خالی هستند.
خواندن و استفاده از این نوع کدها معمولا مشکل و چالش برانگیز است. زیرا خواننده شاهد فیلدهایی است که در اکثر مواقع خالی هستند. همچنین زمان استفاده از این کلاس نمی‌توان از وجود مقادیر فیلدها یا خصوصیات آن‌ها اطمینان لازم را داشت.

روش‌های اصلاح این کد بد بو 

برای اصلاح چنین بوی بدی به طور معمول دو راه وجود دارد. 
اول: با در نظر گرفتن اینکه تمامی کد موجود در متد و فیلدهای مرتبط به آن قابلیت انتقال به کلاس خاص خودشان را دارند، می‌تواند کلاس مجزایی را برای آن متد و فیلدهای مربوطه ایجاد کرد. 
دوم: برای فیلدها و خصوصیاتی که در خیلی مواقع خالی هستند، می‌توان با روش Null object برای وضعیت خالی بودن آن، یک شیء خالی بی اثر را ایجاد کرد.  
به مثال زیر توجه کنید: 
فرض کنید در حال تولید سیستمی هستید که در روال خاصی، نیاز به محاسبه پورسانت فروشنده‌ها دارید. برای محاسبه پورسانت به موارد زیر نیاز است:
  • لیست محصولات فروخته شده
  • درصد کمیسیون خام
  • تاریخ فروش
  • شعبه فروش
  • نوع پرداخت 
به طور نمونه اگر فروشنده فروش نقدی ای انجام دهد، کمیسیون بیشتری نسبت به کمیسیون پیشفرض، به او تعلق خواهد گرفت و … 
ممکن است طراحی اولیه برای چنین متدی به صورت زیر باشد: 
public class Salesman 
{ 
    public void Method1() 
    { 
       return; 
    } 
    public void Method2() 
    { 
        return; 
    } 
    public void Method3() 
    { 
       return; 
    }
    public decimal CalculateCommission(dynamic products, dynamic commissionRate, dynamic saleDate, dynamic branch, dynamic paymentType) 
    { 
       return decimal.MaxValue; 
    } 
}
با مشاهده پارامتر‌های زیاد متد، برنامه نویس می‌تواند از روش‌های اصلاح بوی بد «تعداد زیاد پارامترهای ورودی» استفاده کند. یا اینکه برنامه نویس برای خلاصی از این کد بد بو، بجای ارسال پارامتر، فیلدهایی را در کلاس Salesman ایجاد کند؛ مانند کد زیر:  
public class SalesmanV2 
{ 
    public IEnumerable<dynamic> Products { get; set; } 
    public dynamic CommisionRate { get; set; } 
    public dynamic SaleDate { get; set; } 
    public dynamic Branch { get; set; } 
    public dynamic PaymentType { get; set; } 
    public void Method1() 
    { 
        return; 
    } 
    public void Method2() 
    { 
        return; 
    } 
    public void Method3() 
    { 
        return; 
    } 
    public decimal CalculateCommission() 
    { 
       return decimal.MaxValue; 
    } 
}
با این تغییر، پارامترهای متد CalculateCommision به خصوصیاتی در کلاس Salesman تبدیل خواهند شد. دقت کنید این کلاس متدهای دیگری برای فعالیت‌های مختلف دارد.  
در روش‌های اصلاح این کد بد بو، اشاره به انتقال منطق متد مذکور به کلاس مجزا و مخصوص به خود شده بود. در واقع کد بد بوی «فیلد موقتی» ناشی از عدم رعایت اصل single responsibility است و محاسبه پورسانت را از نظر ذاتی می‌توان وظیفه‌ی اضافه‌ای در این کلاس دانست. با توجه به اینکه می‌توان محاسبه پورسانت را به صورت جداگانه پیاده سازی کرد. به چنین پیاده سازی ای خواهیم رسید.  
public class SalesmanV3 
{ 
    public void Method1() 
    { 
        return; 
    } 
    public void Method2() 
    { 
        return; 
    } 
    public void Method3() 
    { 
        return; 
    } 
} 

public class CommissionCalculator 
{ 
    private IEnumerable<dynamic> _products; 
    private dynamic _commisionRate; 
    private dynamic _saleDate; 
    private dynamic _branch; 
    private dynamic _paymentType; 
    public CommissionCalculator(IEnumerable<dynamic> products, dynamic commisionRate, 
            dynamic saleDate, dynamic branch, dynamic paymentType) 
    { 
        _products = products; 
        _commisionRate = commisionRate; 
        _saleDate = saleDate; 
        _branch = branch; 
        _paymentType = paymentType; 
    } 
}
در شرایط نادری، کد بد بوی «فیلد موقتی» ناشی از عدم رعایت اصل single responsibility نیست. در چنین شرایطی می‌توان از null object برای رفع این بوی بد استفاده کرد.

جمع بندی 

همان‌طور که در متن نیز اشاره شد، عدم رعایت اصل single responsibility می‌تواند منجر به چنین کد بد بویی شود. این کد بد بو با روش‌های ساده‌ای قابل اصلاح است. اصلاح چنین بویی خوانایی و قابلیت نگهداری کد را افزایش خواهد داد. 
مطالب
بررسی Bad code smell ها: میراث رد شده

میراث رد شده یا Refused bequest به دسته «بد استفاده کنندگان از شیء گرایی» تعلق دارد. این دسته از کدهای بد بو، معمولا استفاده ناقص یا نادرستی از مفاهیم و اصول شیء گرایی دارند. 
زمانیکه یک کلاس تنها بخشی از اعضای (خصوصیت، متد و ...) کلاس پدر خود را استفاده می‌کند، با این الگو سر و کار داریم. در چنین شرایطی دیگر اعضای کلاس پدر یا استفاده نمی‌شوند و یا حتی در صورت پیاده سازی شدن توسط کلاس، بلااستفاده می‌مانند. به طور مثال متدهایی از کلاس پدر پیاده سازی می‌شوند و با پرتاب یک استثناء در بدنه‌شان از کار می‌افتند. 
یکی از دلایل مهم ایجاد چنین کدهای بد بویی، ایجاد رابطه ارث بری تنها برای استفاده دوباره از کدهای یک کلاس است. در صورتیکه ممکن است کلاس پدر و فرزند هیچ ارتباط منطقی ای از نظر ارث بری با یکدیگر نداشته باشند.   
به طور مثال فرض کنید در حال توسعه یک محصول هستید که در آن فروش کالا اتفاق می‌افتد. در ابتدای کار، تنها کاربران این محصول، شرکت‌ها هستند. روالی نیز برای محاسبه تخفیف مربوط به شرکت‌ها ایجاد شده است. در این روال یک تخفیف پایه وجود دارد که به همه مشتریان تعلق می‌گیرید و تخفیف‌هایی نیز وجود دارند که به هر یک از شرکت‌ها تعلق می‌گیرند. میزان تخفیف نهایی برای یک شرکت از مجموع این دو مقدار بدست می‌آید. کلاس مربوط به محاسبه تخفیف به این صورت است: 

public class DiscountCalculator 
{ 
    protected decimal CalculateGeneralDiscount() 
    { 
        // calculate general discount 
        return 0; 
    } 
    protected decimal AddSpecificDiscount(decimal baseDiscount) 
    { 
        // add specific discounts to base discount 
        return 0; 
    } 
    protected virtual decimal GetFinalDiscount() 
    { 
        var baseDiscount = CalculateGeneralDiscount(); 
        var addedDiscount = AddSpecificDiscount(baseDiscount); 
        return addedDiscount; 
    } 
}
بعد از مدتی نیاز می‌شود که افراد حقیقی از نرم افزار استفاده کرده و خرید نمایند و این مکانیزم تخفیف برای آن‌ها نیز اعمال شود. توسعه دهنده بعد از بررسی به این نتیجه می‌رسد که تنها تفاوت این مکانیزم با مکانیزم قبلی، متد AddSpecificDiscount است که باید برای اشخاص حقیقی بازنویسی شود. این توسعه دهنده تصمیم می‌گیرد برای استفاده دوباره از کد موجود در کلاس DiscountCalculator، کلاس مربوط به اشخاص حقیقی را از آن ارث ببرد. که نتیجه به صورت زیر خواهد بود:
public class PersonDiscountCalculator : DiscountCalculator 
{ 
    private decimal AddSpecificDiscountForPerson(decimal baseDiscount) 
    { 
        // calculate base discount for person 
        return 0; 
    } 
    protected override decimal GetFinalDiscount() 
    { 
        var baseDiscount = CalculateGeneralDiscount(); 
        var added = AddSpecificDiscountForPerson(baseDiscount); 
        return added; 
    } 
}

همانطور که در کد بالا مشاهده می‌کنید، متد مربوط به افزودن تخفیف‌های خاص شخص از نو نوشته شده و متد مربوط به محاسبه تخفیف‌های پایه استفاده شده و متد GetFinalDiscount دوباره نویسی شده تا با مکانیزم جدید همخوانی داشته باشد.
در این مثال متد مربوط به محاسبه تخفیف برای شرکت، علارغم اینکه به دلیل رابطه ارث بری در کلاس فرزند قابل دسترس است، بلااستفاده مانده است. و حتی وجود چنین متدی در کلاس PersonDiscountCalculator نیز بی معنی است. در واقع کلاس PersonDiscountCalculator برخی از میراث کلاس پدر خود را رد کرده است.

روش‌های اصلاح این نوع کد بد بو 

1) زمانیکه رابطه ارث بری هیچ معنایی ندارد، می‌توان به جای استفاده از ارث بری، شیء مربوط به کلاس پدر را ایجاد و در بدنه کلاس فرزند از آن استفاده کرد. مثلا برای فراخوانی متدها یا دسترسی به خصوصیت‌ها (مثال ذکر شده در این دسته نیست).
2) زمانیکه رابطه منطقی وجود داشته باشد، ولی اعضای اضافی کلاس پدر، به فرزند به ارث برسند، راه حل معمولا در جدا کردن کلاس پدر و ایجاد یک کلاس جدید پدر برای مصرف مورد نظر است.  
در مثال مطرح شده رابطه منطقی بین کلاس‌ها وجود دارد؛ ولی نه به شکلی که پیاده سازی شده است. یکی از راه‌های مناسب برای رفع چنین مشکلی، ایجاد یک کلاس پدر مشترک (در اینجا DiscountCalculator) و انتقال منطق‌های مربوطه به آن و ارث بری کردن تک تک کلاسها از آن است.  
public abstract class DiscountCalculator 
{ 
    protected decimal CalculateGeneralDiscount() 
    { 
        // calculate general discount 
        return 0; 
    } 
    protected abstract decimal AddSpecificDiscount(decimal baseDiscount); 
    protected virtual decimal GetFinalDiscount() 
    { 
        var baseDiscount = CalculateGeneralDiscount(); 
        var addedDiscount = AddSpecificDiscount(baseDiscount); 
        return addedDiscount; 
    } 
}

کلاس DiscountCalculator به عنوان کلاس پایه برای محاسبات تخفیف تعریف شده و کلاس‌های مربوط به شرکت و شخص از آن ارث بری می‌کنند. به این صورت که محاسبات کلی تخفیف‌ها در کلاس پایه و محاسبات مربوط به افزودن تخفیف‌های خاص در کلاس‌های فرزند انجام می‌شود (با فرض این که محاسبات مربوط به افزودن تخفیف‌های خاص تفاوت دارند).   
public class CompanyDiscountCalculator: DiscountCalculator 
{ 
    protected override decimal AddSpecificDiscount(decimal baseDiscount) 
        { 
            // add some customer specific discounts to base discount 
            return 0; 
        } 
    } 
    public class PersonDiscountCalculator : DiscountCalculator 
    { 
        protected override decimal AddSpecificDiscount(decimal baseDiscount) 
        { 
            // calculate base discount for person 
            return 0; 
        } 
}

جمع بندی 

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

نظرات مطالب
بررسی تفصیلی رابطه Many-to-Many در EF Code first
با توجه به مطالب بیان شده در پیاده سازی واحد کار در اینجا و مطالب بیان شده در این قسمت، آیا سرویس‌های ایجاد شده می‌توانند در لایه سرویس به یکدیگر دسترسی داشته باشند؟ به صورت زیر:
    public class EfTagService : ITagService
    {
        IUnitOfWork _uow;
        readonly IDbSet<Tag> _tags;

        public EfTagService(IUnitOfWork uow)
        {
            _uow = uow;
            _tags = _uow.Set<Tag>();
        }

        public bool CreateTag(Tag tag)
        {
            // ...
        }

        public List<Tag> GetTagsByName(string[] tagNames)
        {
            // return ...
        }

    }
و استفاده از آن در EfPostService به صورت زیر:
public class EfPostService : IPostService
{
        IUnitOfWork _uow;
        readonly IDbSet<Post> _posts;
      
         //این قسمت
        private EfTagService _tagService;


        public EfPostService(IUnitOfWork uow)
        {
            _uow = uow;
            _posts = uow.Set<Post>();

             //این قسمت
            _tagService = new EfTagService(_uow);
        }

        public void AddTagsToPost(Post post, string[] tagsList)
        {
            if (post.Tags != null && post.Tags.Any())
                post.Tags.Clear();

             //این قسمت
            var listOfActualTags = _tagService.GetTagsByName(tagsList);
            var listOfActualTagNames = listOfActualTags.Select(x => x.Name.ToLower()).ToList();

            foreach (var tag in tagsList)
            {
                if (!listOfActualTagNames.Contains(tag.ToLowerInvariant().Trim()))
                {
                    Tag newTag = new Tag() { Name = tag };
                 
                      //این قسمت
                    _tagService.CreateTag(newTag);

                    post.Tags.Add(newTag);
                }
            }
            // ...
         
        }
}
آیا پیاده سازی فوق صحیح است؟
نظرات مطالب
فشرده سازی فایل های CSS و JavaScript بصورت خودکار توسط MS Ajax Minifier
تا جایی که من مطلع هستم از طریق تنظیمات IIS می‌توان پاسخ به درخواست‌ها را (شامل فایل‌های استاتیک و داینامیک) به کمک gzip فشرده کرد. اما اگر اطلاعاتم صحیح باشد این موضوع کمی بار CPU را افزایش می‌دهد، هر چند گاهی تا 75% حجم اطلاعات رد و بدل شده را کاهش می‌دهد.
برای اطلاعات بیشتر در مورد تنظیمات IIS6 می‌توانید به + و + مراجعه کنید.
همچنین اگر روی IIS7 به بعد میزبانی می‌شوید می‌توانید درون فایل Web.Config و درون تگ system.webServer تنظیمات زیر را اضافه کنید: 
<httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files">
    <scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll" staticCompressionLevel="9" dynamicCompressionLevel="4" />
    <scheme name="deflate" dll="%Windir%\system32\inetsrv\gzip.dll" staticCompressionLevel="9" dynamicCompressionLevel="4" />
    <dynamicTypes>
        <add mimeType="text/*" enabled="true" />
        <add mimeType="message/*" enabled="true" />
        <add mimeType="application/x-javascript" enabled="true" />
        <add mimeType="application/atom+xml; charset=utf-8" enabled="true" />
        <add mimeType="*/*" enabled="false" />
    </dynamicTypes>
    <staticTypes>
        <add mimeType="text/*" enabled="true" />
        <add mimeType="message/*" enabled="true" />
        <add mimeType="application/javascript" enabled="true" />
        <add mimeType="*/*" enabled="false" />
    </staticTypes>
</httpCompression>
(برای مطالعه بیشتر این +  را ببینید.)
نظرات مطالب
ارتقاء به ASP.NET Core 2.0 - معرفی بسته‌ی Microsoft.AspNetCore.All
در VS Code هم با این خطا مواجه شدم. در بقیه‌ی فایل‌های پروژه نیز به همین صورت اکثر reference‌ها رو نمیشناسد.همین خطا رو توی Visual Studio نیز داشتم البته هنوز آپدیت نکردم.

نظرات مطالب
تنظیمات شیرپوینت برای فعال سازی Session در هنگام کد نویسی
سلام . 
همانطور که بیان شد، در صورت نیاز به استفاده از Session و مشاهده خطا، یکی از راهکار ها، این مورد می‌باشد و هیچ اصراری به استفاده از اون نیست !
همچنین در این پست فقط دلیل این خطا و راه حل اون بیان شد و کسی کاری به مایکروسافت نداره !