آموزش ASP.NET Core MVC سطح مقدماتی

model view controller

MVC مخفف Model View Controller است، MVC یک نوع از انواع معماری های برنامه نویسی برای طراحی نرم افزار می باشد. این معماری از سه بخش اصلی تشکیل شده است:

  1. Model
  2. View
  3. Controller

که در ادامه به معرفی تک تک این لایه ها می پردازیم.

اگر یک برنامه تحت وب که با این معماری نوشته شده است را در نظر بگیریم، شیوه کار به این صورت است:

mvc architecture
  1. کاربر آدرس URL برنامه را در مرورگر وارد می کند. در این زمان یک درخواست http به برنامه مورد نظر ارسال می شود.
  2. Routing برنامه، درخواست کاربر را به متد مورد نظر در Controller برنامه ارسال می کند.
  3. Controller درخواست را با توجه به پارامتر های دریافت شده از کاربر بررسی می نماید. سپس برای دریافت اطلاعات مورد نیاز کاربر درخواست دریافت اطلاعات را توسط یک Query از Database دریافت می کند و آن را به شکل و شمایل مورد نیاز که در Model برنامه وجود دارد تبدیل می کند.
  4. پس از آن اطلاعات از نوع مدل مورد نیاز توسط کنترلر به View ارسال می شود.
  5. View بعد از دریافت اطلاعات، آنها را در بین کد های HTML رندر می کند و سپس در مرورگر کاربر به نمایش در می آید.

معرفی اجزاء MVC

Model

شامل کلاس هایی می شود که قرار است شی هایشان در برنامه استفاده شود و همچنین کلاس هایی که به ذخیره یا واکشی اطلاعات (مدیریت اطلاعات) از دیتابیس می پردازند.

model example

View

با استفاده از اطلاعات دریافتی، به نمایش اطلاعات در بین کدهای HTML می پردازد و آن را آماده ی نمایش در مرورگر می کند.

view example

Controller

لاجیک و منطق اصلی برنامه بر عهده ی controller می باشد.

در کد بالا دو اکشن وجود دارند، به عنوان مثال اگر کاربر به آدرس https://localhost/student برود، اکشن Index اجرا می شود. اگر بخواهد به آدرس https://localhost/student/detail/2 برود، اکشن detail با آرگومان ورودی 2 اجرا خواهد شد.

راه اندازی MVC در NET Core.

برای راه اندازی آن کافی ست چند قدم برداشته شود:

  • اگر از ورژن های قدیمی .net core استفاده می کنید باید کد ()AddMvc را به متد ConfigureService در Startup اضافه کنید:

در غیر این صورت کد زیر در متد ConfigureService فایل Startup.cs وجود خواهد داشت

  • در صورتی که موقع ایجاد پروژه NET Core حالت Empty یا Blank را انتخاب کرده باشید باید تنظیمات مربوط به EndPoint را انجام دهید در غیر این صورت کد های این تنظیمات از قبل نوشته شده اند. تنظیمات EndPoint تعیین می کنند که با توجه به URL درخواست شده، چه کنترلر و اکشنی اجرا شود.

پیاده سازی Model

با یک مثال کاربردی پیاده سازی مدل را شرح می دهیم. فرض کنید که میخواهیم اطلاعات دانش آموزان را در پایگاه داده ذخیره و یا واکشی نماییم. بدین منظور در پوشه ی Model یک پوشه به نام Controller می سازیم و دو Class و یک Interface ایجاد می کنیم:

model folder

کلاس StudentModel را به شکل زیر می نویسیم:

اینترفیس IstudentRepository را به شکل زیر می نویسیم و قرار است تنها یک کار را انجام دهد. یعنی در ازای یک شناسه، مشخصات دانش آموز متناظر را تحویل دهد.

کلاس MockStudentRepository که اینترفیس را پیاده سازی می کند به شکل زیر خواهد بود.

البته کلاس بالا به صورت استاتیک اطلاعات مربوط به دانش آموزان را ایجاد و ذخیره کرده است. بعدا چگونگی کار با دیتابیس و استفاده از  EntityFramework Coreشرح داده خواهد شد.

استفاده از Model در Controller

استفاده از Model در Controller به شیوه ی Constructor injection به شکل زیر خواهد بود:

اگر بخواهیم در این مرحله برنامه را اجرا کنیم به ارور بر میخوریم:

error controller view

این خطا به دلیل اینکه تعیین نکردیم که از کدام پیاده سازی از اینترفیس IStudentRepository استفاده کند رخ داده است. برای حل این مشکل به سراغ کلاس Startup می رویم و در متد ConfigureServices کد زیر را اضافه می کنیم:

کد بالا تعیین می کند که در هرجایی از برنامه، هنگام استفاده از اینترفیس IStudentRepository ، کلاس MockStudentRepository که این اینترفیس را پیاده سازی کرده است استفاده شود. دو سوال پیش می آید، اول اینکه چطور این کار انجام می شود؟ دوم آنکه AddSingleton چیست؟

در پاسخ به این سوال باید گفت که در .NET Core از مفهومی به نام IoC Container استفاده می شود.

IoC Container

مخفف Inversion of Control Container است و فریمورکی برای انجام Dependency Injection است. در این فریمورک امکان تنظیم اولیه وابستگی‌های سیستم وجود دارد. برای مثال زمانیکه برنامه از یک IoC Container، نوع اینترفیس خاصی را درخواست می‌کند، این فریم ورک با توجه به تنظیمات اولیه‌اش، کلاسی مشخص را بازگشت خواهد داد. قبل از ظهور .NET Core برنامه نویسان مجبور بودند آن را در قالب افزونه به پروژه اضافه کنند اما در .NET Core نیازی به انجام این کار نیست چون IoC Container را در دل خود دارد.

IoC Container سه دوره ی حیات دارد که عبارت اند از:

  1. AddSingleton
  2. AddScoped
  3. AddTransient

AddSingleton

با استفاده از AddSingleton، تنها یک نمونه از کلاس وجود خواهد داشت. این نمونه در اولین درخواست سرویس ساخته می شود و در تمام HTTP Request ها و در تمام طول عمر نرم افزار استفاده می شود.

AddScoped

با استفاده از AddScoped تنها یک نمونه از کلاس در یک HTTP Request وجود خواهد داشت. اما به ازای هر HTTP Request ، یک نمونه جدید از کلاس ساخته می شود. فرقی نمیکند که در یک HTTP Request یکبار یا چند بار از آن کلاس استفاده شود. با AddScoped  یک نمونه از کلاس در تمام قسمت های یک HTTP Request وجود خواهد داشت. این نوع از دوره حیات برای شی های Entity Framework DbContext مناسب است (الگوی Unit of Work)

AddTransient

 با استفاده از AddTransient به ازای هر بار استفاده از کلاس، یک نمونه جدید از آن ساخته می شود. فرقی نمیکند که در یک HTTP Request بخواهیم از آن استفاده کنیم یا نه. به زبان ساده تر، هر بار که استفاده از یک سرویس درخواست شود یک نمونه ساخته می شود و برای سرویس ها  lightweight, stateless  (بی وضعیت و سبک) مناسب است.

می توان به عنوان مثال، در داخل کنترلر Home در اکشن Index هم از تزریق، از طریق سازنده کلاس و هم تزریق، از طریق پارامتر استفاده کرد. نیازی نیست که به صورت دستی یک نمونه از آنها ساخته شود و آنها خیلی  ساده در کنترلر موجود هستند.

وقتی بخواهیم از Scoped  در middleware استفاده کنیم ، باید سرویس را به متد Invoke یا InvokeAsync تزریق کنیم و نباید از طریق constructor injection  ( تزریق در سازنده) این کار را انجام دهیم چون سرویس را مجبور به رفتاری مانند Singleton  میکند.

پیاده سازی Controller

با یک مثال کاربردی controller توضیح داده خواهد شد. همانطور که قبلا بیان شد لاجیک و منطق اصلی برنامه بر عهده ی  Controller است و تمام درخواست های HTTP را مدیریت می کند. قرار است در این مثال تمام اطلاعات student را واکشی شود و در قسمت View ( که بعدا توضیح داده خواهد شد) آن را نشان دهیم. به Controller ای که قبلا داشتیم اکشن زیر را اضافه می کنیم:

اگر الان برنامه را اجرا کنیم به خطا بر می خوریم چون هیچ View ای با نام Details وجود ندارد.

view error

دقت کنید که return View به طور پیش فرض به دنبال view ای همنام با متد خود می گردد. اگر بخواهیم سفارشی سازی کنیم باید تغییراتی در کد اعمال کنیم که بعدا توضیح داده خواهد شد.

پیاده سازی View

برای حل مشکلی که پیش آمد در پوشه ی Views ما یک پوشه به نام controller مد نظرمان ایجاد می کنیم و در داخل آن فایل Razor همنام با View مورد نظرمان ایجاد می کنیم. ( منظور آن view ای ست که در کنترلر  به آن ارجاع داشتیم)

view folders

در Details.cshtml کدهایی که از قبل وجود داشت را پاک می کنیم. با نوشتن کلمه ی html و فشردن tab ، به نمونه کد html دست پیدا می کنیم، بعد از آن باید کد های razor را بنویسیم( منظور کد های سی شارپ داخل html هستند)

راه های انتقال داده ها از Controller به View

چندین راه برای انتقال داده ها از Controller به View وجود دارند که عبارت اند از:

  1. ViewData
  2. ViewBag
  3. Strongly Typed View

ViewData

در این روش باید کلید هایی را ایجاد کنیم که در razor بتوانیم به آن دسترسی داشته باشیم. در کد زیر کد های کنترلر تغییر پیدا کرده اند و کلید هایی به آن اضافه شده اند:

بعد از آن در view  می نویسیم:

viewdata example

با اجرای برنامه، خروجی به شکل زیر خواهد بود:

student details example

ViewData روش مورد اطمینانی نیست چون:

  • چون ضعیف و Weakly typed object است.
  • از کلید های string به برای ذخیره و یا دریافت اطلاعات استفاده می کند.
  • به صورت اتوماتیک در هنگام runtime پردازش می شود به همین دلیل اگر کلید یک ViewData را اشتباه بنویسیم، هیچ خطای سینتکسی بروز پیدا نمی کند و فقط در هنگام runtime خطا ایجاد می شود.

ViewBag

ViewBag هم مانند ViewData است با این تفاوت که از داده های داینامیک استفاده می کند. به تغییرات متد Details در کنترلر دقت کنید:

و در View :

viewbag example

اگر دقت کنید متوجه می شوید که در هنگام استفاده از ViewBag احتیاجی به cast نیست.

Strongly Typed View

 دو روش قبلی ViewBag و ViewData دارای مشکلاتی هستند. به عنوان مثال در کد های Razor دارای Intellisense نیستند و اگر اشتباه نوشته شده باشند فقط در هنگام runtime به خطا بروز پیدا می کند. برای رفع این مشکل از روش دیگری استفاده می شود. در کنترلر، یکی از overload های View این است که می توان به آن یک Model را پاس داد.

در کد های Razor به جای کد های قبلی باید اینگونه نوشت:

strongly typed view example

راه های دسترسی به View های مختلف

  • اگر در کنترلر بخواهیم به view ای غیر از view ای که همنام متد است دسترسی داشته باشیم کافیست نام آن را بنویسیم:

در این صورت به جای Details ، ویو ای با نام Test اجرا می شود.

test view example
  • اگر ویو مدنظر در پوشه ی جداگانه ای باشد:
other view example

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

توجه کنید که چون آدرس دهی فوق مطلق است و نه نسبی، در این صورت باید پسوند فایل حتما نوشته شود.

  • آدرس دهی نسبی

  • می توان هم آدرس و هم دیتا به View داد:

View Model

در روش قبلی می توانستیم مدل را به راحتی بفرستیم ولی برای پاس دادن Page Title یا هر property دیگری به View مجبور بودیم که از viewData و یا ViewBag استفاده کنیم که با مشکلاتی همراه بودند وهمانند strongly typed view به صورت داینامیک نبودند. برای حل این مشکل از یک viewModel استفاده می کنیم. بدین منظور ابتدا یک پوشه به نام ViewModels ایجاد و سپس یک کلاس viewModel در آن به شکل زیر می نویسیم:

و در کنترلر تغییرات زیر را اعمال می کنیم:

و کدهای Razor View به شکل زیر خواهد بود.

viewmodel example

نوشته شده توسط mrbitmap علیرضا علی رمضانی

مقالات مرتبط

جدیدترین مقالات

فهرست