مطالب
مروری بر Claim
تعریف :
در این پست قصد دارم در مورد claim که از آن به عنوان یک Abstraction برای شناسایی نام برده شده ، صحبت کنم و گریزی با ارتباط آن با شیرپوینت بزنم . مایکروسافت در جایی Claim را این گونه تعریف کرده بود : یک عبارت که یک شیئ ، آن را در باره خودش یا شیئ دیگری می‌سازد . Claim یک Abstraction برای شناسایی فراهم می‌کند . برای مثال میتوان گفت که یک عبارت که شامل نام ، شناسه ، کلید ، گروه بندی ، ظرفیت و ... باشد ، فراهم می‌کند .
 لازم است به تعریف Token هم اشاره ای شود . هنگامی که یک شناسه دیجیتالی در شبکه در حال گذر است ، فقط حاوی مجموعه ای از بایت‌ها است .( ارجاع به مجموعه ای از بایت‌ها که حاوی اطلاعات شناسایی به عنوان یک Token امنیتی با فقط یک Token باشد، امری عادی است ) . در محیطی که بر مبنای Claim بنا شده است ، یک Token حاوی یک یا چند Claim است که هر یک می‌تواند برخی تکه‌های اطلاعاتی را برای شناسایی (بیشتر در مورد کاربران و افراد استفاده می‌شود) ، در خود جای دهد  

Claim‌ها تقریبا هر چیزی را در مورد یک کاربر می‌تواند ارائه دهد. . برای مثال در Token تصویر بالا ، 3 claim اول به اطلاعات نام و نقش و سن کاربر اشاره دارند . 
فراهم کننده - توزیع کننده :
Claim‌ها توسط یک فراهم کننده (Provider) توزیع می‌شوند (Issuer) و سپس به آنها یک یا چند مقدار ، اختصاص می‌یابد و در Security Token هایی که توسط یک توزیع کننده ، توزیع می‌شوند ، بسته بندی می‌شود و معمولا به عنوان Security Token Service یا STS شناخته می‌شوند . برای مشاهده تعریف اصطلاحات مرتبط به Claim به اینجا مراجعه کنید 

STS ، می‌تواند توسط چند Identity Provider - IdP به مالکیت در بیاید . یک فراهم کننده شناسه در STS یا IP-STS ، یک سرویس است که درخواست‌ها را برای اطمینان از شناسایی Claim‌ها مدیریت می‌کند . یک IP-STS از یک پایگاه داده که Identity Store نامیده می‌شود برای نگهداری و مدیریت شناسه‌ها و خصیصه‌های مرتبط با آنها استفاده می‌کند .Identity Store می‌تواند یک دیتا بیس معمولی مانند SQL Server باشد یا یک محیط پیچیده‌تر مانند Active Directory . (از قبیل Active Directory Domain Services یا Active Directory Lightweight Directory Service ) . 
 
قلمرو - Realm
بیانگر مجموعه ای از برنامه‌ها ، URL‌ها ، دامنه‌ها یا سایت هایی می‌باشد که برای Token ، معتبر باشد .معمولا یک Realm با استفاده از دامنه (microsoft.com) یا مسیری داخل دامنه (microsoft.com/practices/guides) تعریف می‌شود .بعضی وقت‌ها یک realm ، به عنوان Security Domain بیان می‌شود چرا که تمام برنامه‌های داخل یک مرز امنیتی ویژه ای را احاطه کرده است .
 
Identity Federation
Identity Federation در حقیقت دریافت کننده Token هایی است که در خارج از Realm شما ایجاد شده اند و در صورتی Token را می‌پذیرد که شما Issuer یا توزیع کننده را مورد اطمینان معرفی کرده باشد . این امر به کاربران اجازه می‌دهد تا بدون نیاز به ورود به realm تعریف شده خودشان ، از realm دیگری وارد برنامه شوند . کاربران با یک بار ورود به محیط برنامه ، به چندین realm دسترسی پیدا خواهند کرد . 

Relying party application

هر برنامه سمت client که از Claim پشتیبانی کند 

مزایای Claim

  • جدا سازی برنامه از جزییات شناسایی
  • انعطاف پذیری در احراز هویت
  • Single sign-on
  • عدم نیاز به VPN
  • متحد کردن مجموعه با دیگر شرکت ها
  • متحد کردن مجموعه با سرویس‌های غیر از AD 

عناصر Claim

Claim شامل عناصر زیر می‌باشد :

  • Token
  • Claim
  • Provider/Issuer
    • Sharepoint STS
    • ADFS
    • ACS
    • OID
    • ,و غیره 
توزیع کننده‌ی ADFS

  
پرنکل‌ها و Token‌های Claim
شاید این بخش ، یکی از سردرگم کننده‌ترین مفاهیم باشد . هنگامی که صحبت از Claim می‌شود ، عده ای دچار این عدم توجه صحیح می‌شوند که هر دو نوع مختلفی از Token‌ها که با Claim‌ها استفاده می‌شوند ، توسط تمام برنامه‌ها پشتیبانی نمی‌شوند . نکته قابل توجه نوع پروتکلی است که می‌خواهید از آن استفاده کنید و باید کامل از آن مطلع باشید .
Security Token هایی که در اینترنت رفت و آمد می‌کنند ، معمولا یکی از دو نوع زیر هستند :
 - توکن‌های Security Assertion Markup Language یا SAML که ساختار XMLی دارند و encode شده اند و داخل ساختارهای دیگر از قبیل پیغام‌های HTTP و SOAP جای می‌گیرند
 - Simple Web Token یا SWT که درون هدر‌های درخواست یا پاسخ HTTP جای میگیرند .(WS-Federation)
 
نوع متفاوتی از Token که وابسته به مکانیسم احراز هویت است، ایحاد شده است . برای مثال اگر از Claim با Windows Sign-in استفاده می‌کنید ، شیرپوینت 2010 ، شیئ UserIdentity را به شیئ ClaimIdentity نبدیل می‌کند و claim را تقویت کرده و Token حاصله را مدیریت می‌کند . (این نوع Toaken جزء SAML نمی‌شود)
 
تنها راه به گرفتن توکن‌های SAML ، استفاده از یک Provider برای SAML است . مانند Windows Live ID یا ADFS . [+ ] 

معماری برنامه‌های مبتنی بر Claim
نام مدل : Direct Hub Model 

نام مدل : Direct Trust Model
 

مزایا :
- مدیریت راحت‌تر برای multiple trust relationships دز ADFS نسبت به Sharepoint
- مدیریت ساده‌تر در single trust relationship در شیرپوینت و عدم نیاز به فراهم کننده‌های سفارشی سازی شده برای Claim
- قایلیت استفاده از ویژگی‌های ADFS برای پیگیری توزیع Token ها
- ADFS از هز دوی SAML و WS-Federation پشتیبانی می‌کند
- توزیع کننده ADFS اجازه می‌دهد تا خصیصه‌های LDAP را از AD استخراج کنید
- ADFS به شما اجازه استفاده از قواعد دستوری SQL را برای استخراج داده‌ها از دیگر پایگاه‌های داده می‌دهد
- کارایی و اجرای مناسب 

معایب :
- کند بودن
- عدم پشتیبانی از SAML-P
- نیازمند تعریف کاربر‌ها در AD یا نواحی مورد اطمینان 

مطالب
Angular Animation – بخش دوم

در قسمت قبل کلیات نحوه‌ی استفاده از Animation در Angular را مورد بررسی قرار دادیم. در این بخش قصد داریم نحوه‌ی اعمال Animation ‌های پیشرفته‌تری را مورد بررسی قرار دهیم. 


وضعیت void

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

درکل وضعیت void برای تعریف انیمیشنی در هنگام ورود و خروج المان به و از صفحه مورد استفاده قرار می‌گیرد. برای مثال گذار *=>void به تمامی المانهایی که view را ترک می‌کنند اعمال خواهد شد و void=>* به المانهایی که به view اضافه می‌شوند. 

قطعه کد زیر سبب تعریف انیمیشنی بر روی المنتهای ورودی و خروجی از صفحه خواهد شد: 

animations: [
  trigger('flyInOut', [
    transition('void => *', [
      style({transform: 'translateX(-100%)'}),
      animate(100)
    ]),
    transition('* => void', [
      animate(100, style({transform: 'translateX(100%)'}))
    ])
  ])
]

در این قطعه کد یک trigger به نام flyInOut تعریف شده است که در آن برای گذار ورود و خروج المنت در صفحه، انیمیشن تعریف شده است. همانطور که واضح است نیازی به تعریف حالت void، توسط تابع state وجود ندارد.

کد زیر نحوه استفاده از این trigger را نشان میدهد (با فرض اینکه لیستی از کاربران را در متغییر users داریم که با فراخوانی متد addNewUser یک آیتم به آن اضافه شده و با زدن دکمه Remove آیتم مورد نظر از لیست حذف می‌شود):

<ul>
  <li *ngFor="let user of users" [@flyInOut]>
    {{user.FirstName}}
    <button (click)="remove(user)">Remove</button>
    </li>
</ul>
<button (click)="addNewUser()">Add New User</button>

همچنین به جای void=>* در تابع transition، از :enter و به جای *=>void، از :leave می‌توان استفاده کرد. 

transition(':enter', [ ... ]); // void => *
transition(':leave', [ ... ]); // * => void

واضح است که شما می‌توانید از حالت void به هر حالت تعریف شده‌ی توسط خودتان نیز گذاری را تعریف کنید. برای مثال اگر قبلا حالت active و inactive را با استفاده از تابع state ساخته باشید، گذارهای زیر قابل تعریف خواهند بود و هیچگونه محدودیتی وجود نخواهد داشت:

transition('void => inactive', //...)

transition('inactive => void', //...)

transition('void => active', //..)

transition('active => void', //...)


کاربرد * در style

فرض کنید می‌خواهیم گذاری را تعریف کنیم که هنگام ورود المنت، در ابتدا ارتفاع المنت را به مقداری 0px تنظیم کرده و سپس همراه با یک انیمیشن، مقدار ارتفاع را به مقدار اصلی تنظیم خواهد کرد. چالشی که در اینجا وجود دارد این است که مقدار ارتفاع المنت مشخص نیست و بستگی به اندازه صفحه نمایش داشته و توسط آن css تنظیم خواهد شد. در اینجا می‌توان از * برای بدست آورن مقدار جاری یک خصوصیت از استایل استفاده کرد:

transition('void => *', [
   style({height: 0 }),
   animate(1000,style({ color: '*' }))
]),


انیمیشن چند مرحله‌ای با استفاده از Keyframes

تا اینجا تمامی انیمیشنهایی را که بررسی کردیم، یک انیمیشن یک مرحله‌ای بودند. در صورتیکه یک انیمیشن حرفه‌ای، متشکل از چند مرحله گذار خواهد بود. برای انجام اینکار از تابع Keyframes استفاده می‌کنیم. برای مثال می‌خواهیم انیمیشن ورود المنت را به صورتی در نظر بگیریم که المنت در ابتدا در نقطه -75% بالاتر از مکانی‌که در آنجا نمایش داده خواهد شد، با opacity صفر شروع  به حرکت کرده و در مرحله بعد به نقطه 35px پائین‌تر از مکان اصلی خود آمده و opacity نیم را خواهد داشت و در نهایت، با حرکت بعدی به جای اصلی خود خواهد رفت و opacity یک را پیدا می‌کند. 

animations: [
  trigger('flyInOut', [
    transition('void => *', [
      animate(300, keyframes([
        style({opacity: 0, transform: 'translateY(-75%)', offset: 0}),
        style({opacity: 0.5, transform: 'translateY(35px)',  offset: 0.3}),
        style({opacity: 1, transform: 'translateY(0)',     offset: 1.0})
      ]))
    ])    
  ])
]

تابع Keyframes آرایه‌ای از تابع style را دریافت می‌کند که هر تابع شامل خصوصیتهای انیمیشن به همراه یه خصوصیت offset است. این خصوصیت اختیاری است و مقدار صفر تا یک را قبول می‌کند و بیانگر زمان اجرای تابع style بعدی است.


رخداد شروع و پایان انیمیشن

با استفاده از @triggerName.start و @triggerName.done با شروع و پایان انیمیشن خود می‌توانید یک تابع سفارشی را نیز اجرا کنید. برای مثال کد زیر را در نظر بگیرید: 

template: `
  <ul>
    <li *ngFor="let hero of heroes"
        (@flyInOut.start)="animationStarted($event)"
        (@flyInOut.done)="animationDone($event)"
        [@flyInOut]="'in'">
      {{hero.name}}
    </li>
  </ul>
`,

در این مثال هنگام شروع انیمیشن تابع animationStarted و پس از اتمام انیمیشن، تابع animationDone اجرا خواهند شد. 

مطالب
آزمون واحد در MVVM به کمک تزریق وابستگی
یکی از خوبی‌های استفاده از Presentation Pattern‌ها بالا بردن تست پذیری برنامه و در نتیجه نگهداری کد می‌باشد.
MVVM الگوی محبوب برنامه نویسان WPF و Silverlight می‌باشد.  به صرف استفاده از الگوی MVVM نمی‌توان اطمینان داشت که ViewModel کاملا تست پذیری داریم. به عنوان مثلا اگر در ViewModel خود مستقیما DialogBox کنیم یا ارجاعی از View دیگری داشته باشیم نوشتن آزمون‌های واحد تقریبا غیر ممکن می‌شود. قبلا درباره‌ی این مشکلات و راه حل آن مطلب در سایت منتشر شده است : 
در این مطلب قصد داریم سناریویی را بررسی کنیم که ViewModel از Background Worker جهت انجام عملیات مانند دریافت داده‌ها استفاده می‌کند.
Background Worker کمک می‌کند تا اعمال طولانی در یک Thread دیگر اجرا شود در نتیجه رابط کاربری Freeze نمی‌شود.
به این مثال ساده توجه کنید : 
    public class BackgroundWorkerViewModel : BaseViewModel
    {
        private List<string> _myData;

        public BackgroundWorkerViewModel()
        {
            LoadDataCommand = new RelayCommand(OnLoadData);
        }

        public RelayCommand LoadDataCommand { get; set; }

        public List<string> MyData
        {
            get { return _myData; }
            set
            {
                _myData = value;
                RaisePropertyChanged(() => MyData);
            }
        }

        public bool IsBusy { get; set; }

        private void OnLoadData()
        {
            var backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += (sender, e) =>
                             {
                                 MyData = new List<string> {"Test"};
                                 Thread.Sleep(1000);
                             };
            backgroundWorker.RunWorkerCompleted += (sender, e) => { IsBusy = false; };
            backgroundWorker.RunWorkerAsync();
        }
    }

در این ViewModel با اجرای دستور LoadDataCommand داده‌ها از یک منبع داده دریافت می‌شود. این عمل می‌تواند چند ثانیه طول بکشد ، در نتیجه برای قفل نشدن رابط کاربر این عمل را به کمک Background Worker به صورت Async در پشت صحنه انجام شده است.
آزمون واحد این ViewModel اینگونه خواهد بود : 
    [TestFixture]
    public class BackgroundWorkerViewModelTest
    {
        #region Setup/Teardown

        [SetUp]
        public void SetUp()
        {
            _backgroundWorkerViewModel = new BackgroundWorkerViewModel();
        }

        #endregion

        private BackgroundWorkerViewModel _backgroundWorkerViewModel;

        [Test]
        public void TestGetData()
        {
              
            _backgroundWorkerViewModel.LoadDataCommand.Execute(_backgroundWorkerViewModel);

            Assert.NotNull(_backgroundWorkerViewModel.MyData);
            Assert.IsNotEmpty(_backgroundWorkerViewModel.MyData);
        }
    }

با اجرای این آزمون واحد نتیجه با آن چیزی که در زمان اجرا رخ می‌دهد متفاوت است و با وجود صحیح بودن کدها آزمون واحد شکست می‌خورد.
چون Unit Test به صورت همزمان اجرا می‌شود و برای عملیات‌های پشت صحنه صبر نمی‌کند در نتیحه این آزمون واحد شکست می‌خورد.

آزمون واحد شکست خورده

یک راه حل تزریق BackgroundWorker به صورت وابستگی به ViewModel می‌باشد. همانطور که قبلا اشاره شده یکی از مزایای استفاده از تکنیک‌های تزریق وابستگی  سهولت Unit testing می‌باشد.
در نتیجه یک Interface عمومی و 2  پیاده سازی همزمان و غیر همزمان جهت استفاده در برنامه‌ی واقعی و آزمون واحد تهیه می‌کنیم : 
   public interface IWorker
    {
        void Run(DoWorkEventHandler doWork);
        void Run(DoWorkEventHandler doWork, RunWorkerCompletedEventHandler onComplete);
    }
جهت استفاده در برنامه‌ی واقعی : 
    public class AsyncWorker : IWorker
    {
        public void Run(DoWorkEventHandler doWork)
        {
            Run(doWork, null);
        }

        public void Run(DoWorkEventHandler doWork, RunWorkerCompletedEventHandler onComplete)
        {
            var backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += doWork;
            if (onComplete != null)
                backgroundWorker.RunWorkerCompleted += onComplete;
            backgroundWorker.RunWorkerAsync();
            

        }
    }
جهت اجرا در آزمون واحد : 
    public class SyncWorker : IWorker
    {
        #region IWorker Members

        public void Run(DoWorkEventHandler doWork)
        {
            Run(doWork, null);
        }

        public void Run(DoWorkEventHandler doWork, RunWorkerCompletedEventHandler onComplete)
        {
            Exception error = null;
            var doWorkEventArgs = new DoWorkEventArgs(null);
            try
            {
                doWork(this, doWorkEventArgs);
            }
            catch (Exception ex)
            {
                error = ex;
                throw;
            }
            finally
            {
                onComplete(this, new RunWorkerCompletedEventArgs(doWorkEventArgs.Result, error, doWorkEventArgs.Cancel));
            }
        }

        #endregion
    }
در نتیجه ViewModel اینگونه تغییر خواهد کرد :
    public class BackgroundWorkerViewModel : BaseViewModel
    {
        private readonly IWorker _worker;
        private List<string> _myData;

        public BackgroundWorkerViewModel(IWorker worker)
        {
            _worker = worker;
            LoadDataCommand = new RelayCommand(OnLoadData);
        }

        public RelayCommand LoadDataCommand { get; set; }

        public List<string> MyData
        {
            get { return _myData; }
            set
            {
                _myData = value;
                RaisePropertyChanged(() => MyData);
            }
        }

        public bool IsBusy { get; set; }

        private void OnLoadData()
        {
            IsBusy = true; // view is bound to IsBusy to show 'loading' message.

            _worker.Run(
                (sender, e) =>
                    {
                        MyData = new List<string> {"Test"};
                        Thread.Sleep(1000);
                    },
                (sender, e) => { IsBusy = false; });
        }
    }

کلاس مربوطه به آزمون واحد را مطابق با تغییرات ViewModel :
    [TestFixture]
    public class BackgroundWorkerViewModelTest
    {
        #region Setup/Teardown

        [SetUp]
        public void SetUp()
        {
            _backgroundWorkerViewModel = new BackgroundWorkerViewModel(new SyncWorker());
        }

        #endregion

        private BackgroundWorkerViewModel _backgroundWorkerViewModel;

        [Test]
        public void TestGetData()
        {
              
            _backgroundWorkerViewModel.LoadDataCommand.Execute(_backgroundWorkerViewModel);

            Assert.NotNull(_backgroundWorkerViewModel.MyData);
            Assert.IsNotEmpty(_backgroundWorkerViewModel.MyData);
        }
    }

اکنون اگر Unit Test را اجرا کنیم نتیجه اینگونه خواهد بود :




 
نظرات مطالب
Lambda Syntax و کارآیی
تعریف متدهای بی نام (چه بصورت delegate{} و چه بصورت Lambda) مستلزم  ایجاد یک کلاس اضافه بهمراه تشکیل متد و متغیر‌های لازمه توسط کامپایلر هستند اما در مورد متدهای بانام (صریح) اغلب نیازی به ایجاد کلاسی مجزا نیست و توسط برنامه نویس معمولا در همان کلاس نوشته میشوند.
مسلماْ کامپایلر خیلی سریع‌تر از برنامه نویس‌ها میتوانند این موارد رو ایجاد کند.
پس قبل از اجرای برنامه متدها و هندلر‌ها وجود دارند و نمیتواند از این بابت در سرعت اجرا تاثیری داشته باشند. بنظر من تنها دلیل کندتر بودن (خیلی کم) متدهای بی نام در زمان اجرا این است که چون متدهای بی نام در کلاسی مجزا تعریف شده است نیاز به نمونه سازی (newobj ) دارند در حالی که متدهای بانام از این مورد مبرا هستند.
با این توصیف و با چشم پوشی نسبت به زمان اندکی که کامپایلر صرف متدهای بی نام میکند استفاده از متدهای بی نام بصرفه‌تر هستند و برنامه رو هم زیباتر و خواناتر میکنند.
نظرات مطالب
استفاده از Web API در ASP.NET Web Forms
- بله. گروه Web API و EF را در سایت پیگیری کنید.
- Web API یک بحث سمت سرور است. به آن به زبان ساده به چشم یک وب سرویس مدرن نگاه کنید. برای نمونه بجای وب‌متدهای استاتیک صفحات aspx یا فایل‌های ashx یا asmx و حتی سرویس‌های WCF از نوع REST و امثال آن، بهتر است از Web API استفاده کنید.  
- برای نمونه پایه مباحثی مانند Forms Authentication در اینجا هم کاربرد دارد (البته این یک نمونه است).
- برای کار با Web API الزاما نیازی به ASP.NET ندارید (نه وب فرم‌ها و نه MVC)؛ به هیچکدام از نگارش‌های آن. سمت کاربر آن AngularJS و سمت سرور آن Web API باشد. کار می‌کند. (اهمیت این مساله در اینجا است که الان می‌شود یک فریم ورک جدید توسعه‌ی برنامه‌های وب را کاملا مستقل از وب فرم‌ها و MVC طراحی کرد)
نظرات مطالب
چند نکته کاربردی درباره Entity Framework
- سورس آزمایش به عمد ارسال شد، تا بتونید خودتون اجراش کنید و اندازه گیری کنید. این‌ها چشم بندی نبوده یا نظر شخصی نیست. یک سری اندازه گیری است.
- توضیح دادم در انتهای همان آزمایش. برای تکرار مجدد: چون یکبار رفت و برگشت کمتری داره به دیتابیس. چون تغییر State یک شیء و ورود آن به سیستم ردیابی، خیلی سریعتر است از واکشی اطلاعات از بانک اطلاعاتی. اما در مورد لیستی از اشیاء، توسط context.Factors سیستم EF دسترسی به IDها پیدا می‌کنه (در هر دو حالت متصل و منقطع). اگر سیستم ردیابی خاموش شود، برای اتصال مجدد این‌ها زمان خواهد برد (چون IDهای دریافت شده از بانک اطلاعاتی ردیابی نمی‌شوند)، اما در حالت متصل، همان بار اولی که کوئری گرفته شده، همانجا اتصال هم برقرار شده و در حین به روز رسانی اطلاعات می‌داند چه تغییراتی رخ داده و چگونه سریعا باید محاسبات رو انجام بده. اما در حالت منقطع توسط متد DetectChanges تازه شروع به اتصال و محاسبه می‌کند.
نظرات مطالب
خلاصه‌ای کوتاه در مورد WinRT
خیر. به WinRT یا Windows run time جدید به چشم Silverlight run time نگاه کنید. لایه‌ای است بالاتر از Win32 API که برفراز آن‌ می‌شود برنامه توسعه داد (WPF فقط یک روش طراحی رابط کاربری جدید است، run time نیست). WinRT شبیه به همان مدل امنیتی بسته سیلورلایت را به ارث برده. همان لایه نمایش XAML را به ارث برده. با این تفاوت که این run time جدید آن علاوه بر XAML ، امکان کار با HTML5 و جاوا اسکریپت را هم می‌دهد و محدود به XAML نیست. برخلاف سیلورلایت، این run time فقط محدود به دات نت هم نیست و با CPP و Native کد هم می‌شود با آن کار کرد. به این نتیجه رسیدند که طراحی خوبی انجام دادن، خوب چرا فقط دات نت استفاده کند؟
ضمنا این محدودیت‌های امنیتی ذکر شده برای آن قطعا برای خیلی از برنامه نویس‌ها خوشایند نخواهد بود. برای دسترسی بیشتر، مجبور خواهند شد به سیستم‌های دسکتاپ سابق رجوع کنند.
مطالب
قابلیت های جدید VisualStudio.NET 2012 - قسمت دوم
در ادامه قسمت اول  به برخی دیگر از قابلیت‌های جدید VisualStudio.NET 2012 می‌پردازیم.

بهبود ویرایشگر JavaScript:
یکی دیگر از قابلیت‌های جدیدی که در VS.NET 2012 چشم نوازی می‌کند، اضافه شدن گزینه Go To Definition در بخش ویرایشگر کد جاوااسکریپت است. کاملاً روشن است که جاوااسکریپت جان دوباره ای گرفته است و امروزه شاهد حضور بیش از پیش و مؤثر آن در برنامه‌های تحت وب هستیم و گویا دوستان ما در تیم توسعه VisualStudio.NET در تلاش هستند تا ما را خوشحال کنند!


ارتقاء ویرایشگر CSS:
ویرایشگر CSS هم در نوع خود بسیار بهتر از پیش عمل می‌کند. از قابلیت‌های جدید آن می‌توان به Color-Picker اشاره داشت. همچنین امکان Comment و Un-Comment کردن کد‌ها با اضافه شدن دکمه هایی در نوار ابزار آسان‌تر شده است.


انتخاب مرورگر، این بار در Toolbar:
اضافه شدن امکان انتخاب مرورگر در نوار ابزار هم در نوع خود جالب است و موجب خوش دستی بیش از پیش VS.NET شده است:

نظرات نظرسنجی‌ها
کدامیک از قلم‌های فارسی ذیل خواناتر هستند؟
عموما این ناراضی زمانی دیده میشه که از کاربران نظرسنجی بشه. کاربران فقط یک موقع خودجوش اعتراض میکنن که فونت واقعا خیلی مشکل داشته باشه یا سال‌ها با یک فونت کار کرده باشند و در یک مرحله زمانی فونت به یک نمونه بدتر تغییر پیدا کنه.
در بقیه حالات حتی اگ هم ناراضی باشن سخنی نمی‌گویند ولی در یک نظرسنجی که کاربر دو نمونه رو ببینه میشه به نکات مهمتری رسید. فونت یکان یکی از فونت‌های مورد علاقه من هست ولی در وب رضایت چندانی ازش ندارم. هر چند تا مدت‌ها جز معدود فونت‌های مجاز و خوب بود. دلیل اینکه ازش ناراضی هستم این هست که چندان برای وب بهینه نیست و در حالت‌های سایز خیلی بزرگ و کوچک فرم خودش رو از دست میده ولی وزیر و صمیم این مشکل چندان حاد نیست. چون بسیار بهینه‌تر شدند یا مثلا تاهما تا موقعی که 9pt هست بسیار خوب عمل می‌کنه، بزرگتر بشه به یک فاجعه تبدیل میشه. من از صمیم راضی هستم چون واقعا برای خواندن مطالب بلند برای چشم عالی هست. خیلی حالت رسمی داره.
مطالب
روش صحیح تست DateTime در NUnit و MSTest
وقتی ما تست‌های Unit - Integration - UI را می‌نویسیم، به طور معمول پیش می‌آید که بخواهیم آبجکتی را نیز از نوع DateTime، اثبات کنیم (Assert.That). وقتی دو DateTime را با هم مقایسه می‌کنیم، معمولا این دو به خاطر ثانیه و یا میلی ثانیه با هم برابر نمی‌شوند. به همین دلیل ما به راه بهتری برای مقایسه نیاز داریم. برای مثال اگر بخواهیم دو تاریخ زیر را مقایسه کنیم:
2016-11-13 21:03:20  <=>  2016-11-13 21:03:21  
این دو تاریخ تقریبا با هم برابرند و تنها 1 ثانیه با هم اختلاف دارند. در بیشتر موارد 1 ثانیه مسئله مهمی نیست و قابل چشم پوشی می‌باشد. بنابراین ما نیاز به متدی برای اثبات داریم که بتوانیم آن را برای چشم پوشی از 1 ثانیه اختلاف، تنظیم کنیم.

چگونگی اثبات کردن DateTime در NUnit

NUnit  با استفاده از کلمه کلیدی Within این کار را به صورت کامل پشتیبانی کرده است.
DateTime now = DateTime.Now;
DateTime later = now + TimeSpan.FromHours(1.0);

Assert.That( now, Is.EqualTo(now) );
Assert.That( later, Is.EqualTo(now).Within( TimeSpan.FromHours(3.0) ) );
Assert.That( later, Is.EqualTo(now).Within(3).Hours );
بنابراین نیازی به پیاده سازی متد سفارشی نیست.

چگونگی اثبات کردن DateTime در MSTest

با استفاده از متد AreEqual در کلاس زیر می‌توان دو تاریخ را با هم مقایسه کرد و میزان اختلاف قابل چشم پوشی را نیز با استفاده از پارامتر maximum تعیین کرد.
public static class DateTimeAssert
{
    public static void AreEqual( DateTime? expectedDate,
                                 DateTime? actualDate,
                                 TimeSpan maximum )
    {
        if ( expectedDate == null && actualDate == null )
            return;

        if ( expectedDate == null )
            throw new NullReferenceException( "The expected date was null" );

        if ( actualDate == null )
            throw new NullReferenceException( "The actual date was null" );

        var totalSecondsDifference = Math.Abs( ( actualDate.Value - expectedDate.Value ).TotalSeconds );
        if ( totalSecondsDifference > maximum.TotalSeconds )
        {
            throw new Exception( $"Expected Date: {expectedDate}, Actual Date: {actualDate} Expected: {maximum}, Total Seconds Difference: {totalSecondsDifference}" );
        }
    }
}
برای استفاده:
DateTimeAssert.AreEqual( new DateTime(2016, 11, 12, 21, 4, 5),
                         new DateTime(2016, 11, 13, 21, 4, 5),
                         TimeSpan.FromMilliSeconds(500));
DateTimeAssert.AreEqual( new DateTime(2016, 11, 12, 21, 4, 5),
                         new DateTime(2016, 11, 13, 21, 4, 5),
                         TimeSpan.FromMinutes(0.5)); // half a minute = 30s