مطالب
ارسال چند درخواست به صورت همزمان به ASP.NET Web API 2.x در AngularJS 1.x

 ما در AngularJs آبجکتی را به نام  q$ داریم که برای اجرای توابع به صورت async مفید است و همچنین در استفاده از مقادیر برگشتی از این درخواست‌ها برای پردازش‌های آینده به ما کمک میکند. برای اطلاعات بیشتر در مورد این سرویس به اینجا مراجعه کنید.

در ادامه ما از تابع ()all از q$ برای ترکیب چند شیء promise داخل یک شیء promise، به منظور صدا زدن چند سرویس به صورت یکجا، استفاده میکنیم.


پیاده سازی ASP.NET Web API


قدم اول : Visual Studio  را بازکنید و یک پروژه empty ASP.NET Web API را مطابق شکل زیر ایجاد کنید.


قدم دوم : در داخل پوشه models، کلاسی را با کدهای زیر ایجاد کنید:
using System.Collections.Generic;
 
namespace NG_Combine_Multiple_Promises.Models
{
    public class Courses
    {
        public int CourseId { get; set; }
        public string CourseName { get; set; }
    }
    public class CourseDatabase : List<Courses>
    {
        public CourseDatabase()
        {
            Add(new Courses() { CourseId=1,CourseName="الکترونیک"});
            Add(new Courses() { CourseId = 2, CourseName = "ریاضی 2" });
            Add(new Courses() { CourseId = 3, CourseName = "طراحی نرم افزار" });
        }
    }
 
    public class Student
    {
        public int StudentId { get; set; }
        public string Name { get; set; }
        public string AcadmicYear { get; set; }
    }
 
    public class StudentDatabase : List<Student>
    {
        public StudentDatabase()
        {
            Add(new Student() {StudentId=101,Name="محمد علوی", 
                               AcadmicYear="اول" });
            Add(new Student() { StudentId = 102, Name = "طاهره موسوی", 
                               AcadmicYear = "دوم" });
            Add(new Student() { StudentId = 103, Name = "علی عباسی", 
                               AcadmicYear = "سوم" });
            Add(new Student() { StudentId = 104, Name = "جواد نوری", 
                               AcadmicYear = "اول" });
            Add(new Student() { StudentId = 105, Name = "محسن خدایی", 
                               AcadmicYear = "دوم" });
            Add(new Student() { StudentId = 106, Name = "علی کاظمی", 
                               AcadmicYear = "سوم" });
            Add(new Student() { StudentId = 107, Name = "زهرا مقدم", 
                               AcadmicYear = "اول" });
            Add(new Student() { StudentId = 108, Name = "لاله فکور", 
                               AcadmicYear = "دوم" });
            Add(new Student() { StudentId = 109, Name = "علی نوروزی", 
                               AcadmicYear = "چهارم" });
        }
    }
     
}

کد بالا شامل موجودیت‌های Courses و Student است و کلاس‌های CourseDatabase و StudentDatabase به ترتیب برای ذخیره این موجودیت‌ها است.


قدم سوم :  بسته‌ی نیوگت Microsoft.AspNet.WebAPi.Cors را با استفاده از NuGet Package Manager، به منظور فعال سازی امکان صدا زدن این وب سرویس از دامنه‌های مختلف، به پروژه اضافه کرده و کد زیر را در کلاس WebApiCofig در پوشه App_Start قرار دهید.

config.EnableCors();


قدم چهارم : دو کنترل از نوع Web API 2 Empty را با نام‌های CourseAPIController و StudentAPIController ایجاد کرده و کدهای زیر را در آنها قرار دهید.

CourseAPIController.cs 

[EnableCors("*","*","*")]
public class CourseAPIController : ApiController
{
    [Route("Courses")]
    public IEnumerable<Courses> Get()
    {
        return new CourseDatabase();
    }
}

StudentAPIController.cs 

[EnableCors("*", "*", "*")]
public class StudentAPIController : ApiController
{
    [Route("Students")]
    public IEnumerable<Student> Get()
    {
        return new StudentDatabase();
    }
}


استفاده از Angular $q.all  

قدم اول : پروژه‌ی جدیدی را از نوع Empty ASP.NET در همین solution اضافه کرده و ارجاعات jQuery, Bootstrap و AngularJS را با استفاده از NuGet Package manager  مانند زیر اضافه کنید:

Install-Package jQuery
Install-Package bootstrap
Install-Package angularjs


قدم دوم : پوشه‌ایی را به نام MyScripts ایجاد کرده و درون آن فایل javascript  زیر را با نام logic.js اضافه کنید: 

var app = angular.module('mymodule', []);

//سرویسی برای بازگرداندن لیست دروس
app.service('courseService', function ($http) {
    this.get = function () {
        var response = $http.get("http://localhost:11696/Courses");
        return response;
    };
});

//سرویسی برای بازگرداندن لیست دانشجویان
app.service('studentService', function ($http) {
    this.get = function () {
        var response = $http.get("http://localhost:11696/Students");
        return response;
    };
});

//تعریف کنترلر
app.controller('ctrl', function ($scope, $q, courseService, studentService) {

    $scope.Courses = [];
    $scope.Students = [];
    loadData();

    /**/
    function loadData() {
        var promiseCourse = courseService.get();
        var promiseStudent = studentService.get();

        $scope.combineResult = $q.all([
            promiseCourse,
            promiseStudent
        ]).then(function (resp) {
            $scope.Courses = resp[0].data;
            $scope.Students = resp[1].data;
        });
    }
});
توضیحات: تابعq$.all لیستی از promise هایی را که  توسط courseService.get و studentService.get بدست آمده‌اند، گرفته و وقتی تمام promise‌ها تمام شدند، قسمت ()then آن اجرا میشود. 

قدم سوم:  فایل html ایی را با نام DataPage در پوشه‌ی view با کد زیر ایجاد کنید: 
<!DOCTYPE html>
<html ng-app="mymodule">
<head>
    <title></title>
    <meta charset="utf-8" />
    <link href="../Content/bootstrap.min.css" rel="stylesheet" />
    <script src="../Scripts/jquery-3.2.1.min.js"></script>
    <script src="../Scripts/angular.min.js"></script>
    <script src="../MyScripts/logic.js"></script>
</head>
<body ng-controller="ctrl">
       <div class="container">
        <h1 class="h1">دروس</h1>
        <table class="table table-striped table-bordered table-condensed">
            <thead>
                <tr>
                    <td class="text-center">کد درس</td>
                    <td class="text-center">نام درس</td>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="Course in Courses">
                    <td class="text-center">{{Course.CourseId}}</td>
                    <td class="text-center">{{Course.CourseName}}</td>
                </tr>
            </tbody>
        </table>
        <hr />
        <h1 class="h1">دانشجویان</h1>

        <table class="table table-striped table-bordered table-condensed">
            <thead>
                <tr>
                    <td class="text-center">کد دانشجویی</td>
                    <td class="text-center">نام و نام خانوادگی</td>
                    <td class="text-center">سال دانشجویی</td>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="Student in Students">
                    <td class="text-center">{{Student.StudentId}}</td>
                    <td class="text-center">{{Student.Name}}</td>
                    <td class="text-center">{{Student.AcadmicYear}}</td>
                </tr>
            </tbody>
        </table>
    </div>
</body>
</html>

خروجی نهایی پروژه به شکل زیر خواهد بود:

نظرات مطالب
کار با SignalR Core از طریق یک کلاینت Angular
مطلب «ارتقاء به ASP.NET Core 2.0 - معرفی بسته‌ی Microsoft.AspNetCore.All» را مطالعه کنید. خصوصا این دو قسمت را در نظرات تکمیلی آن:
- ارتقاء به ASP.NET Core 2.1 - معرفی بسته‌ی Microsoft.AspNetCore. App
- یک نکته‌ی مهم: روش صحیح به روز رسانی وابستگی‌های پروژه‌های NET Core. 
بازخوردهای دوره
استفاده از StructureMap به عنوان یک IoC Container
مشکل تداخل نگارش‌های مختلف را با هم دارید.
- ابتدا مطمئن شوید که بسته‌ها را فقط از طریق نیوگت اضافه کرده‌اید و نه ارجاع دستی (مهم).
- همچنین مطمئن شوید که بسته‌ی EF در پروژه‌ای که به آن اشاره کرده، نصب شده‌است.
- سپس یکبار تمام بسته‌ها را به روز کنید و در ادامه یکبار هم بر اساس نگارش فعلی دات نت انتخابی، آن‌ها را تنظیم مجدد کنید:
PM> update-package
PM> update-package -reinstall
نظرات مطالب
انجام کارهای زمانبندی شده در برنامه‌های ASP.NET توسط DNT Scheduler
یک نکته‌ی تکمیلی
- این پروژه در GitHub قرار گرفت. در اینجا
- بسته‌ی نیوگت آن‌را نیز به این صورت می‌توانید نصب کنید:
Install-Package DNTScheduler
چند مورد اصلاحیه در این بسته هست:
- تعریف صحیح الگوی singleton در آن
- همچنین می‌توانید public override Task RunAsync را نیز برای زمانیکه نیاز است از متدهای async استفاده کنید، تعریف کنید (از تعریف async void پرهیز کنید).
نظرات مطالب
EF Code First #1
نیوگت خیلی بهینه عمل می‌کند. بار اول که درخواست نصب بسته‌ای را می‌دهید، ابتدا یک کوئری ساده برای دریافت شماره آخرین نگارش موجود در مخزن سایت رسمی آن ارسال می‌کند. بعد این شماره نگارش را با کش محلی سیستم (فایل‌های قبلی دریافت شده آن) مقایسه می‌کند. اگر یکی بود، از کش محلی استفاده می‌شود (چیزی مجددا دریافت نخواهد شد)؛ در غیراینصورت بسته‌ی جدید را دریافت خواهد کرد.
مطالب
Roslyn #6
معرفی Analyzers

پیشنیاز این بحث نصب مواردی است که در مطلب «شروع به کار با Roslyn » در قسمت دوم عنوان شدند:
الف) نصب SDK ویژوال استودیوی 2015
ب) نصب قالب‌های ایجاد پروژه‌های مخصوص Roslyn

البته این قالب‌ها چیزی بیشتر از ایجاد یک پروژه‌ی کلاس Library جدید و افزودن ارجاعاتی به بسته‌ی نیوگت Microsoft.CodeAnalysis، نیستند. اما درکل زمان ایجاد و تنظیم این نوع پروژه‌ها را خیلی کاهش می‌دهند و همچنین یک پروژه‌ی تست را ایجاد کرده و تولید بسته‌ی نیوگت و فایل VSIX را نیز بسیار ساده می‌کنند.


هدف از تولید Analyzers

بسیاری از مجموعه‌ها و شرکت‌ها، یک سری قوانین و اصول خاصی را برای کدنویسی وضع می‌کنند تا به کدهایی با قابلیت خوانایی بهتر و نگهداری بیشتر برسند. با استفاده از Roslyn و آنالیز کننده‌های آن می‌توان این قوانین را پیاده سازی کرد و خطاها و اخطارهایی را به برنامه نویس‌ها جهت رفع اشکالات موجود، نمایش داده و گوشزد کرد. بنابراین هدف از آنالیز کننده‌های Roslyn، سهولت تولید ابزارهایی است که بتوانند برنامه نویس‌ها را ملزم به رعایت استانداردهای کدنویسی کنند.
همچنین معلم‌ها نیز می‌توانند از این امکانات جهت ارائه‌ی نکات ویژه‌‌ای به تازه‌کاران کمک بگیرند. برای مثال اگر این قسمت از کد اینگونه باشد، بهتر است؛ مثلا بهتر است فیلدهای سطح کلاس، خصوصی تعریف شوند و امکان دسترسی به آن‌ها صرفا از طریق متدهایی که قرار است با آن‌ها کار کنند صورت گیرد.
این آنالیز کنند‌ها به صورت پویا در حین تایپ کدها در ویژوال استودیو فعال می‌شوند و یا حتی به صورت خودکار در طی پروسه‌ی Build پروژه نیز می‌توانند ظاهر شده و خطاها و اخطارهایی را گزارش کنند.


بررسی مثال معتبری که می‌تواند بهتر باشد

در اینجا یک کلاس نمونه را مشاهده می‌کنید که در آن فیلدهای کلاس به صورت public تعریف شده‌اند.
    public class Student
    {
        public string FirstName;
        public string LastName;
        public int TotalPointsEarned;

        public void TakeExam(int pointsForExam)
        {
            TotalPointsEarned += pointsForExam;
        }

        public void ExtraCredit(int extraPoints)
        {
            TotalPointsEarned += extraPoints;
        }


        public int PointsEarned { get { return TotalPointsEarned; } }
    }
هرچند این کلاس از دید کامپایلر بدون مشکل است و کامپایل می‌شود، اما از لحاظ اصول کپسوله سازی اطلاعات دارای مشکل است و نباید جمع امتیازات کسب شده‌ی یک دانش آموز به صورت مستقیم و بدون مراجعه‌ی به متدهای معرفی شده، از طریق فیلدهای عمومی آن قابل تغییر باشد.
بنابراین در ادامه هدف ما این است که یک Roslyn Analyzer جدید را طراحی کنیم تا از طریق آن هشدارهایی را جهت تبدیل فیلدهای عمومی به خصوصی، به برنامه نویس نمایش دهیم.


با اجرای افزونه‌ی View->Other windows->Syntax visualizer، تصویر فوق نمایان خواهد شد. بنابراین در اینجا نیاز است FieldDeclaration‌ها را یافته و سپس tokenهای آن‌ها را بررسی کنیم و مشخص کنیم که آیا نوع یا Kind آن‌ها public است (PublicKeyword) یا خیر؟ اگر بلی، آن مورد را به صورت یک Diagnostic جدید گزارش می‌دهیم.


ایجاد اولین Roslyn Analyzer

پس از نصب پیشنیازهای بحث، به شاخه‌ی قالب‌های extensibility در ویژوال استودیو مراجعه کرده و یک پروژه‌ی جدید از نوع Analyzer with code fix را آغاز کنید.


قالب Stand-alone code analysis tool آن دقیقا همان برنامه‌های کنسول بحث شده‌ی در قسمت‌های قبل است که تنها ارجاعی را به بسته‌ی نیوگت Microsoft.CodeAnalysis به صورت خودکار دارد.
قالب پروژه‌ی Analyzer with code fix علاوه بر ایجاد پروژه‌های Test و VSIX جهت بسته بندی آنالایزر تولید شده، دارای دو فایل DiagnosticAnalyzer.cs و CodeFixProvider.cs پیش فرض نیز هست. این دو فایل قالب‌هایی را جهت شروع به کار تهیه‌ی آنالیز کننده‌های مبتنی بر Roslyn ارائه می‌دهند. کار DiagnosticAnalyzer آنالیز کد و ارائه‌ی خطاهایی جهت نمایش به ویژوال استودیو است و CodeFixProvider این امکان را مهیا می‌کند که این خطای جدید عنوان شده‌ی توسط آنالایزر، چگونه باید برطرف شود و راه‌کار بازنویسی Syntax tree آن‌را ارائه می‌دهد.
همین پروژه‌ی پیش فرض ایجاد شده نیز قابل اجرا است. اگر بر روی F5 کلیک کنید، یک کپی جدید و محصور شده‌ی ویژوال استودیو را باز می‌کند که در آن افزونه‌ی در حال تولید به صورت پیش فرض و محدود نصب شده‌است. اکنون اگر پروژه‌ی جدیدی را جهت آزمایش، در این وهله‌ی محصور شده‌ی ویژوال استودیو باز کنیم، قابلیت اجرای خودکار آنالایزر در حال توسعه را فراهم می‌کند. به این ترتیب کار تست و دیباگ آنالایزرها با سهولت بیشتری قابل انجام است.
این پروژه‌ی پیش فرض، کار تبدیل نام فضاهای نام را به upper case، به صورت خودکار انجام می‌دهد (که البته بی‌معنا است و صرفا جهت نمایش و ارائه‌ی قالب‌های شروع به کار مفید است).
نکته‌ی دیگر آن، تعریف تمام رشته‌های مورد نیاز آنالایزر در یک فایل resource به نام Resources.resx است که در جهت بومی سازی پیام‌های خطای آن می‌تواند بسیار مفید باشد.

در ادامه کدهای فایل DiagnosticAnalyzer.cs را به صورت ذیل تغییر دهید:
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
 
namespace CodingStandards
{
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public class CodingStandardsAnalyzer : DiagnosticAnalyzer
    {
        public const string DiagnosticId = "CodingStandards";

        // You can change these strings in the Resources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat.
        internal static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AnalyzerTitle), Resources.ResourceManager, typeof(Resources));
        internal static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
        internal static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AnalyzerDescription), Resources.ResourceManager, typeof(Resources));
        internal const string Category = "Naming";

        internal static DiagnosticDescriptor Rule = 
            new DiagnosticDescriptor(
                DiagnosticId, 
                Title, 
                MessageFormat, 
                Category, 
                DiagnosticSeverity.Error, 
                isEnabledByDefault: true, 
                description: Description);
 
        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
        {
            get { return ImmutableArray.Create(Rule); }
        }

        public override void Initialize(AnalysisContext context)
        {
            // TODO: Consider registering other actions that act on syntax instead of or in addition to symbols
            context.RegisterSyntaxNodeAction(analyzeFieldDeclaration, SyntaxKind.FieldDeclaration);
        }

        static void analyzeFieldDeclaration(SyntaxNodeAnalysisContext context)
        {
            var fieldDeclaration = context.Node as FieldDeclarationSyntax;
            if (fieldDeclaration == null) return;
            var accessToken = fieldDeclaration
                                .ChildTokens()
                                .SingleOrDefault(token => token.Kind() == SyntaxKind.PublicKeyword);

            // Note: Not finding protected or internal
            if (accessToken.Kind() != SyntaxKind.None)
            {
                // Find the name of the field:
                var name = fieldDeclaration.DescendantTokens()
                              .SingleOrDefault(token => token.IsKind(SyntaxKind.IdentifierToken)).Value;
                var diagnostic = Diagnostic.Create(Rule, fieldDeclaration.GetLocation(), name, accessToken.Value);
                context.ReportDiagnostic(diagnostic);
            }
        }
    }
}
توضیحات:

اولین کاری که در این کلاس انجام شده، خواندن سه رشته‌ی AnalyzerDescription (توضیحی در مورد آنالایزر)، AnalyzerMessageFormat (پیامی که به کاربر نمایش داده می‌شود) و AnalyzerTitle (عنوان پیام) از فایل Resources.resx است. این فایل را گشوده و محتوای آن‌را مطابق تنظیمات ذیل تغییر دهید:


سپس کار به متد Initialize می‌رسد. در اینجا برخلاف مثال‌های قسمت‌های قبل، context مورد نیاز، توسط پارامترهای override شده‌ی کلاس پایه DiagnosticAnalyzer فراهم می‌شوند. برای مثال در متد Initialize، این فرصت را خواهیم داشت تا به ویژوال استودیو اعلام کنیم، قصد آنالیز فیلدها یا FieldDeclaration را داریم. پارامتر اول متد RegisterSyntaxNodeAction یک delegate یا Action است. این Action کار فراهم آوردن context کاری را برعهده دارد که نحوه‌ی استفاده‌ی از آن‌را در متد analyzeFieldDeclaration می‌توانید ملاحظه کنید.
سپس در اینجا نوع نود در حال آنالیز (همان نودی که کاربر در ویژوال استودیو انتخاب کرده‌است یا در حال کار با آن است)، به نوع تعریف فیلد تبدیل می‌شود. سپس توکن‌های آن استخراج شده و بررسی می‌شود که آیا یکی از این توکن‌ها کلمه‌ی کلیدی public هست یا خیر؟ اگر این فیلد عمومی تعریف شده بود، نام آن‌را یافته و به عنوان یک Diagnostic جدید بازگشت و گزارش می‌دهیم.


ایجاد اولین Code fixer

در ادامه فایل CodeFixProvider.cs پیش فرض را گشوده و تغییرات ذیل را به آن اعمال کنید. در اینجا مهم‌ترین تغییر صورت گرفته نسبت به قالب پیش فرض، اضافه شدن متد makePrivateDeclarationAsync بجای متد MakeUppercaseAsync از پیش موجود آن است:
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
 
namespace CodingStandards
{
    [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CodingStandardsCodeFixProvider)), Shared]
    public class CodingStandardsCodeFixProvider : CodeFixProvider
    {
        public sealed override ImmutableArray<string> FixableDiagnosticIds
        {
            get { return ImmutableArray.Create(CodingStandardsAnalyzer.DiagnosticId); }
        }

        public sealed override FixAllProvider GetFixAllProvider()
        {
            return WellKnownFixAllProviders.BatchFixer;
        }

        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

            // TODO: Replace the following code with your own analysis, generating a CodeAction for each fix to suggest
            var diagnostic = context.Diagnostics.First();
            var diagnosticSpan = diagnostic.Location.SourceSpan;

            // Find the type declaration identified by the diagnostic.
            var declaration = root.FindToken(diagnosticSpan.Start)
                                   .Parent.AncestorsAndSelf().OfType<FieldDeclarationSyntax>()
                                   .First();

            // Register a code action that will invoke the fix.
            context.RegisterCodeFix(
                CodeAction.Create("Make Private", 
                c => makePrivateDeclarationAsync(context.Document, declaration, c)),
                diagnostic);
        }

        async Task<Document> makePrivateDeclarationAsync(Document document, FieldDeclarationSyntax declaration, CancellationToken c)
        {
            var accessToken = declaration.ChildTokens()
                .SingleOrDefault(token => token.Kind() == SyntaxKind.PublicKeyword);

            var privateAccessToken = SyntaxFactory.Token(SyntaxKind.PrivateKeyword);

            var root = await document.GetSyntaxRootAsync(c);
            var newRoot = root.ReplaceToken(accessToken, privateAccessToken);

            return document.WithSyntaxRoot(newRoot);
        }
    }
}
اولین کاری که در یک code fixer باید مشخص شود، تعیین FixableDiagnosticIds آن است. یعنی کدام آنالایزرهای از پیش تعیین شده‌ای قرار است توسط این code fixer مدیریت شوند که در اینجا همان Id آنالایزر قسمت قبل را مشخص کرده‌ایم. به این ترتیب ویژوال استودیو تشخیص می‌دهد که خطای گزارش شده‌ی توسط CodingStandardsAnalyzer قسمت قبل، توسط کدام code fixer موجود قابل رفع است.
کاری که در متد RegisterCodeFixesAsync انجام می‌شود، مشخص کردن اولین مکانی است که مشکلی در آن گزارش شده‌است. سپس به این مکان منوی Make Private با متد متناظر با آن معرفی می‌شود. در این متد، اولین توکن public، مشخص شده و سپس با یک توکن private جایگزین می‌شود. اکنون این syntax tree بازنویسی شده بازگشت داده می‌شود. با Syntax Factory در قسمت سوم آشنا شدیم.

خوب، تا اینجا یک analyzer و یک code fixer را تهیه کرده‌ایم. برای آزمایش آن دکمه‌ی F5 را فشار دهید تا وهله‌ای جدید از ویژوال استودیو که این آنالایزر جدید در آن نصب شده‌است، آغاز شود. البته باید دقت داشت که در اینجا باید پروژه‌ی CodingStandards.Vsix را به عنوان پروژه‌ی آغازین ویژوال استودیو معرفی کنید؛ چون پروژه‌ی class library آنالایزرها را نمی‌توان مستقیما اجرا کرد. همچنین یکبار کل solution را نیز build کنید.
پس از اینکه وهله‌ی جدید ویژوال استودیو شروع به کار کرد (بار اول اجرای آن کمی زمانبر است؛ زیرا باید تنظیمات وهله‌ی ویژه‌ی اجرای افزونه‌ها را از ابتدا اعمال کند)، همان پروژه‌ی Student ابتدای بحث را در آن باز کنید.


نتیجه‌ی اعمال این افزونه‌ی جدید را در تصویر فوق ملاحظه می‌کنید. زیر سطرهای دارای فیلد عمومی، خط قرمز کشیده شده‌است (به علت تعریف DiagnosticSeverity.Error). همچنین حالت فعلی و حالت برطرف شده را نیز با رنگ‌های قرمز و سبز می‌توان مشاهده کرد. کلیک بر روی گزینه‌ی make private، سبب اصلاح خودکار آن سطر می‌گردد.


روش دوم آزمایش یک Roslyn Analyzer

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


نود references را باز کرده و سپس بر روی گزینه‌ی analyzers کلیک راست نمائید. در اینجا گزینه‌ی Add analyzer را انتخاب کنید. در صفحه‌ی باز شده بر روی دکمه‌ی browse کلیک کنید. در اینجا می‌توان فایل اسمبلی موجود در پوشه‌ی CodingStandards\bin\Debug را به آن معرفی کرد.


بلافاصله پس از معرفی این اسمبلی، آنالایزر آن شناسایی شده و همچنین فعال می‌گردد.


در این حالت اگر برنامه را کامپایل کنیم، با خطاهای جدید فوق متوقف خواهیم شد و برنامه کامپایل نمی‌شود (به علت تعریف DiagnosticSeverity.Error).
نظرات مطالب
توسعه برنامه های Cross Platform با Xamarin Forms & Bit Framework - قسمت سوم

در صورتی که به علت کیفیت پایین اینترنت، هر بار بیلد کردن پروژه عملا به بن بست می‌رسد و حتی با چند دقیقه صبر کردن هم تمام نمی‌شود، می‌توانید از منوی Tools در ویژوال استدیو، به Options رفته و سپس از قسمت Nuget Package Manager، تیک گزینه Automatically check for missing packages during build in Visual Studio رو بردارید.