ارتقاء به ASP.NET Core 1.0 - قسمت 8 - فعال سازی ASP.NET MVC
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: پنج دقیقه

پیشنیازهای بحث (از قسمت 8 به بعد این سری)
اگر پیشتر سابقه‌ی کار کردن با ASP.NET MVC را ندارید، نیاز است «15 مورد» ابتدایی مطالب ASP.NET MVC سایت را پیش از ادامه‌ی این سری مطالعه کنید؛ از این جهت که این سری از مطالب «ارتقاء» نام دارند و نه «بازنویسی مجدد». دراینجا بیشتر تفاوت‌ها و روش‌های تبدیل کدهای قدیمی، به جدید را بررسی خواهیم کرد؛ تا اینکه بخواهیم تمام مطالبی را که وجود دارند از صفر بازنویسی کنیم.


فعال سازی ASP.NET MVC

تا اینجا خروجی برنامه را صرفا توسط میان افزار app.Run نمایش دادیم. اما در نهایت می‌خواهیم یک برنامه‌ی ASP.NET MVC را برفراز ASP.NET Core 1.0 اجرا کنیم و این قابلیت نیز به صورت پیش فرض غیرفعال است. برای فعال سازی آن نیاز است ابتدا بسته‌ی نیوگت آن‌را نصب کرد. سپس سرویس‌های مرتبط با آن‌را ثبت و معرفی نمود و در آخر میان افزار خاص آن‌را فعال کرد.


نصب وابستگی‌های ASP.NET MVC

برای این منظور بر روی گره references کلیک راست کرده و گزینه‌ی manage nuget packages را انتخاب کنید. سپس در برگه‌ی browse آن Microsoft.AspNetCore.Mvc را جستجو کرده و نصب نمائید:


انجام این مراحل معادل هستند با افزودن یک سطر ذیل به فایل project.json برنامه:
 {
    "dependencies": {
      //same as before  
      "Microsoft.AspNetCore.Mvc": "1.0.0"
 },


تنظیم سرویس‌ها و میان افزارهای ASP.NET MVC

پس از نصب بسته‌ی نیوگت ASP.NET MVC، دو تنظیم ذیل در فایل آغازین برنامه، برای شروع به کار با ASP.NET MVC کفایت می‌کنند:
الف) ثبت یکجای سرویس‌های ASP.NET MVC
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

ب) معرفی میان افزار ASP.NET MVC
public void Configure(IApplicationBuilder app)
{
   app.UseFileServer();
   app.UseMvcWithDefaultRoute();
در مورد متد UseFileServer در مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 4 - فعال سازی پردازش فایل‌های استاتیک» بیشتر بحث شد.
در اینجا دو متد UseMvc و UseMvcWithDefaultRoute را داریم. اولی، امکان تعریف مسیریابی‌های سفارشی را میسر می‌کند و دومی به همراه یک مسیریابی پیش فرض است.


افزودن اولین کنترلر برنامه و معرفی POCO Controllers


در ویژوال استودیو بر روی نام پروژه کلیک راست کرده و پوشه‌ی جدیدی را به نام کنترلر اضافه کنید (تصویر فوق). سپس به این پوشه کلاس جدید HomeController را با این محتوا اضافه کنید:
namespace Core1RtmEmptyTest.Controllers
{
    public class HomeController
    {
        public string Index()
        {
            return "Running a POCO controller!";
        }
    }
}
در ادامه برای اینکه فایل index.html موجود در پوشه‌ی wwwroot بجای محتوای اکشن متد Index ما نمایش داده نشود (با توجه به تقدم و تاخر میان افزارهای ثبت شده‌ی در کلاس آغازین برنامه)، این فایل را حذف کره و یا تغییر نام دهید.
سپس برنامه را اجرا کنید. این خروجی باید قابل مشاهده باشد:


اگر با نگارش‌های قبلی ASP.NET MVC کار کرده باشید، تفاوت این کنترلر با آن‌ها، در عدم ارث بری آن از کلاس پایه‌ی Controller است. به همین جهت به آن POCO Controller نیز می‌گویند (plain old C#/CLR object).
در ASP.NET Core، همینقدر که یک کلاس public غیر abstract را که نامش به Controller ختم شود، داشته باشید و این کلاس در اسمبلی باشد که ارجاعی را به وابستگی‌های ASP.NET MVC داشته باشد، به عنوان یک کنترلر معتبر شناخته شده و مورد استفاده قرار خواهد گرفت. در نگارش‌های قبلی، شرط ارث بری از کلاس پایه Controller نیز الزامی بود؛ اما در اینجا خیر. هدف از آن نیز کاهش سربارهای وهله سازی یک کنترلر است. اگر صرفا می‌خواهید یک شیء را به صورت JSON بازگشت دهید، شاید وهله سازی یک کلاس ساده، بسیار بسیار سریعتر از نمونه سازی یک کلاس مشتق شده‌ی از Controller، به همراه تمام وابستگی‌های آن باشد.

 البته هنوز هم مانند قبل، کنترلرهای مشتق شده‌ی از کلاس پایه‌ی Controller قابل تعریف هستند:
using Microsoft.AspNetCore.Mvc;
 
namespace Core1RtmEmptyTest.Controllers
{
    public class AboutController : Controller
    {
        public IActionResult Index()
        {
            return Content("Hello from DNT!");
        }
    }
}
با این خروجی:


تفاوت دیگری را که ملاحظه می‌کنید، خروجی IActionResult بجای ActionResult نگارش‌های قبلی است. در اینجا هنوز هم ActionResult را می‌توان بکار برد و اینبار ActionResult، پیاده سازی پیش فرض اینترفیس IActionResult است.
و اگر بخواهیم در POCO Controllers شبیه به return Content فوق را پیاده سازی کنیم، نیاز است تا تمام جزئیات را از ابتدا پیاده سازی کنیم (چون کلاس پایه و ساده ساز Controller در اختیار ما نیست):
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
 
namespace Core1RtmEmptyTest.Controllers
{
    public class HomeController
    {
        [ActionContext]
        public ActionContext ActionContext { get; set; }
 
        public HttpContext HttpContext => ActionContext.HttpContext;
 
        public string Index()
        {
            return "Running a POCO controller!";
        }
 
        public IActionResult About()
        {
            return new ContentResult
            {
                Content = "Hello from DNT!",
                ContentType = "text/plain; charset=utf-8"
            };
        }
    }
}
همانطور که ملاحظه می‌کنید اینبار بجای return Content ساده، باید وهله سازی شیء ContentResult از ابتدا صورت گیرد؛ به همراه تمام جزئیات آن.
به علاوه در اینجا نحوه‌ی دسترسی به HttpContext را هم مشاهده می‌کنید. ویژگی ActionContext سبب تزریق اطلاعات آن به کنترلر جاری شده و سپس از طریق آن می‌توان به HttpContext و تمام قابلیت‌های آن دسترسی یافت.
اینجا است که می‌توان میزان سبکی و سریعتر بودن POCO Controllers را احساس کرد. شاید در کنترلری نیاز به این وابستگی‌ها نداشته باشید. اما زمانیکه کنترلری از کلاس پایه‌ی Controller مشتق می‌شود، تمام این وابستگی‌ها را به صورت پیش فرض و حتی در صورت عدم استفاده، در اختیار خواهد داشت و این در اختیار داشتن یعنی وهله سازی شدن تمام وابستگی‌های مرتبط با شیء پایه‌ی Controller. به همین جهت است که POCO Controllers بسیار سبک‌تر و سریع‌تر از کنترلرهای متداول مشتق شده‌ی از کلاس پایه‌ی Controller عمل می‌کنند.
  • #
    ‫۸ سال و ۲ ماه قبل، سه‌شنبه ۲۹ تیر ۱۳۹۵، ساعت ۲۰:۰۶
    با سلام. بعد از فعال کردن mvc ، خطای زیر همواره دریافت می‌شود:
     Error while building type Microsoft.AspNetCore.Routing.DefaultInlineConstraintResolver
    با این پیغام برای inner exception:
     An item with the same key has already been added 
    محتوای startup هم به این صورت است:
    startup.txt
    • #
      ‫۸ سال و ۲ ماه قبل، سه‌شنبه ۲۹ تیر ۱۳۹۵، ساعت ۲۲:۰۷
      این باگ را در اینجا گزارش کنید (به نظر structuremap.dnx هنوز برای نگارش RTM آماده نیست).

      به روز رسانی
      این مساله در اینجا گزارش شده و عنوان کرده‌اند که یک populate اضافی دارد:
      private IServiceProvider IocConfig(IServiceCollection services)
              {
                  var container = new Container();
                  container.Configure(config =>
                  {
                      //config.Populate(services); ---> این اضافی است
                  });
      
                  container.Populate(services);
                  return container.GetInstance<IServiceProvider>();
              }
  • #
    ‫۷ سال و ۶ ماه قبل، یکشنبه ۶ فروردین ۱۳۹۶، ساعت ۱۷:۰۳
    در ویژوال 2017 ( نسخه نهایی یا نسخه RC) وقتی پروژه به صورت empty ایجاد می‌شه ممکنه با ایجاد یک کنترلر جدید و استفاده از Code Generator به مشکل no executable found matching command "dotnet-aspnet-codegenerator"  بربخورید .
    برای حل این مورد می‌بایست قطعه کد زیر رو به فایل yourpaojectname.csproj اضافه کنید :

    <ItemGroup>
        <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0-msbuild3-final" />
        <DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="1.0.0-msbuild3-final" />
        <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0-msbuild3-final" />
      </ItemGroup>
  • #
    ‫۷ سال و ۶ ماه قبل، دوشنبه ۷ فروردین ۱۳۹۶، ساعت ۰۰:۰۰
    به روز رسانی
    با حذف فایل project.json در VS 2017، اکنون با کلیک راست بر روی گروه نام پروژه (فایل csproj)، گزینه‌ی Edit آن ظاهر شده و مداخل ذکر شده‌ی در مطلب فوق، چنین تعاریفی را پیدا می‌کنند:  
    <Project Sdk="Microsoft.NET.Sdk.Web">
      <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
        <PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="1.1.2" />
      </ItemGroup>
    </Project>
  • #
    ‫۶ سال و ۶ ماه قبل، شنبه ۱۲ اسفند ۱۳۹۶، ساعت ۱۳:۱۸
    ارتقاء به ASP.NET Core 2.1 - معرفی درجه‌ی سازگاری فریم ورک

    پس از نصب یک SDK جدید، بهترین روش یافتن تغییرات انجام شده، ایجاد یک پوشه‌ی خالی جدید، باز کردن خط فرمان در این پوشه و سپس صدور دستور dotnet new mvc است. به این ترتیب بدون داشتن هیچ نوع IDE خاصی می‌توانید یک پروژه‌ی جدید مبتنی بر آن SDK را ایجاد کنید.
    در قالب پیش‌فرض نگارش 2.1، سطر فعالسازی Mvc به صورت زیر تغییر کرده‌است:
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }
    در اینجا CompatibilityVersion یک چنین تعریفی را دارد:
    public enum CompatibilityVersion
    {
       Version_2_0 = 0,
       Version_2_1 = 1,
       Latest = int.MaxValue
    }
    برای مثال تنظیم آن به Version_2_0‌، صرفنظر از نگارش جاری Mvc مورد استفاده، رفتار نگارش 2.0 را برای برنامه تنظیم می‌کند که البته هدف اصلی آن‌ها در حقیقت چنین چیزی است:
    services.AddMvc()
       .SetCompatibilityVersion(CompatibilityVersion.Version_2_1) // Give me all of the 2.1 behaviors
       .AddMvcOptions(options =>
       {
          options.AllowCombiningAuthorizeFilters = false; // don't combine authorize filters (keep 2.0 behavior)
          options.AllowEmptyInputInBodyModelBinding = false; // shouldn't treat empty input as valid.
       });
    و فلسفه‌ی آن نیز به این صورت است: چگونه یک فریم‌ورک را بهبود ببخشیم، بدون اینکه ارتقاء به نگارش‌های جدید را سخت‌تر کنیم؟
    برای مثال در نگارش 2.1، اگر بدنه‌ی درخواست رسیده خالی باشد، خطایی را به ModelState اضافه می‌کند که پیشتر اینگونه نبوده‌است و یا ترکیب سیاست‌های امنیتی پیش از نگارش 2.1، آنطور که تصور میشده، کار نمی‌کرده‌است و این باگ اکنون اصلاح شده‌است. اگر پس از به روز رسانی به نگارش 2.1، این دو تغییر، برنامه‌ی شما را به هم می‌ریزند، یا می‌توانید CompatibilityVersion را به Version_2_0 تعیین کنید (لغو کلی تغییرات رفتاری نگارش 2.1) و یا Version_2_1 را انتخاب کنید و توسط متد AddMvcOptions، گزینه‌های مختلف این تغییرات انجام شده را به دلخواه انتخاب کنید.

    نکته‌ی مهم: این رفتارها تا ابد نگهداری نخواهند شد. یعنی با ارائه‌ی نگارش 3.0 و انتخاب آن، دیگر دسترسی به رفتارهای قدیمی قابل انتخاب برای نگارش 2.1 نخواهید داشت. به همین جهت در این بین، فرصت بررسی، انطباق و به روز رسانی برنامه‌ی خود را خواهید داشت.
  • #
    ‫۵ سال و ۴ ماه قبل، یکشنبه ۸ اردیبهشت ۱۳۹۸، ساعت ۱۴:۲۹
    در ASP.NET Core 3.0، بنابر درخواست استفاده کنندگان که به نظر آن‌ها AddMvc تعداد زیادی از سرویس‌ها را به سیستم اضافه می‌کند که شاید مورد استفاده قرار نگیرند (برای مثال کسانیکه فقط با Web API کار می‌کنند، نیازی به سرویس‌های Viewها ندارند)، متدهای اختصاصی‌تری طراحی شده‌اند. البته AddMvc حذف نخواهد شد و همانند قبل رفتار می‌کند.
    هدف
    سرویس‌های اضافه شده
    متد تنظیم سرویس‌ها
    - مناسب برای توسعه‌ی Web API
    - اما باید بخاطر داشت که این سرویس‌ها را به صورت پیش‌فرض اضافه نمی‌کند:
    • Antiforgery
    • Temp Data
    • Views
    • Pages
    • Tag Helpers
    • Memory Cache 
    • Controllers
    • Model Binding
    • API Explorer (OpenAPI integration)
    • Authorization [Authorize]
    • CORS [EnableCors]
    • Data Annotations validation [Required]
    • Formatter Mappings (translate a file-extension to a content-type) 
     ()AddControllers 
    شبیه به ASP.NET Core 1.X عمل می‌کند؛ یعنی سرویس Pages را که مرتبط با Razor Pages است، به صورت پیش‌فرض ثبت نمی‌کند.
    • Controllers
    • Model Binding
    • API Explorer (OpenAPI integration)
    • Authorization [Authorize]
    • CORS [EnableCors]
    • Data Annotations validation [Required]
    • Formatter Mappings (translate a file-extension to a content-type)
    • Antiforgery
    • Temp Data
    • Views
    • Tag Helpers
    • Memory Cache 
     ()AddControllersWithViews
     برای کار با Razor pages بوده و این سرویس‌ها را به صورت پیش‌فرض به همراه ندارد:
    • API Explorer (OpenAPI integration)
    • CORS [EnableCors]
    • Formatter Mappings (translate a file-extension to a content-type) 
    • Pages
    • Controllers
    • Model Binding
    • Authorization [Authorize]
    • Data Annotations validation [Required]
    • Antiforgery
    • Temp Data
    • Views
    • Tag Helpers
    • Memory Cache 
     ()AddRazorPages
    • #
      ‫۴ سال و ۵ ماه قبل، یکشنبه ۲۵ اسفند ۱۳۹۸، ساعت ۱۶:۳۳
      دستورات ایجاد یک پروژه تحت Core و اعمال خودکار تنظیمات فایل آغازین
      برای ایجاد یک پروژه وب (خالی)
      dotnet new web
      برای ایجاد یک پروژه WebApi
      dotnet new webapi
      برای ایجاد پروژه‌های mvc
      dotnet new mvc
      و برای RazorPage
      dotnet new webapp

  • #
    ‫۴ سال و ۸ ماه قبل، یکشنبه ۲۲ دی ۱۳۹۸، ساعت ۱۴:۳۸
    در نسخه ۳.۱ تست کردم. ارث بری از کلاس Controller رو حذف کردم پروژه بیلد نشد.
    • #
      ‫۴ سال و ۸ ماه قبل، یکشنبه ۲۲ دی ۱۳۹۸، ساعت ۲۲:۵۸
      - با نگارش 3.1 مشکلی مشاهده نشد (هیچ تغییری نداشته): net-core-31-final-poco-controller.zip
      - حذف کردن ارث‌بری از کلاس پایه کنترلر، نیاز به یکسری تغییرات را هم در کدهای شما خواهد داشت که تعدادی از نکات آن، در انتهای بحث عنوان شد‌ه‌اند؛ مانند  تزریق ActionContext و بازگشت new ContentResult بجای return Content، چون این return Content از کلاس پایه کنترلر تامین می‌شود. اگر آن‌را حذف کردید، باید جستجو کنید که return Content، ساده کننده‌ی چه چیزی در پشت صحنه هست و امثال این. این نوع نکات هم با مفاهیم ASP.NET MVC 5x یکی است: « ASP.NET MVC #6»