نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 21 - بررسی تغییرات Bundling و Minification
سلام؛ من با visual studio موفق به این کار شدم و مشکلی نداریم. اما هر کاری کردم با vscode برای پروژه DNT نتونستم bundler minifier رو راه اندازی کنم. نکته خاصی داره یا باید حتما از visual studio استفاده کرد؟
مطالب
پردازش URLهایی با دامنه‌های یونیکد
این لینک را درنظر بگیرید:
 http://en.هشام.com/post/build-customizable-language-switcher-tag-helper-with-bootstrap
در دامنه‌ی آن، حروف یونیکد (فارسی/عربی) بکار رفته‌اند. اگر صرفا با استفاده از قطعه کد زیر بخواهیم وجود این آدرس را بررسی کنیم:
 WebRequest wr = WebRequest.Create(uri);
using (WebResponse response = wr.GetResponse()) { }
به خطای زیر برخواهیم خورد:
 The remote name could not be resolved: 'en.هشام.com'

البته ممکن است کد فوق را بر روی ویندوزهای جدید بدون مشکل اجرا کنید. علت اینجا است که اگر از ویندوزهای قبل از ویندوز سرور 2012 استفاده می‌کنید، دات نت فریم ورک از RFC 3490 استفاده می‌کند؛ در غیراینصورت از RFC 5891 (فقط برای Windows 8, Windows 8.1, Windows 10, or Windows Server 2012)، با این تفاوت‌ها.

روش رفع آن هم فعال سازی پردازش این نوع دامنه‌ها (بر روی تمام ویندوزها) در فایل‌های app.config و یا web.config به صورت زیر است:
<configuration>
    <uri>
        <idn enabled="All" />
        <iriParsing enabled="true" />
    </uri>
</configuration>
کاری که این فعال سازی انجام می‌دهد، تبدیل خودکار نام یونیکد به «Punycode» است:
 var unicode = @"en.هشام.com";
 
var mapping = new IdnMapping(); // IDN  = Internationalizing Domain Names
var ascii = mapping.GetAscii(unicode);
Console.WriteLine(ascii);
 
string convertedBackToUnicode = mapping.GetUnicode(ascii);
Console.WriteLine(convertedBackToUnicode);
در اینجا به معادل اسکی ویژه‌ی دامنه‌ی یونیکد یا «en.xn--mgbz4cf.com» که Punycode نام گرفته می‌رسیم. این دامنه‌ای است که بر روی تمام ویندوزها بدون مشکل کار می‌کند. البته همانطور که عنوان شد نیازی به انجام دستی این نوع تبدیلات نیست و همان چند سطر تنظیمات فایل config برای فعال سازی خودکار این نوع تبدیلات کافی است.
مطالب
کمپین ضد IF !

بکارگیری بیش از حد If و خصوصا Switch برخلاف اصول طراحی شیءگرا است؛ تا این حد که یک کمپین ضد IF هم وجود دارد!



البته سایت فوق بیشتر جنبه تبلیغی برای سمینارهای گروه مذکور را دارد تا اینکه جنبه‌ی آموزشی/خود آموزی داشته باشد.

یک مثال کاربردی:
فرض کنید دارید یک سیستم گزارشگیری را طراحی می‌کنید. به جایی می‌رسید که نیاز است با Aggregate functions سروکار داشته باشید؛ مثلا جمع مقادیر یک ستون را نمایش دهید یا معدل امتیازهای نمایش داده شده را محاسبه کنید و امثال آن. طراحی متداول آن به صورت زیر خواهد بود:

using System.Collections.Generic;

using System.Linq;

namespace CircularDependencies
{
public enum AggregateFunc
{
Sum,
Avg
}

public class AggregateFuncCalculator
{
public decimal Calculate(IList<decimal> list, AggregateFunc func)
{
switch (func)
{
case AggregateFunc.Sum:
return getSum(list);
case AggregateFunc.Avg:
return getAvg(list);
default:
return 0m;
}
}

private decimal getAvg(IList<decimal> list)
{
if (list == null || !list.Any()) return 0;
return list.Sum() / list.Count;
}

private decimal getSum(IList<decimal> list)
{
if (list == null || !list.Any()) return 0;
return list.Sum();
}
}
}

در کلاس AggregateFuncCalculator یک متد Calculate داریم که توسط آن قرار است روی list دریافتی یک سری عملیات انجام شود. عملیات پشتیبانی شده هم توسط یک enum معرفی شده؛ برای مثال اینجا فقط جمع و میانگین پشتیبانی می‌شوند.
و مشکل طراحی این کلاس، همان switch است که برخلاف اصول طراحی شیء‌گرا می‌باشد. یکی از اصول طراحی شیءگرا بر این مبنا است که:
یک کلاس باید جهت تغییر، بسته اما جهت توسعه، باز باشد.

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

چکار باید کرد؟
آیا می‌توانید در کلاس AggregateFuncCalculator یک الگوی تکراری را تشخیص دهید؟ الگوی تکراری موجود، محاسبات بر روی یک لیست است. پس می‌شود بر اساس آن یک اینترفیس عمومی را تعریف کرد:

public interface IAggregateFunc

{
decimal Calculate(IList<decimal> list);
}

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

public class Sum : IAggregateFunc

{
public decimal Calculate(IList<decimal> list)
{
if (list == null || !list.Any()) return 0;
return list.Sum();
}
}

public class Avg : IAggregateFunc
{
public decimal Calculate(IList<decimal> list)
{
if (list == null || !list.Any()) return 0;
return list.Sum() / list.Count;
}
}

تا اینجا 2 هدف مهم حاصل شده است:
- کم کم کلاس AggregateFuncCalculator دارد خلوت می‌شود. قرار است هر کلاس یک کار را بیشتر انجام ندهد.
- برنامه از بسته بودن جهت توسعه هم خارج شده است (یکی دیگر از اصول طراحی شیءگرا). اگر تعاریف توابع محاسباتی را تماما در یک کلاس قرار دهیم صاحب اول و آخر آن کتابخانه خودمان خواهیم بود. این کلاس بسته است جهت تغییر. اما با معرفی IAggregateFunc، من امروز 2 تابع را تعریف کرد‌ه‌ام، شما فردا توابع خاص خودتان را تعریف کنید. باز هم برنامه کار خواهد کرد. نیازی نیست تا من هر روز یک نگارش جدید از کتابخانه را ارائه دهم که در آن فقط یک تابع دیگر اضافه شده است.

اکنون یکی از چندین و چند روش بازنویسی کلاس AggregateFuncCalculator به صورت زیر می‌تواند باشد

public class AggregateFuncCalculator

{
public decimal Calculate(IList<decimal> list, IAggregateFunc func)
{
return func.Calculate(list);
}
}

بله! دیگر سوئیچی در کار نیست. این کلاس تنها یک کار را انجام می‌دهد. همچنین دیگر نیازی به تغییر هم ندارد (محاسبات از آن خارج شده) و باز است جهت توسعه (شما نگارش‌های دلخواه IAggregateFunc دیگر خود را توسعه داده و استفاده کنید).

مطالب
توسعه اپلیکیشن های ASP.NET با Windows Azure Active Directory
ابزار ASP.NET برای Windows Azure Active Directory فعال کردن احراز هویت در وب اپلیکیشن هایی که روی  Windows Azure Web Sites  میزبانی شده اند را ساده‌تر می‌کند. می‌توانید از Windows Azure Authentication برای احراز هویت کاربران Office 365 استفاده کنید، حساب‌های کاربری را از On-Premise Active Directory خود همگام سازی (Sync) کنید و یا از یک دامنه سفارشی Windows Azure Active Directory بهره ببرید. فعال سازی Windows Azure Authentication، اپلیکیشن شما را طوری پیکربندی می‌کند تا تمامی کاربران را با استفاده از یک  Windows Azure Active Directory tenant  احراز هویت کند.

این مقاله ساختن یک اپلیکیشن ASP.NET را که بر اساس  organizational accounts  پیکربندی شده و بر روی  Windows Azure Active Directory  میزبانی می‌شود، مرور می‌کند.

پیش نیاز ها

  1. Visual Studio Express 2013 RC for Web یا Visual Studio 2013 RC 
  2. یک حساب کاربری در Windows Azure. می‌توانید یک حساب رایگان بسازید.


یک مدیر کلی به حساب کاربری Active Directory خود اضافه کنید

  1. وارد Windows Azure Portal شوید.
  2. یک حساب کاربری (Windows Azure Active Directory (AD انتخاب یا ایجاد کنید. اگر قبلا حساب کاربری ساخته اید از همان استفاده کنید در غیر اینصورت یک حساب جدید ایجاد کنید. مشترکین Windows Azure یک AD پیش فرض با نام Default Directory خواهند داشت.
  3. در حساب کاربری AD خود یک کاربر جدید در نقش Global Administrator بسازید. اکانت AD خود را انتخاب کنید و Add User را کلیک کنید. برای اطلاعات کامل‌تر به Managing Windows Azure AD from the Windows Azure Portal 1– Sign Up with an Organizational Account مراجعه کنید.

یک نام کاربری انتخاب کرده و به مرحله بعد بروید.

نام کاربری را وارد کنید و نقش Global Administrator را به آن اختصاص دهید. مدیران کلی به یک آدرس ایمیل متناوب هم نیاز دارند. به مرحله بعد بروید.

بر روی Create کلیک کنید و کلمه‌ی عبور موقتی را کپی کنید. پس از اولین ورود باید کلمه عبور را تغییر دهید.


یک اپلیکیشن ASP.NET بسازید

در ویژوال استودیو یک پروژه جدید ASP.NET Web Forms یا MVC بسازید و روی Change Authentication  کلیک کنید. 

گزینه Organizational Accounts را انتخاب کنید. نام دامنه خود را وارد کنید و سپس گزینه Single Sign On, Read directory data را انتخاب کنید. به مرحله بعد بروید.

نکته: در قسمت More Options می توانید قلمرو اپلیکیشن (Application ID URI) را تنظیم کنید. تنظیمات پیش فرض برای اکثر کاربران مناسب است اما در صورت لزوم می‌توانید آنها را ویرایش کنید، مثلا از طریق Windows Azure Portal دامنه‌های سفارشی خودتان را تنظیم کنید.

اگر گزینه Overwrite را انتخاب کنید اپلیکیشن جدیدی در Windows Azure برای شما ساخته خواهد شد. در غیر اینصورت فریم ورک سعی می‌کند اپلیکیشنی با شناسه یکسان پیدا کند (در پست متدهای احراز هویت در VS 2013 به تنظیمات این قسمت پرداخته شده).

اطلاعات مدیر کلی دامنه در Active Directory خود را وارد کنید (Credentials) و پروژه را با کلیک کردن بر روی Create Project بسازید.

با کلیدهای ترکیبی Ctrl + F5، اپلیکیشن را اجرا کنید. مرورگر شما باید یک اخطار SSL Certificate به شما بدهد. این بدین دلیل است که مدرک استفاده شده توسط IIS Express مورد اعتماد (trusted) نیست. این اخطار را بپذیرید و اجازه اجرا را به آن بدهید. پس از آنکه اپلیکیشن خود را روی Windows Azure منتشر کردید، این پیغام دیگر تولید نمی‌شود؛ چرا که Certificate‌های استفاده شده trusted هستند.

با حساب کاربری سازمانی (organizational account) که ایجاد کرده‌اید، وارد شوید.

همانطور که مشاهده می‌کنید هم اکنون به سایت وارد شده اید.



توزیع اپلیکیشن روی Windows Azure

در Windows Azure Portal یک وب سایت را به‌همراه یک دیتابیس، ایجاد کنید. در پانل سمت چپ صفحه روی Websites کلیک کنید و بعد New را انتخاب کنید. سپس گزینه Custom Create را برگزینید.

اپلیکیشن را روی Windows Azure منتشر کنید. روی پروژه کلیک راست کرده و Publish را انتخاب کنید. در مرحله تنظیمات (Settings) مشاهده می‌کنید که احراز هویت حساب‌های سازمانی (organizational accounts) فعال است. همچنین سطح دسترسی به خواندن تنظیم شده است. در قسمت Database رشته اتصال دیتابیس را تنظیم کنید.

حال به وب سایت Windows Azure خود بروید و توسط حساب کاربری ایجاد شده وارد سایت شوید. در این مرحله دیگر نباید خطای امنیتی SSL را دریافت کنید.


خواندن اطلاعات پروفایل کاربران توسط Graph API

قالب پروژه ویژوال استودیو برای organizational accounts یک متد و نما بنام UserProfile به پروژه اضافه کرده است.
[Authorize]
public async Task<ActionResult> UserProfile()
{
    string tenantId = ClaimsPrincipal.Current.FindFirst(TenantSchema).Value;

    // Get a token for calling the Windows Azure Active Directory Graph
    AuthenticationContext authContext = new AuthenticationContext(String.Format(CultureInfo.InvariantCulture, LoginUrl, tenantId));
    ClientCredential credential = new ClientCredential(AppPrincipalId, AppKey);
    AuthenticationResult assertionCredential = authContext.AcquireToken(GraphUrl, credential);
    string authHeader = assertionCredential.CreateAuthorizationHeader();
    string requestUrl = String.Format(
        CultureInfo.InvariantCulture,
        GraphUserUrl,
        HttpUtility.UrlEncode(tenantId),
        HttpUtility.UrlEncode(User.Identity.Name));

    HttpClient client = new HttpClient();
    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
    request.Headers.TryAddWithoutValidation("Authorization", authHeader);
    HttpResponseMessage response = await client.SendAsync(request);
    string responseString = await response.Content.ReadAsStringAsync();
    UserProfile profile = JsonConvert.DeserializeObject<UserProfile>(responseString);

    return View(profile);
}

کلیک کردن لینک UserProfile  اطلاعات پروفایل کاربر جاری را نمایش می‌دهد.



اطلاعات بیشتر

نظرات مطالب
ایجاد سیستم وضعیت آب و هوا مانند گوگل (بخش اول)
قسمت switch ایی را که در View نوشتید، تبدیل کنید به یک متد کمکی در کلاسی خارج از View: (مهم نیست متد الحاقی باشد یا خیر؛ فقط داخل View نباشد)
public static string GetFileName(int code)
{
    switch (code)
    {
       case 0: return "/Images/User/Weather/Tornado.png";
  //...
}
بعد یک خاصیت محاسباتی به نام FileName به مدل مورد استفاده اضافه کنید:
    public class YahooWeatherRssItem
    {
        public int Code { get; set; } 
        //...
        public string FileName 
        {
          get { return Util.GetFileName(Code); }
        }
    }
به این صورت View از کدهای محاسبات یافتن FileName خالی می‌شود.
مطالب
بررسی Bad code smell ها: گذاره‌های Switch
این کد بد بو در دسته «بد استفاده کنندگان از شیء گرایی» قرار می‌گیرد. زمانیکه گذاره‌های switch و یا دنباله‌ای از گذاره‌های if در کد وجود داشته باشد، معمولا با چنین الگویی روبرو هستیم. تشخیص این کد بد بو نیز بسیار آسان است. 
در شرایط نادری استفاده از switch می‌تواند یک طراحی شیء گرای مناسب باشد. در طراحی شیء گرا معمولا یک گذاره switch نشان دهنده یک رابطه چند ریختی (Polymorphism) نادیده گرفته شده است. 
معمولا زمانیکه بجای استفاده از اصول طراحی شیء گرا، از گذاره‌های switch استفاده می‌شود، این گذاره‌ها در بخش‌های مختلف کد پراکنده خواهند شد. در نتیجه، برای اضافه یا حذف نمودن یک شرط از شرایط switch، باید تمامی گذاره‌ها را در کد، تغییر داد.  
از اولین قدم‌ها برای رفع چنین بوی بدی، می‌تواند متمرکز کردن گذاره switch پراکنده در کلاسی مناسب باشد. با این کار می‌توان کنترل نسبتا بیشتری بر روی گذاره و شرط‌های آن داشت.  
یکی از دلایل ایجاد چنین بوی بدی استفاده از کد نوع (Type code) بجای پیاده سازی روابط ارث بری است. به طور مثال فرض کنید در حال تولید سیستمی هستید که دو نوع مشتری حقیقی و حقوقی در آن وجود دارد. ممکن است به این نتیجه برسید که یک فیلد به نام Type را در کلاس مربوط به مشتری اضافه کنید. مانند کد زیر:  
public enum CustomerType 
{ 
     Person = 0, 
     Company = 1 
} 
public class Customer 
{ 
    public CustomerType Type { get; set; } 
}

با وجود چنین کلاسی از مشتری و نیاز به انجام فعالیت‌های مختلفی بر روی آن، احتمالا نیاز خواهد بود که در بخش‌های مختلف کد، گذاره‌ی switch ای مانند زیر را اضافه کنید:  

switch (customer.Type) 
{ 
      case CustomerType.Person: 
         // calculate discount, or send message or edit customer or anything else 
          break; 
      case CustomerType.Company: 
          // calculate discount, or send message or edit customer or anything else 
          break; 
      default: 
          throw new ArgumentOutOfRangeException(); 
 }

برای انجام فعالیت‌های مختلفی مانند محاسبه تخفیف، ارسال پیام و یا ویرایش مشتری، نیاز خواهد بود این گذاره تکرار شود که خود این موضوع بوی بد duplicate code است و به الگوی shotgun surgery نیز ختم خواهد شد. 

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

برای حل این نوع از کد بد بو، معمولا یک کلاس پدر را به نام مشتری ایجاد کرده و کلاس‌های مختص هر یک از انواع مشتری را از آن به ارث می‌برند (Replace type code with subclass):

یا می‌توان طراحی را کمی متفاوت‌تر و به صورت زیر انجام داد:

دلیل مشابه دیگر ایجاد این الگوی بد کد استفاده از type code به عنوان وضعیت یک تایپ است. که در این صورت می‌توان بجای type code از state object استفاده کرد (Replace type code with strategy). به این مورد در مباحث مربوط به refactoring به طور مفصل پرداخته شده است.


جمع بندی 

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