مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 11 - بررسی بهبودهای Razor
زبان Razor نیز در ASP.NET Core به همراه بهبودها و اضافات قابل توجهی است که در این قسمت تعدادی از آن‌ها را مانند امکان ارث بری و تزریق وابستگی‌ها، بررسی خواهیم کرد.

نحوه‌ی سفارشی سازی کلاس پایه‌ی تمام Viewهای برنامه و معرفی inherits@

در نگارش‌های پیشین ASP.NET MVC، امکان تعویض کلاس پایه‌ی Viewها، در فایل web.config واقع در پوشه‌ی ریشه‌ی Views وجود داشت. با حذف این فایل و ساده سازی و محول کردن مسئولیت‌های آن به فایل جدید view imports، اینبار برای تعریف کلاس پایه‌ی viewها می‌توان به صورت ذیل عمل کرد:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Razor;
 
namespace Core1RtmEmptyTest.StartupCustomizations
{
    public abstract class MyCustomBaseView<TModel> : RazorPage<TModel>
    {
        public bool IsAuthenticated()
        {
            return Context.User.Identity.IsAuthenticated;
        }
 
#pragma warning disable 1998
        public override async Task ExecuteAsync()
        {
        }
#pragma warning restore 1998
    }
}
به صورت پیش فرض تمام viewهای برنامه از کلاس <RazorPage<T ارث بری می‌کنند؛ که در اینجا T، نوع مدلی است که توسط model@ تنظیم می‌شود. اگر نیاز به سفارشی سازی این کلاس وجود داشت، برای مثال بجای اینکه هربار در viewها مقدار Context.User.Identity.IsAuthenticated را جهت نمایش قسمتی از صفحه، به کاربران اعتبارسنجی شده بررسی کنیم، می‌توان این قطعه کد را به یک کلاس پایه‌ی سفارشی منتقل و از آن در تمام Viewها استفاده کرد که نمونه‌ای از آن‌را در کدهای فوق مشاهده می‌کنید.
پس از تعریف این کلاس، برای ثبت و معرفی آن به فایل ViewImports.cshtml_ مراجعه کنید و این یک سطر را به ابتدای آن اضافه نمائید:
@inherits Core1RtmEmptyTest.StartupCustomizations.MyCustomBaseView<TModel>
inherits@ از تازه‌های razor بوده و جهت تعریف ارث بری‌ها کاربرد دارد. البته ممکن است در حین تعریف فوق، TModel را قرمز رنگ مشاهده کنید که مهم نیست و بیشتر مشکل ReSharper است و برنامه بدون مشکل اجرا می‌شود.
برای نمونه پس از سفارشی سازی صفحه‌ی پایه‌ی تمام Viewها، اکنون یک سطر ذیل را در هر view ایی می‌توان تعریف و استفاده کرد:
 Is Current User Authenticated? @IsAuthenticated()


معرفی functions@

دایرکتیو جدید functions@، بسیار شبیه است به دایرکتیو قدیمی و حذف شده‌ی helper@، که در نگارش‌های پیشین Razor معرفی شده بود:
@functions
 {
    public string Test()
    {
        return message;
    }
 
    readonly string message = "test";
}
ASP.NET Core در حین پردازش یک View، کدهای آن‌را تبدیل به یک کلاس می‌کند و در اینجا تمام کدهای داخل بدنه‌ی functions@ را نیز به صورت اعضای این کلاس تعریف خواهد کرد. به این ترتیب یک چنین فراخوانی‌هایی در View میسر می‌شوند:
 @Test()
<br />
@message


معرفی inject@

توسط دایرکتیو جدید inject@، یک خاصیت عمومی به ASP.NET Core اعلام می‌شود و سپس مقدار دهی آن بر اساس تنظیمات IoC Container برنامه به صورت خودکار صورت خواهد گرفت. برای مثال زمانیکه می‌خواهیم به سرویس توکار HostingEnvironment در یک  View دسترسی پیدا کنیم، می‌توان در ابتدای آن نوشت:
 @inject Microsoft.AspNetCore.Hosting.IHostingEnvironment Host;
در این حالت کد فوق از دیدگاه ASP.NET Core به صورت ذیل تفسیر می‌شود:
 [Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public Microsoft.AspNetCore.Hosting.IHostingEnvironment Host { get; private set; }
این خاصیت عمومی نیز با توجه به از پیش ثبت شده بودن سرویس IHostingEnvironment  و مشخص شدن توسط RazorInjectAttribute، توسط IoC Container آن شناسایی شده و تامین می‌شود.
اکنون برای استفاده‌ی از آن خواهیم داشت:
 <div>
 Running in @Host.EnvironmentName
</div>
البته استفاده‌ی از inject@ شاید به نوعی سؤ استفاده‌ی از الگوی MVC به شما رود؛ از این جهت که اطلاعات مورد نیاز یک View، باید از طریق کنترلر آن تامین شود و خود View نباید به صورت مستقیم درخواست تامین آ‌ن‌ها را بدهد. اما باید دقت داشت که در نهایت View نیاز دارد تا کدها را اجرا کرده و خروجی را تولید کند و برای این منظور، در پشت صحنه سرویس‌های زیادی مانند IUrlHelper ، IViewComponentHelper ، IHtmlHelper و غیره به همین ترتیب در اختیار آن قرار می‌گیرند. به علاوه استفاده‌ی از تزریق وابستگی‌ها بهتر است از روش ارث بری صفحات پایه، از این جهت که انتخاب composition همواره مقدم است بر inheritance و سبب انعطاف پذیری بیشتری نسبت به قبل می‌گردد. داشتن یک صفحه‌ی پایه که بتواند تمام نیازهای انواع و اقسام Viewها را تامین کند، دور از انتظار و گاهی از اوقات، سبب سنگینی بیش از حد پردازش تمام Viewها خواهد شد. اما تزریق سرویس‌هایی اینچنینی جهت تامین نیازهای اولیه و تکراری یک یا چند View خاص، کل برنامه را سنگین نکرده و همچنین انعطاف پذیری بیشتری را در جهت تامین آن‌ها فراهم می‌کند.
به علاوه باید دقت داشت اگر تعریف inject@ فوق را در فایل view import قرار دهیم، این سرویس در اختیار تمام Viewهای برنامه قرار خواهد گرفت و دیگر نیازی به قرار دادن آن در یک کلاس پایه‌ی سفارشی نیست.
یکی از مفیدترین استفاده‌های از قابلیت تزریق سرویس‌ها در Viewها می‌تواند دسترسی به سرویس تامین تنظیمات برنامه باشد (که در مورد نحوه‌ی تامین آن در مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 7 - کار با فایل‌های config» بیشتر بحث شد):
 @inject IOptions<SmtpConfig> Settings;
مطالب
ModelBinder سفارشی در ASP.NET MVC
زمانی که درخواستی به سمت یک Action پارامتر دار ارسال میشود، قسمت  ActionInvoker قبل از فراخوانی اکشن مربوطه، به دنبال Model Binder مناسبی برای داده‌های پارامترها می‌گردد و در صورت یافت نشدن، از ModelBinder پیش فرض ASP.NET MVC استفاده می‌کند.
اما وظیفه‌ی ModelBinder چیست ؟
ModelBinder  داده‌های ارسال شده از مرورگر را که توسط درخواست‌های HTTP (کوئری استرینگ‌ها و یا داده‌های همراه با فرم‌ها ) ارسال شده است، تبدیل به داده‌های قابل فهم برای پارامترها میکند.
به عبارتی ModelBinder وظیفه تبدیل داده‌های ارسال شده از سمت مرورگر به اشیاء NET. را دارد.
فرض کنید ما مدلی به شکل زیر داریم :
public class CustomerInfo
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
}
فیلد آخر برای ذخیره‌ی تاریخ تولد مشتری استفاده میشود. که View مربوط به آن به شکل زیر خواهد بود :

همانطور که می‌بینید تایپ کردن تاریخ به این صورت (1/1/2009  12:00:00 AM) ، هم زیاد جالب نیست و هم کمی مشکل است. به همین دلیل برخی سایت‌ها  از سه قسمت جدا برای گرفتن روز ، ماه و سال استفاده می‌کنند و در نهایت آنها را با یکدیگر ترکیب میکنند.
در این مثال ما نیز می‌خواهیم تاریخ را به صورت زیر دریافت و پس از تبدیل آن به تاریخ میلادی، آن را به کاربر نمایش دهیم :

اما هنگام ارسال فرم  به صورت بالا ، ModelBinder  توانایی تبدیل این سه ورودی (روز ، ماه و سال)  به فیلد BirthDate موجود در کلاس CustomerInfo را ندارد. به همین خاطر ما باید یک ModelBinder متناسب با نیاز خود را طراحی کنیم.
برای ایجاد یک ModelBinder  سفارشی نیاز است که از کلاس IModelBinder ارثبری و متد BindModel آن را پیاده سازی کنیم.
ساختار این اینترفیس به شکل زیر است :
public interface IModelBinder
{ 
    object BindModel(ControllerContext controllerContext, 
        ModelBindingContext bindingContext); 
}
متد BindModel حاوی 2 پارامتر است :
ControllerContext : حاوی اطلاعاتی در مورد درخواست http جاری 
ModelBindingContext : این کلاس حاوی یک property به نام Model  است که حاوی ارجاعی به مدلی که همکنون قصد پردازشش آن را دارد.
با توجه به موارد بالا کلاس ما به شکل زیر خواهد بود :
using System;
using System.Web;
using System.Web.Mvc;
using ModelBinderExample.Models;
using Persia;

namespace ModelBinderExample.CustomModelBinder
{
    // Article written for www.dotnettips.info
    public class CustomerInfoModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            HttpRequestBase request = controllerContext.HttpContext.Request;

            string firstName = request.Form.Get("FirstName");
            string lastName  = request.Form.Get("LastName");

            DateTime birthDate = this.GetMiladiDate(request);

            return new CustomerInfo()
            {
                FirstName = firstName,
                LastName  = lastName,
                BirthDate = birthDate
            };
        }

        private DateTime GetMiladiDate(HttpRequestBase request)
        {
            int day   = int.Parse(request.Form.Get("Day"));
            int month = int.Parse(request.Form.Get("Month"));
            int years = int.Parse(request.Form.Get("Years"));

            //Convert shamsi to miladi
            return Persia.Calendar.ConvertToGregorian(years, month, day, DateType.Gerigorian);
        }
    }
}
در کد بالا ایتدا موارد ارسال شده را دریافت میکنیم و توسط متد ()GetMiladiDate تاریخ دریافتی از کاربر که به صورت روز، ماه و سال میباشد را  تبدیل به میلادی میکنیم و سپس در قالب یک شی customerInfo آنها را برگشت می‌دهیم.
نکته : جهت تبدیل تاریخ شمسی به میلادی از کتابخانه‌ی Persia کمک گرفته شده است که در فایل پیوستی قرار داده شده.
کار ایجاد یک ModelBinder سفارشی تمام شده و حال نیاز است کلاس را در فایل Global.asax  در قسمت ()Application_start ثبت کنیم به شکل زیر :
protected void Application_Start()
{
     AreaRegistration.RegisterAllAreas();

     WebApiConfig.Register(GlobalConfiguration.Configuration);
     FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
     RouteConfig.RegisterRoutes(RouteTable.Routes);
     //Register New ModelBinder
     ModelBinders.Binders.Add(typeof(CustomerInfo), new CustomerInfoModelBinder());
}
و برای استفاده از این ModelBinder ، ما باید به کنترلر اطلاع دهیم که میخواهیم از چه نوع Binding استفاده کنیم به همین دلیل از attribute زیر برای انجام این کار استفاده می‌کنیم: 
[HttpPost]
public ActionResult Create([ModelBinder(typeof (CustomerInfoModelBinder))] CustomerInfo customerInfo)
{
      if (ModelState.IsValid)
      {
           ViewBag.FirstName = customerInfo.FirstName;
           ViewBag.LastName = customerInfo.LastName;
           ViewBag.BirthDate = customerInfo.BirthDate;
      }
      return View();
}

پروژه پیوستی : ModelBinder-Example.zip
مطالب
مقید سازی پارامترهای نوع جنریک
احتمالا در بیشتر مقالات (فارسی/انگلیسی) عبارات هایی مثل نمونه‌های زیر را دیده اید :
where T:clas
where T:struc
...
در این مقاله قصد داریم بپردازیم به «مقید سازی پارامتر‌های نوع جنریک» و اینکه چه کاربردی دارند و در چه زمانی بهتر است از آن‌ها استفاده کنیم و نحوه استفاده از آنها چگونه است. فرض میکنیم که خواننده‌ی محترم با مفاهیم جنریک آشنایی دارد. در صورتیکه با جنریک‌ها آشنا نیستید ابتدا مروری داشته باشید بر جنریک‌ها و بعد این مقاله را مطالعه فرمایید؛ به این دلیل که موضوع مورد بحث بر پایه‌ی جنریک‌ها می‌باشد.

همانطور که مطلع هستید هر عنصری جنریکی را که تعریف میکنید حداقل دارای یک پارامتر نوع هست و در زمان بکارگیری آن جنریک باید نوع آن را مشخص نمایید. برای نمونه مثال زیر را در نظر بگیرید :
public  class MyCollection<T>
        {
            private List<T> collections = new List<T>();
            public void Add(T value)
            {
                collections.Add(value);
            }
        }
کلاس فوق یک کلاس جنریک است که در هنگام ساخت نمونه‌ای از آن، باید ابتدا data type نوعی را که که می‌خواهیم با آن کار کنیم، تعیین کنیم. برای مثال در کد فوق در هنگام ساخت نمونه‌ای از آن، نوع int را برای آن مشخص میکنیم و هر وقت بخواهیم متد Add آن را فراخوانی کنیم، فقط نوعی را قبول خواهد کرد که در ابتدا برای آن تعیین کرده ایم (int):
MyCollection<int> myintObj = new MyCollection<int>();
            myintObj.Add(12);
            myintObj.Add(33);
             myintObj.Add(33.3);// ERROR z 
سؤال: می‌خواهیم فقط نوع‌هایی را بتوان به T نسبت داد که از نوع ارجاعی (reference type) هستن و یا فقط نوع هایی را به T نسبت داد که یک سازنده دارند؛ چگونه؟

ایجاد قید‌ها یا محدودیت‌ها بر روی پارامتر‌های جنریک‌ها شامل پنج حالت می‌باشد:

حالت اول : Where T:struct
در این حالت T باید یک ساختار باشد .

حالت دوم : where T:class
T  باید یک نوع ارجاعی باشد. اگر در مثال فوق این قید را به آن اضافه کنیم، در هنگام ساخت نمونه‌ای از کلاس فوق، اگر یک نوع value type را به T نسبت دهیم، در هنگام وارد کردن یک نوع value type با خطا مواجه خواهیم شد. مثال:
public  class MyCollection<T> where T:class
        {
            private List<T> collections = new List<T>();
            public void Add(T value)
            {
                collections.Add(value);
            }
        }
و برای استفاده :
 MyCollection<int> myintObj = new MyCollection<int>(); // ERROR , int is value type

حالت سوم : ()Where T:new
نوعی که به T نسبت داده می‌شود باید یک سازنده‌ی پیش فرض داشته باشد.
داخل پرانتز : سازنده‌ی پیش فرض: زمانی که شما یک کلاس می‌نویسید اگر آن کلاس دارای هیچ سازنده‌ای نباشد، کامپایلر یک سازنده‌ی بدون پارامتر را به کلاس فوق اضافه می‌کند که کار آن مقدار دهی به فیلد‌های کلاس است. در اینجا از مقادیر پیش فرض استفاده می‌شود. مثلا برای int مقدار صفر و برای string مقدار "" و به همین ترتیب.
اگر از مقدار دهی پیش فرض توسط کامپایلر خرسند نیستید، می‌توانید سازنده پیش فرض را تغییر داده و مطابق میل خود فیلد‌ها را مقدار دهی اولیه کنید .


حالت چهارم : where T:NameOfBaseClass
نوعی که به T نسبت داده می‌شود باید از کلاس NameOfBaseClass ارث بری کرده باشد.

حالت پنجم : where T:NameOfInterface
همانند حالت چهارم می‌باشد؛ با این تفاوت: نوعی که به T نسبت داده می‌شود باید واسط NameOfInterface را پیاده سازی کرده باشد.

پنج حالت فوق نمونه‌هایی از ایجاد محدودیت بر روی پرامتر نوع اعضای جنریک بودند و اما در ادامه قصد داریم نکاتی را در این باب، بیان کنیم:

نکته اول : می‌توانید محدودیت‌های فوق را با هم ترکیب کنید برای اینکار آنها را با کاما از هم جدا کنید :
 public  class MyCollection<T> where T:class,IDisposable,new()
        {
   //content
}
نوعی که به T نسبت داده می‌شود
  • باید از نوع ارجاعی باشد.
  • باید واسط IDisposable را پیاده سازی کرده باشد.
  • باید یک سازنده‌ی پیش فرض داشته باشد.

نکته دوم : زمانیکه از چندین محدودیت استفاده می‌کنید مثل مثال فوق، باید محدودیت ()new در آخرین جایگاه محدودیت‌ها قرار گیرد؛ در غیر اینصورت با خطای زمان ترجمه روبه رو خواهید شد .

نکته سوم : می‌توان محدودیت‌های فوق را علاوه بر کلاس، بر روی متد‌های جنریک نیز اعمال کنید:

public void Swap<T>(ref T val1,ref T val2) where T:struct
            {
//content
            }
نکته چهارم : زمانیکه کلاس و یا متدهای شما بیش از یک نوع پارامتر از نوع جنریک را دریافت می‌کنند، باید محدودیت‌های مورد نظر را برای هر کدام به صورت جداگانه قید کنید. به طور مثال به کلاس زیر که دو پارمتر T و K را دارد، باید برای هر کدام جداگانه محدودیت‌های مورد نظر را اعمال کنیم (در صورت نیاز):
 public  class MyCollection<T,K> where T:class where K:IDisposable,new()
        {
//content
}
نظرات مطالب
VS Code برای توسعه دهندگان ASP.NET Core - قسمت اول - نصب و راه اندازی
نکته تکمیلی
الان که آخرین نسخه Vs Code رو دانلود کردم، در بخش File->Preferences->Settings، ادیتور Workspace Settings رو که تنظیمات ورک اسپیس جاری را نگه میدارد، مطابق آموزش نداشت (نام آن به صورت خلاصه، Workspace شده):

باید خودتون در پوشه .vscode روت برنامتون یک فایل با نام Settings.json ایجاد کنید یا اینکه در تب Workspace کنار تب User حداقل یکی از تنظیمات رو تغییر بدید تا به صورت خودکار فایل Settings.json به همراه تنظیماتی که اعمال کردید در پوشه .vscode روت برنامتون ایجاد شود، حال که فایل مربوطه ایجاد شده است، میتوانید آن تنظیماتی را که تغییر داده اید به حالت اول برگردانید.
مطالب
آشنایی با الگوی MVP

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

یکی از الگوهایی که شیوه‌ی صحیح این جدا سازی را ترویج می‌کند، الگوی MVP یا Model-View-Presenter می‌باشد. خلاصه‌ی این الگو به صورت زیر است:


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

View :
من می‌دانم که چگونه باید اطلاعاتی را به کاربر به شکلی بصری ارائه داد.
من می‌دانم که چگونه باید اعمالی مانند data binding و امثال آن را انجام داد.
من نمی‌دانم که چگونه باید منطق پردازشی موارد ذکر شده را فراهم آورم.

Presenter :
من می‌دانم که چگونه باید درخواست‌های رسیده کاربر به View را دریافت کرده و آن‌ها را به Model‌ انتقال دهم.
من می‌دانم که چگونه باید اطلاعات را به Model ارسال کرده و سپس نتیجه‌ی پردازش آن‌ها را جهت نمایش در اختیار View قرار دهم.
من نمی‌دانم که چگونه باید اطلاعاتی را ترسیم کرد (مشکل View است نه من) و نمی‌دانم که چگونه باید پردازشی را بر روی اطلاعات انجام دهم. (مشکل Model است و اصلا ربطی به اینجانب ندارد!)


یک مثال ساده از پیاده سازی این روش
برنامه‌ای وبی را بنویسید که پس از دریافت شعاع یک دایره از کاربر، مساحت ‌آن‌را محاسبه کرده و نمایش دهد.
یک تکست باکس در صفحه قرار خواهیم داد (txtRadius) و یک دکمه جهت دریافت درخواست کاربر برای نمایش نتیجه حاصل در یک برچسب به نام lblResult

الف) پیاده سازی به روش متداول (اسپاگتی کد)

protected void btnGetData_Click(object sender, EventArgs e)
{
lblResult.Text = (Math.PI * double.Parse(txtRadius.Text) * double.Parse(txtRadius.Text)).ToString();
}
بله! کار می‌کنه!
اما این مشکلات را هم دارد:
- منطق برنامه (روش محاسبه مساحت دایره) با رابط کاربر گره خورده.
- کدهای برنامه در پروژه‌ی دیگری قابل استفاده نیست. (شما متد یا کلاسی را این‌جا با قابلیت استفاده مجدد می‌توانید پیدا می‌کنید؟ آیا یکی از اهداف برنامه نویسی شیءگرا تولید کدهایی با قابلیت استفاده مجدد نبود؟)
- چگونه باید برای آن آزمون واحد نوشت؟

ب) بهبود کد و جدا سازی لایه‌ها از یکدیگر

در روش MVP متداول است که به ازای هر یک از اجزاء ابتدا یک interface نوشته شود و سپس این اینترفیس‌ها پیاده سازی گردد.

پیاده سازی منطق برنامه:

1- ایجاد Model :
یک فایل جدید را به نام CModel.cs به پروژه اضافه کرده و کد زیر را به آن خواهیم افزود:

using System;

namespace MVPTest
{
public interface ICircleModel
{
double GetArea(double radius);
}

public class CModel : ICircleModel
{
public double GetArea(double radius)
{
return Math.PI * radius * radius;
}
}
}
همانطور که ملاحظه می‌کنید اکنون منطق برنامه از موارد زیر اطلاعی ندارد:
- خبری از textbox و برچسب و غیره نیست. اصلا نمی‌داند که رابط کاربری وجود دارد یا نه.
- خبری از رخ‌دادهای برنامه و پاسخ دادن به آن‌ها نیست.
- از این کد می‌توان مستقیما و بدون هیچ تغییری در برنامه‌های دیگر هم استفاده کرد.
- اگر باگی در این قسمت وجود دارد، تنها این کلاس است که باید تغییر کند و بلافاصله کل برنامه از این بهبود حاصل شده می‌تواند بدون هیچگونه تغییری و یا به هم ریختگی استفاده کند.
- نوشتن آزمون واحد برای این کلاس که هیچگونه وابستگی به UI ندارد ساده است.


2- ایجاد View :
فایل دیگری را به نام CView.cs را به همراه اینترفیس زیر به پروژه اضافه می‌کنیم:

namespace MVPTest
{
public interface IView
{
string RadiusText { get; set; }
string ResultText { get; set; }
}
}

کار View دریافت ابتدایی مقادیر از کاربر توسط RadiusText و نمایش نهایی نتیجه توسط ResultText است البته با یک اما.
View نمی‌داند که چگونه باید این پردازش صورت گیرد. حتی نمی‌داند که چگونه باید این مقادیر را به Model جهت پردازش برساند یا چگونه آن‌ها را دریافت کند (به همین جهت از اینترفیس برای تعریف آن استفاده شده).

3- ایجاد Presenter :
در ادامه فایل جدیدی را به نام CPresenter.cs‌ با محتویات زیر به پروژه خواهیم افزود:

namespace MVPTest
{
public class CPresenter
{
IView _view;

public CPresenter(IView view)
{
_view = view;
}

public void CalculateCircleArea()
{
CModel model = new CModel();
_view.ResultText = model.GetArea(double.Parse(_view.RadiusText)).ToString();
}
}
}

کار این کلاس برقراری ارتباط با Model است.
می‌داند که چگونه اطلاعات را به Model ارسال کند (از طریق _view.RadiusText) و می‌داند که چگونه نتیجه‌ی پردازش را در اختیار View قرار دهد. (با انتساب آن به _view.ResultText)
نمی‌داند که چگونه باید این پردازش صورت گیرد (کار مدل است نه او). نمی‌داند که نتیجه‌ی نهایی را چگونه نمایش دهد (کار View است نه او).
روش معرفی View به این کلاس به constructor dependency injection معروف است.

اکنون کد وب فرم ما که در قسمت (الف) معرفی شده به صورت زیر تغییر می‌کند:

using System;

namespace MVPTest
{
public partial class _Default : System.Web.UI.Page, IView
{
protected void Page_Load(object sender, EventArgs e)
{
}

public string RadiusText
{
get { return txtRadius.Text; }
set { txtRadius.Text = value; }
}
public string ResultText
{
get { return lblResult.Text; }
set { lblResult.Text = value; }
}

protected void btnGetData_Click(object sender, EventArgs e)
{
CPresenter presenter = new CPresenter(this);
presenter.CalculateCircleArea();
}
}
}

در این‌جا یک وهله از Presenter برای برقراری ارتباط با Model ایجاد می‌شود. همچنین کلاس وب فرم ما اینترفیس View را نیز پیاده سازی خواهد کرد.

مطالب
تزریق وابستگی (Dependency Injection) و توسعه پذیری
دانستن اینکه چگونه یک نرم افزار با قابلیت نگهداری بالا بنویسیم مهم است ، برای اکثر سیستم‌های سازمانی زمانی که در فاز نگهداری صرف می‌شود بیشتر از زمان فاز توسعه می‌باشد. به عنوان مثال تصور کنید در حال توسعه یک سیستم مالی هستید ، این سیستم احتمالا بین شش ماه تا یک زمان برای توسعه نیاز دارد و بقیه‌ی دوره‌ی پنج ساله صرف نگهداری سیستم خواهد شد. در فاز نگهداری زمان صرف رفع باگ ، افزودن امکانات جدید و یا تغییر عملکرد ویژگی‌های فعلی می‌شود. مهم است که این تغییرات راحت و سریع صورت پذیرد.
 اطمینان از اینکه کدها قابلیت نگهداری دارند به توسعه دهندگان احتمالی که در آینده به پروژه اضافه می‌شوند کمک می‌کند سریع کد‌های فعلی را درک کنند و مشغول کار شوند. روش‌های زیادی برای افزایش قابلیت نگهداری کد‌ها وجود دارد ، مانند نوشتن آزمون‌های واحد ، شکستن قسمت‌های بزرگ سیستم به قسمت‌های کوچک‌تر و ... در این مورد که ما از یکی از زبان‌های شئ گرا مانند C# استفاده می‌کنیم در حالت معمول کلاس‌ها باید با مسئولیت‌های مستقل و منحصر به فرد طراحی شوند به جای آنکه تمام مسئولیت‌ها از قبیل پردازش ورودی‌های کاربر ، رندر کردن HTML و حتی Query زدن به دیتابیس را به یک کلاس سپرد (مثلا Controller در MVC ) باید برای هر مقصود کلاسی مجزا طراحی کرد. با این روش نتیجه اینگونه خواهد بود که می‌توان هر قسمت از عملکرد را بدون نیاز به تغییر بقیه‌ی قسمت‌های Codebase تغییر داد.
در این مطلب قصد داریم به کمک تزریق وابستگی (ِDependency Injection) قسمت‌های مستقلتری توسعه دهیم. تکنیک تزریق وابستگی را نمی‌توان در یک مطلب وبلاگ و حتی یک فصل کامل از یک کتاب کامل تشریح کرد ، اگر جستجو کنید کتاب‌ها و آموزش‌های ویدویی زیادی هستند که فقط روی این تکنیک بحث و آموزش دارند. برای بیان مفهوم DI مثالی از یک سیستم ساده‌ی "چاپ اسناد" ارائه می‌کنیم ، این سیستم ممکن است کار‌های متفاوتی انجام دهد :
 این سیستم ابتدا باید یک سند را تحویل بگیرد ، سپس باید آن را به فرمت قابل چاپ در آورد و در انتها باید عمل اصلی چاپ را انجام دهد. برای اینکه سیستم ما ساختار خوبی داشته باشد می‌توان هر وظیفه را به کلاسی مجزا سپرد :
 کلاس Document : این کلاس اطلاعات سندی که قرار است چاپ شود را نگه می‌دارد.
کلاس DocumentRepository : این کلاس وظیفه‌ی بازیابی سند از فایل سیستم (یا هر منبع دیگری) را دارد.
 کلاس DocumentFormatter : یک وهله از سند را جهت چاپ آماده می‌کند.
کلاس Printer : مسئولیت ارتباط با سخت افزار Printer را دارد.
کلاس DocumentPrinter : مسئولیت سازماندهی اجزا سیستم را بر عهده دارد.
 در این مطلب پیاده سازی بدنه‌ی کلاس‌های بالا اهمیتی ندارد :
public class DocumentPrinter
{
  public void PrintDocument(string documentName)
  {
    var repository = new DocumentRepository();
    var formatter = new DocumentFormatter();         
    var printer = new Printer();              
    var document = repository                        
      .GetDocumentByName(documentName);               
    var formattedDocument = formatter.Format(document);    
    printer.Print(formattedDocument); 
  }
}
همانطور که مشاهده می‌کنید در بدنه‌ی کلاس DocumentPrinter ابتدا وابستگی‌ها نمونه سازی شده اند ، سپس یک سند بر اساس نام دریافت شده و سند پس از آماده شدن به فرمت چاپ به چاپگر ارسال شده است.  کلاس DocumentPrinter به تنهایی قادر به چاپ سند نیست و برای انجام این کار نیاز به نمونه سازی همه‌ی وابستگی‌ها دارد .
 استفاده از این API اینگونه خواهد بود :
var documentPrinter = new DocumentPrinter();
documentPrinter.PrintDocument(@"c:\doc.doc");
در حال حاضر کلاس DocumentPrinter از DI استفاده نمی‌کند این کلاس Loosely coupled نیست. به طور مثال لازم است که API سیستم به گونه ای تغییر پیدا کند که سند به جای فایل سیستم از دیتابیس بازیابی شود ، باید کلاس جدیدی به نام DatabaseDocumentRepository تعریف شود و به جای DocumentRepository اصلی در بدنه‌ی DocumentPrinter استفاده شود ، در نتیجه با تغییر با تغییر دادن یک قسمت از برنامه مجبور به تغییر در قسمت دیگر شده ایم.(tightly coupled است یعنی به دیگر قسمت‌ها چفت شده است.)
  DI به ما کمک می‌کند که این چفت شدگی (coupling) را از بین ببریم.
استفاده از constructor injection:
 اولین قدم برای از بین بردن این چفت شدگی Refactor کردن کلاس DocumentPrinter هست ، پس از این Refactoring وظیفه‌ی وهله سازی مستقیم اشیاء از این کلاس گرفته می‌شود و نیازمندی‌های این کلاس از طریق سازنده به این کلاس تزریق می‌شود و فیلد‌های کلاس نگهداری می‌شود . به کد زیر توجه کنید :
public class DocumentPrinter
{
  private DocumentRepository _repository;
  private DocumentFormatter _formatter;       
  private Printer _printer;              
  public DocumentPrinter(             
    DocumentRepository repository,               
    DocumentFormatter formatter,      
    Printer printer)                  
  {                                   
    _repository = repository;         
    _formatter = formatter;           
    _printer = printer;               
  }
  public void PrintDocument(string documentName)
  {
    var document = _repository.GetDocumentByName(documentName);
    var formattedDocument = _formatter.Format(document);
    _printer.Print(formattedDocument);
  }
}
 اکنون برای استفاده از این کلاس باید نیازمندی هایش را قبل از ارسال به سازنده نمونه سازی کرد :
var repository = new DocumentRepository();
var formatter = new DocumentFormatter();
var printer = new Printer();
var documentPrinter = new DocumentPrinter(repository, formatter, printer);
documentPrinter.PrintDocument(@"c:\doc.doc");
بله هنوز طراحی خوبی نیست اما این یک مثال ساده از DI می‌باشد. هنوز مشکلاتی در این طراحی هست ، به طور مثال کلاس DocumentPrinter به یک پیاده سازی مشخص از وابستگی هایش چفت شده است. (هنوز برای استفاده از  DatabaseDocumentRepository باید DocumentPrinter را تغییر داد) پس این طراحی هنوز انعطاف پذیر نیست و نمی‌توان به سادگی برای آن آزمون واحد نوشت.
برای حل این مشکلات از Interface‌ها کمک می‌گیریم. اگر به مثال قبلی بازگردیم نگرانی هر دو کلاس DocumentRepository و DatabaseDocumentRepository دریافت سند می‌باشد ، تنها پیاده سازی تفاوت دارد ، پس می‌توان یک Interface تعریف کرد
public interface IDocumentRepository
{
  Document GetDocumentByName(string documentName);
}
 حال ما 2 کلاس داریم که هر دو یک Interface را پیاده سازی کرده اند می‌توان این کار را برای بقیه‌ی وابستگی‌های کلاس DocumentPrinter نیز انجام داد ، حالا باید DocumentPrinter را به گونه ای Refactor کنیم که وابستگی‌ها را بر اساس Interface دریافت کند :
public class DocumentPrinter
{
  private IDocumentRepository _repository;                        
  private IDocumentFormatter _formatter;                          
  private IPrinter _printer;                                      
  public DocumentPrinter(
    IDocumentRepository repository,
    IDocumentFormatter formatter,
    IPrinter printer)
  {
    _repository = repository;
    _formatter = formatter;
    _printer = printer;
  }
  public void PrintDocument(string documentName)
  {
    var document = _repository.GetDocumentByName(documentName);
    var formattedDocument = _formatter.Format(document);
    _printer.Print(formattedDocument);
  }
}
حالا به سادگی می‌توان پیاده سازی‌های متفاوتی را از وابستگی‌های DocumentPrinter انجام داد و به آن تزریق کرد. همچنین اکنون نوشتن آزمون واحد هم ممکن شده است ، می‌توان یک پیاده سازی جعلی از هر کدام از Interface‌ها انجام داد و جهت اهداف Unit testing از آن استفاده کرد. به طور مثال می‌توان یک پیاده سازی جعلی از IPrinter انجام داد و بدون نیاز به ارسال صفحه به پرینتر عملکرد سیستم را تست کرد.
با وجودی که موفق شدیم چفت شدگی میان DocumentPrinter و وابستگی هایش را از بین ببریم اما اکنون استفاده از آن پیچیده شده است ، هربار که قصد نمونه سازی شیء را داریم باید به یاد آوریم کدام پیاده سازی از Interface مورد نیاز است ؟ این پروسه را می‌توان به کمک یک DI Container اتوماسیون کرد.
DI Container یک Factory هوشمند است ، مانند بقیه‌ی کلاس‌های Factory وظیفه‌ی نمونه سازی اشیاء را بر عهده دارد. هوشمندی آن در اینجا هست که می‌داند چطور وابستگی‌ها را نمونه سازی کند . DI Container‌های زیادی برای .NET وجود دارند یکی از محبوب‌ترین آنها StructureMap می‌باشد که قبلا در سایت درباره آن صحبت شده است .
برای مثال جاری پس از افزودن StructureMap به پروژه کافی است در ابتدای شروع برنامه به آن بگوییم برای هر Interface کدام شیء را وهله سازی کند : 
ObjectFactory.Configure(cfg =>
{
  cfg.For<IDocumentRepository>().Use<FilesystemDocumentRepository>();
  cfg.For<IDocumentFormatter>().Use<DocumentFormatter>();
  cfg.For<IPrinter>().Use<Printer>();
});
مطالب
خلاصه‌ای در مورد روش‌های دریافت فایل از سایت NuGet
بهبود سرعت دریافت بسته‌های نیوگت

در کشور بسیاری از اوقات دسترسی به پروتکل HTTPS به کندی صورت می‌گیرد. گاهی از اوقات نیز این دسترسی غیر ممکن می‌شود تا حد دریافت چند بایت در دقیقه. همین مساله تاکنون بر روی بسیاری از مسایل دیگر نیز تاثیر گذار بوده است؛ برای مثال اگر یک مخزن کد را مثلا در CodePlex یا GitHub داشته باشید، چون تمام Commitها از طریق همین پروتکل امن صورت می‌گیرد، کار کردن با آن‌ها بسیار مشکل خواهد شد. نمونه‌ی دیگر آن دسترسی به NuGet است. فید NuGet در VS.NET به Https تنظیم شده است. اگر دسترسی به Https برای شما به کندی صورت می‌گیرد فقط کافی است مسیر فید آن‌را در منوی Tools، گزینه‌ی Options، ذیل قسمت Package manager یافته و به http://nuget.org/api/v2 تغییر دهید؛ یعنی به Http خالی، بجای Https؛ تا سرعت دریافت بسته‌های NuGet مورد نظر افزایش یابند.


دریافت مستقیم بسته‌های نیوگت

برای دریافت بسته‌های نیوگت که دارای پسوند nupkg هستند، اما در اصل یک فایل zip بیشتر نیستند، الزامی به استفاده از ابزار و افزونه نیوگت در VS.NET نیست. می‌توان این بسته‌ها را به صورت مستقیم نیز دریافت کرد. برای مثال اگر آدرس بسته‌ای در سایت NuGet به صورت زیر است:
https://www.nuget.org/packages/PropertyChanged.Fody
برای دریافت مستقیم آن کافی است آدرس ذیل را درخواست کنید:
https://www.nuget.org/api/v2/package/PropertyChanged.Fody/1.42.0
یک api/v2 به این لینک اضافه می‌شود به همراه شماره نگارش مدنظر برای دریافت:
 https://www.nuget.org/api/v2/package/{packageID}/{packageVersion}
و یا برای مثال در سایت نیوگت عضو شوید و سپس به آن لاگین کنید. به این ترتیب با مراجعه به هر کتابخانه‌ای که در آنجا آپلود شده، یک لینک download در کنار صفحه، سمت چپ ظاهر می‌شود. با کلیک بر روی آن فایل nupkg آن کتابخانه قابل دریافت خواهد بود. این فایل در حقیقت یک فایل zip است. بنابراین کار کردن با محتویات آن ساده‌است.
به صورت خلاصه:
لینک اصلی کتابخانه: https://www.nuget.org/packages/Twitter.Bootstrap.RTL.Less/3.0.0
لینک دانلود آن: https://www.nuget.org/api/v2/package/Twitter.Bootstrap.RTL.Less/3.0.0

راه دیگر، ساخت دستی این آدرس است:
https://az320820.vo.msecnd.net/packages/propertychanged.fody.1.42.0.nupkg
که در حقیقت تشکیل شده است از:
 https://az320820.vo.msecnd.net/packages/{name}.{version}.nupkg
اگر نام آخرین بسته ارسالی PropertyChanged.Fody 1.42.0 باشد. فقط کافی است این دو قسمت را، یعنی نام و شماره نگارش را با یک نقطه به هم متصل کنید و سپس به انتهای آن، پسوند nupkg را اضافه نمائید. این فایل در آدرس https://az320820.vo.msecnd.net/packages/ به صورت مستقیم قابل دریافت است.


اهمیت تنظیمات IE

اگر پیام قطع شدن اتصال یا مشکلات DNS را در کنسول NuGet در VS.NET دریافت می‌کنید، ابتدا سعی کنید همان روش ذکر شده در ابتدای بحث را امتحان کنید. اگر کار نکرد احتمالا مشکل از تنظیمات IE است. برای مثال اگر بر روی تنظیمات اتصالی شما در IE یک پروکسی غیرقابل دسترسی در زمان جاری، تنظیم شده باشد، این مساله مستقیما بر روی اتصالات برنامه‌های دات نتی نیز تاثیر گذار است. بنابراین ابتدا لینک nupkg را که ساخته‌اید یکبار با IE امتحان کنید. اگر قابل دریافت نبود یعنی تنظیمات آن به هم ریخته است و این مساله بر روی بسیاری از برنامه‌های دیگر نیز تاثیر گذار است.
مطالب
مبانی TypeScript؛ تنظیمات TypeScript در ویژوال استودیو
تا اینجا «نحوه‌ی نصب و راه اندازی TypeScript را در VSCode» به همراه «تنظیمات کامپایلر TypeScript» و «دریافت فایل‌های d.ts. را توسط بسته‌های NodeJS» بررسی کردیم. در ادامه قصد داریم این تنظیمات را به نگارش کامل VS.NET نیز اعمال کنیم.


به روز رسانی وابستگی‌های VS.NET

برای دریافت آخرین نگارش TypeScript نیاز است افزونه‌های آن‌را از سایت رسمی زبان TypeScript دریافت و نصب کرد:


به علاوه نصب افزونه‌ی Web Essentials نیز جهت تکمیل امکانات کار با TypeScript مانند امکان مشاهده‌ی خروجی جاوا اسکریپت تولیدی، در حین کار با فایل TypeScript فعلی توصیه می‌شود. همچنین TSLint را نیز نصب می‌کند.


افزودن فایل تنظیمات tslint

افزونه‌ی Web Essentials که Web Analyzer نیز اکنون جزئی از آن است، به همراه TSLint هم هست که کار آن ارائه راهنماهایی جهت تولید کدهای با کیفیت TypeScript است. گزینه‌های آن‌را در منوی Tools -> Options می‌توانید مشاهده کنید:


برای بازنویسی تنظیمات آن (در صورت نیاز) فایل جدیدی را به نام tslint.json به ریشه‌ی پروژه (کنار فایل web.config) اضافه کنید. فایل پیش فرض آن چنین شکلی را دارد:
settings-defaults/tslint.json
و یک نمونه‌ی اصلاح شده‌ی آن به صورت ذیل است که می‌تواند به ریشه‌ی پروژه کپی شود:
tslint.json


تنظیمات کامپایلر TypeScript در VS.NET

هرچند قالب افزودن یک پروژه‌ی جدید TypeScript نیز به همراه نصب بسته‌های TypeScript به لیست پروژه‌های موجود اضافه می‌شود، اما عموما نیاز است تا فایل‌های ts. را به یک پروژه‌ی وب موجود اضافه کرد. بنابراین، یک پوشه‌ی جدید را به برای مثال به نام TypeScript ایجاد کرده و بر روی آن کلیک راست کنید. سپس گزینه‌ی Add->new item را انتخاب کرده و در اینجا TypeScript را جستجو کنید:


پس از اضافه شدن اولین فایل ts. به پروژه، دیالوگ زیر نیز ظاهر خواهد شد:


در اینجا جستجوی فایل‌های d.ts. را پیشنهاد می‌دهد. فعلا بر روی No کلیک کنید. این‌کار را در ادامه انجام خواهیم داد.
پس از افزودن اولین فایل ts. به پروژه، اگر به خواص پروژه‌ی جاری مراجعه کنید، برگه‌ی جدید تنظیمات کامپایلر TypeScript را مشاهده خواهید کرد:


با این تنظیمات در مطلب «تنظیمات کامپایلر TypeScript» پیشتر آشنا شده‌اید. برای مثال فرمت خروجی جاوا اسکریپت آن ES 5 باشد و یا در اینجا نوع‌های any که به صورت صریح any تعریف نشده‌اند، ممنوع شده‌است (تیک پیش فرض آن‌را بردارید). نوع ماژول‌های تولیدی نیز به commonjs تنظیم شده‌است.
همچنین در اینجا می‌توانید گزینه‌ی redirect JavaScript output to directory را هم مثلا به پوشه‌ی Scripts واقع در ریشه‌ی پروژه تنظیم کنید تا فایل‌های js. نهایی را در آن‌جا قرار دهد.

پس از این تنظیمات اولیه، به منوی tools->options مراجعه کرده و گزینه‌ی کامپایل فایل‌های ts. ایی را که به solution explorer اضافه نشده‌اند، نیز فعال کنید:


اعمال این تنظیمات نیاز به یکبار بستن و گشودن مجدد پروژه را دارد.


فعال سازی کامپایل خودکار فایل‌های ts. پس از ذخیره‌ی آن‌ها

پس از اعمال تغییرات فوق، اگر فایل ts. ایی را تغییر داده و ذخیره کردید و بلافاصله خروجی js. آن‌را مشاهده نکردید (این فایل‌ها در پوشه‌ی TypeScriptOutDir تنظیمات ذیل ذخیره می‌شوند و برای مشاهده‌ی آن‌ها باید گزینه‌ی show all files را در solution explorer فعال کنید)، فایل csproj پروژه‌ی جاری را در یک ادیتور متنی باز کرده و مداخل تنظیمات تنظیم شده‌ی در قسمت قبل را پیدا کنید. در اینجا نیاز است مدخل جدید TypeScriptCompileOnSaveEnabled را به صورت دستی اضافه کنید:
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
  <TypeScriptModuleKind>commonjs</TypeScriptModuleKind>
 <TypeScriptCompileOnSaveEnabled>True</TypeScriptCompileOnSaveEnabled>
  <TypeScriptOutDir>.\Scripts</TypeScriptOutDir>
  <TypeScriptNoImplicitAny>True</TypeScriptNoImplicitAny>  
  <TypeScriptTarget>ES5</TypeScriptTarget>  
  <TypeScriptRemoveComments>false</TypeScriptRemoveComments>
  <TypeScriptOutFile></TypeScriptOutFile>
  <TypeScriptGeneratesDeclarations>false</TypeScriptGeneratesDeclarations>
  <TypeScriptSourceMap>true</TypeScriptSourceMap>
  <TypeScriptMapRoot></TypeScriptMapRoot>
  <TypeScriptSourceRoot></TypeScriptSourceRoot>
  <TypeScriptNoEmitOnError>true</TypeScriptNoEmitOnError>  
</PropertyGroup>
پس از این تغییرات بدیهی است یکبار باید پروژه را بسته و مجددا بارگذاری نمائید.


رفع مشکل عدم کامپایل پروژه

زمانیکه افزونه‌های TypeScript را نصب کنید و تنظیمات فوق را اعمال نمائید، در دو حالت ذخیره‌ی یک فایل ts و یا کامپایل کل پروژه، فایل‌های js تولید خواهند شد. اما ممکن است نگارش نصب شده‌ی بر روی سیستم شما ناقص باشد و چنین خطایی را در حین کامپایل پروژه دریافت کنید:
 Your project file uses a different version of the TypeScript compiler and tools than is currently installed on this machine.  
No compiler was found at C:\Program Files (x86)\Microsoft SDKs\TypeScript\1.8\tsc.exe.
You may be able to fix this problem by changing the <TypeScriptToolsVersion> element in your project file.
اگر این خطا را دریافت کردید، سریع‌ترین راه رفع آن به صورت زیر است:
الف) ابتدا به تمام مسیرهای ذیل (در صورت وجود) مراجعه کرده و پوشه‌ی TypeScript را تغییر نام دهید (یا کلا آن‌را حذف کنید):
 C:\Program Files (x86)\Microsoft SDKs
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\
ب) سپس نصاب افزونه‌ی TypeScript را مجددا اجرا کنید. اینبار گزینه‌ی repair ظاهر می‌شود. با ترمیم صورت گرفته، مشکل فوق برطرف خواهد شد. این گزینه‌ی repair را در کنترل‌پنل و قسمت add/remove programs هم می‌توانید پیدا کنید (اگر فایل نصاب افزونه را حذف کرده‌اید).


اصلاح شماره نگارش کامپایلر TypeScript خط فرمان ویژوال استودیو

در فایل C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\VsDevCmd.bat که مربوط به خط فرمان VS.NET است، شماره نگارش TypeScript به 1.5 تنظیم شده‌است که نیاز به اصلاح دستی دارد؛ برای مثال تنظیم آن به نگارش 1.8 به صورت زیر است:
 @rem Add path to TypeScript Compiler
@if exist "%ProgramFiles%\Microsoft SDKs\TypeScript\1.8" set PATH=%ProgramFiles%\Microsoft SDKs\TypeScript\1.8;%PATH%
@if exist "%ProgramFiles(x86)%\Microsoft SDKs\TypeScript\1.8" set PATH=%ProgramFiles(x86)%\Microsoft SDKs\TypeScript\1.8;%PATH%
اگر از VS 2013 استفاده می‌کنید، چنین تنظیمی در فایل C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\VsDevCmd.bat آن نیز وجود دارد که به نگارش 1 تنظیم شده‌است و این مورد هم باید اصلاح شود (تنظیمات آن دقیقا مانند تنظیم فوق است).


تداخل ReSharper با شماره نگارش TypeScript نصب شده

برای نمونه اگر بخواهیم از decorators استفاده کنیم، یک چنین خطایی نمایش داده می‌شود:


هرچند در ابتدای بحث، آخرین نگارش TypeScript برای دریافت معرفی شده‌است، اما پس از نصب آن، ممکن است هنوز خطای استفاده از نگارش قدیمی 1.4 را مشاهده کنید. علت آن به نصب بودن ReSharper بر می‌گردد:
به منوی ReSharper و سپس گزینه‌ی Options آن مراجعه کنید.
 ReSharper -> Options -> Code Editing -> TypeScript -> Inspections -> Typescript language level

در اینجا می‌توان نگارش TypeScript مورد استفاده را تغییر داد. این شماره‌ها، نگارش‌هایی هستند که ReSharper از آن‌ها پشتیبانی می‌کند و نه شماره‌ای که نصب شده‌است.

و یا حتی می‌توان به صورت کامل فایل‌های ts را از کنترل ReSharper خارج کرد:
 Tools -> Options -> ReSharper Options -> Code Inspection -> Settings -> File Masks to Skip -> add *.ts
این مورد زمانی مفید خواهد بود که شماره نگارش فعلی TypeScript، از شماره نگارش پشتیبانی شده‌ی توسط ReSharper بالاتر باشد. در این حالت ممکن است syntaxهای جدید زبان TypeScript را ReSharper به صورت خطا اعلام کند که اشتباه است. بنابراین باید به ReSharper اعلام کرد که از این فایل‌ها صرفنظر کند. برای نمونه در زمان نگارش این مطلب، جهت کار با decorators، حتما نیاز است ReSharper را جهت حذف بررسی فایل‌های ts تنظیم کرد و گرنه ذیل کدهای مرتبط، خطوط قرمز نمایش خطا را مشاهده خواهید کرد که با توجه به کامپایلر جدید موجود، بی‌مورد است.


افزودن فایل tsconfig.json به پروژه

همانطور که در مطلب «تنظیمات کامپایلر TypeScript» نیز مطالعه کردید، روش دیگری نیز برای ذکر تنظیمات ویژه‌ی کامپایلر، خصوصا مواردی که در برگه‌ی خواص پروژه هنوز اضافه نشده‌اند، با استفاده از افزودن فایل ویژه‌ی tsconfig.json وجود دارد.
پشتیبانی کاملی از فایل‌های tsconfig.json در پروژه‌های VS 2015 با ASP.Core 1.0 وجود دارد و حتی گزینه‌ای در منوی add->new item برای آن درنظر گرفته شده‌است.
اگر گزینه‌ی فوق را در لیست موارد add->new item پیدا نمی‌کنید (تحت عنوان TypeScript JSON Configuration File)، مهم نیست. تنها کافی است فایل جدیدی را به نام tsconfig.json به ریشه‌ی پوشه‌ی فایل‌های ts خود اضافه کنید؛ با این محتوا:
 {
    "compilerOptions": {
         "target": "es5",
         "outDir": "../Scripts",
         "module": "commonjs",
         "sourceMap": true,
         //"watch": true, // JsErrorScriptException (0x30001)
         //"compileOnSave": true, // https://github.com/Microsoft/TypeScript/issues/7362#issuecomment-196586037
         "experimentalDecorators": true,
         "emitDecoratorMetadata": true
    }
}
حتی اگر از VS 2013 هم استفاده می‌کنید، این فایل توسط کامپایلر tsc شناسایی شده و استفاده می‌شود. برای آزمایش آن، گزینه‌ای غیرمتعارف را به گزینه‌های موجود اضافه کرده و سپس پروژه را کامپایل کنید. بلافاصله خطایی را در لیست خطاهای کامپایل پروژه دریافت خواهید کرد.
در اینجا نیازی به استفاده از گزینه‌ی watch نیست و ممکن است سبب بروز خطای JsErrorScriptException (0x30001) شود. قرار است این مشکل در نگارش‌های بعدی افزونه‌ی TypeScript مخصوص VS.NET برطرف شود.


افزودن فایل‌های d.ts. از طریق نیوگت

به ازای هر کتابخانه‌ی جاوا اسکریپتی معروف، یک بسته‌ی نیوگت تعاریف نوع‌های TypeScript آن هم وجود دارد.
یک مثال: فرض کنید می‌خواهیم فایل d.ts. کتابخانه‌ی jQuery را اضافه کنیم. برای این منظور jquery.typescript را در بین بسته‌های نیوگت موجود، جستجو کنید:


برای سایر کتابخانه‌ها نیز به همین صورت است. نام کتابخانه را به همراه typescript جستجو کنید.