- با ارائهی نگارش RC، مداخل ذکر شدهی در صفحهی index.html کاهش یافته و به فایل systemjs.config.js منتقل شدهاند.
- با استفاده از فایل systemjs.config.js دیگر نیازی به ذکر متد ({}) System.config در فایل index.html نیست.
- تعاریف فایل main.ts اینبار از مسیر ذیل خوانده میشوند:
/// <reference path="../typings/es6-shim.d.ts" /> import {bootstrap} from '@angular/platform-browser-dynamic';
"scripts": { "postinstall": "typings install" },
Ionic , react native , flutter , xamarin ….
مزایای نوشتن یک اپلیکیشن با فریم ورکها:
1- نوشتن کد به مراتب آسانتر است.
۲- چون اکثر فریم ورکها، فریم ورکهای جاوا اسکریپتی هستند، سرعت بالایی هنگام run کردن برنامه دارند ولی در build آخر و خروجی نهایی بر روی پلتفرم، این سرعت کندتر میشود.
۳- cossplatform بودن. با طراحی یک اپلیکیشن برای یک پلتفرم میتوان همزمان برای پلتفرمهای دیگر خروجی گرفت.
۱- برنامه نویس را محدود میکند.
۲- سرعت اجرای پایینی دارد.
۳- حجم برنامه به مراتب بالاتر میباشد.
۴- از منابع سخت افزاری بیشتری استفاده میکند.
اگر شما هم میخواهید از فریم ورکها برای طراحی اپلیکیشن استفاده کنید در اینجا میتوانید اطلاعات بیشتری را درباره هر کدام از فریم ورکها ببینید. هر کدام از این فریم ورکها دارای مزایا معایب و همچنین رزومه کاری خوب میباشند. بیشتر فریم ورکهای بالا در رندر آخر، همان کد native را تولید میکنند؛ مثلا اگر برنامهای را با react native بنویسید، میتوانید همان برنامه را بر روی اندروید استودیو و کد native بالا بیارید. توضیحات بالا مقایسه فریم ورکهای Cross Platform با زبانهای native بود. اما در این مقاله قصد آشنایی با تکنولوژی جدیدی را داریم که شما را قادر میسازد یک وب اپلیکیشن را با آن طراحی کنید.
pwa مخفف Progressive Web Apps است و یک تکنولوژی برای طراحی وب اپلیکیشنهای تحت مرورگر میباشد. شما با pwa میتوانید اپلیکیشن خود را بر روی پلتفرمهای مختلفی اجرا کنید، طوری که کاربران متوجه نشوند با یک صفحهی وبی دارند کار میکنند. شاید شما هم فکر کنید این کار را هم میتوان با html ,css و responsive کردن صفحه انجام داد! ولی اگر بخواهید کاربر متوجه استفادهی از یک صفحهی وبی نشود، باید حتما از pwa استفاده کنید! برای مثال یک صفحهی وبی معمولی حتما باید در بستر اینترنت اجرا شود، ولی با pwa با یکبار وصل شدن به اینترنت و کش کردن دادهها، برای بار دوم دیگر نیازی به اینترنت ندارد و میتواند به صورت offline کار کند. شما حتی با pwa میتوانید اپلیکیشن را در background اجرا کنید و notification ارسال کنید.
۱- یکی از مزیتهای مهم pwa، حالت offline آن میباشد که حتی با قطع اینترنت، شما میتوانید همچنان با اپلیکیشن کار کنید.
۲- با توجه به اینکه شما در حقیقت با یک صفحهی وبی کار میکنید، دیگر نیازی به دانلود و نصب ندارید.
۳- امکان بهروز رسانی کردن، بدون اعلام کردن نسخه جدید.
۴- از سرعت بسیار زیادی برخوردار است.
۵- چون pwa از پروتکل https استفاده میکند، دارای امنیت بالایی میباشد.
۱- محدود به مرورگر میباشد.
۲- هرچند امروزه اکثر مرورگرها pwa را پشتیبانی میکنند، ولی در بعضی از مرورگرها و مرورگرهای با ورژن پایین، pwa پشتیبانی نمیشود.
3- نمیتوان یک برنامهی مبتنی بر os را نوشت و محدود به مرورگر میباشد
1- برای pwa لزومی ندارد حتما از فریم ورکهای spa استفاده کنید. شما از هر فریم ورک Client Side ای میتوانید استفاده کنید.
۲- چون صفحات شما در پلتفرمهای مختلف و با صفحه نمایشهای مختلفی اجرا میشود، باید صفحات به صورت کاملا responsive شده طراحی شوند.
۳- باید از پروتکل https استفاده کنید.
ما در این مقاله از فریم ورک angular استفاده خواهیم کرد.
قبل از شروع، با شیوه کار pwa آشنا خواهیم شد. یکی از قسمتهای مهم Service Worker ،pwa میباشد که از جمله کش کردن، notification فرستادن و اجرای پردازشها در پس زمینه را بر عهده دارد.
چند نکته در رابطه با Service Worker
- نباید برای نگهداری داده global از Service Worker استفاد کرد. برای استفاده از دادههای Global میتوان از Local Storage یا IndexedDB استفاده کرد.
- service worker به dom دسترسی ندارند.
قبل از شروع، سناریوی پروژه را تشریح خواهیم کرد. رکن اصلی یک برنامهی وب، UI آن میباشد و قصد داریم کاربران را متوجه کار با یک صفحهی وبی نکنیم. قالبی که ما در این مثال در نظر گرفتیم خیلی شبیه به یک اپلیکیشن پلتفرم اندرویدی میباشد. یک کاربر با کشیدن منوی کشویی میتواند گزینههای خود را انتخاب نمایند. اولین گزینهای که قصد پیاده سازی آن را داریم، ثبت کاربران میباشد. بعد از ثبت کاربران در یک Component جدا، کاربران را در یک جدول نمایش خواهیم داد.
1- سرویس crud را به صورت کامل در پروژه قرار خواهیم داد، ولی چون از حوصلهی مقاله خارج است، فقط ثبت کاربران و نمایش کاربران را پیاده سازی خواهیم کرد.
شروع به کار
پیش نیازهای یک پروژهی انگیولاری را بر روی سیستم خود فراهم کنید. ما در این مثال از یک template آماده انگیولاری استفاده خواهیم کرد. پس برای اینکه با جزئیات و طراحی ui درگیر نشویم، از لینک github پروژه را دریافت کنید.
سپس وارد root پروژه شوید و با دستور زیر پکیجهای پروژه را نصب کنید:
npm install
قبل از اینکه کاری را انجام دهید، چند بار صفحه را refresh کنید! صفحه بدون هیچ تغییری refresh میشود. اینبار گزینهی offline را فعال کنید و مجددا صفحه را refresh کنید.
نصب pwa بر روی پروژه
برای اضافه کردن pwa به پروژه وارد ریشهی پروژه شوید و دستور زیر را وارد کنید:
ng add @angular/PWA
Manifest.json : اگر محتویات فایل را مشاهده کرده باشید، شامل تنظیمات فنی وب اپلیکیشن میباشد؛ از جمله Home Screen Icon و نام وب اپلیکیشن و سایر تنظیمات دیگر.
Nsgw-config.json : این فایل نسبت به فایل manifest فنیتر میباشد و بیشتر به کانفیگ مد آفلاین و کش کردن مرتبط میشود. در ادامه با این فایل بیشتر کار داریم.
اجرا کردن وب اپلیکیشن
برای اجرا کردن و نمایش خروجی از وب اپلیکیشن، ابتدا باید از پروژه build گرفت. با استفاده از دستور زیر از پروژه خود build بگیرید:
ng build -- prod
cd dist/Web Application Pwa
Http-server -o
npm i http-server
برسی فایل Nsgw-config.json
وارد فایل Nsgw-config.json شوید:
"$schema": "./node_modules/@angular/service-worker/config/schema.json", "index": "/index.html", "assetGroups": [ { "name": "app", "installMode": "prefetch", "resources": { "files": [ "/favicon.ico", "/index.html", "/*.css", "/*.js" ] } }, { "name": "assets", "installMode": "lazy", "updateMode": "prefetch", "resources": { "files": [ "/assets/**", "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)" ] } } ], "dataGroups": [ { "name": "api-performance", "urls": [ "https://api/**" ], "cacheConfig": { "strategy": "performance", "maxSize": 100, "maxAge": "3d" } } ] }
۱- assetGroups : کش کردن اطلاعات مربوط به اپلیکیشن
۲- Index : کش کردن فایل مربوط به index.html
۳- assetGroups : کش کردن فایلهای مربوط به asset، شامل فایلهای js، css و غیره
۴- dataGroups : این object مربوط به وقتی است که برنامه در حال اجرا است. میتوان دادههای در حال اجرای اپلیکیشن را کش کرد. دادهی در حال اجرا میتواند شامل فراخوانی apiها باشد. برای مثال فرض کنید شما در حالت کار کردن online با اپلیکیشن، لیستی از اسامی کاربران را از api گرفته و نمایش میدهید. وقتی دفعهی بعد در حالت offline اپلیکیشن را باز کنیم، اگر api را کش کرده باشیم، اپلیکیشن دادهها را از کش فراخوانی میکند. این عمل درباره post کردن دادهها هم صدق میکند.
خود dataGroups شامل چند object زیر میباشد:
۱- name : یک نام انتخابی برای Groups میباشد.
۲- urls : شامل آرایهای از آدرسها میباشد. میتوان آدرس یک دومین را همراه با کل apiها به صورت زیر کش کرد:
"https://api/**"
۱- maxSize : حداکثر تعداد کشهای مربوط به Groups .
۲- maxAge : حداکثر lifetime مربوط به کش.
۳- strategy : که میتواند یکی از مقادیر freshness به معنی Network-First یا performance به معنی Cache-First باشد.
پیاده سازی پیغام نمایش بهروزرسانی جدید وب اپلیکیشن
در اپلیکیشنهای native وقتی بهروزرسانی جدیدی برای app اعلام میشود، در فروشگاهای اینترنتی پیغامی مبنی بر بهروزرسانی جدید app برای کاربران ارسال میشود که کاربران میتوانند app خود را بهروزرسانی کنند. ولی در pwa تنها با یک رفرش صفحه میتوان اپلیکیشن را به جدیدترین امکانات بهروزرسانی کرد! برای اینکه بتوانیم با هر تغییر، پیغامی را جهت بهروزرسانی نسخه یا هر پیغامی دیگری را نمایش دهیم، از کد زیر استفاده میکنم:
if(this.swUpdate.isEnabled) { this.swUpdate.available.subscribe(()=> { if(confirm("New Version available.Load New Version?")){ window.location.reload(); } }) }
در منوی سمت چپ، بر روی database کلیک کنید و یک دیتابیس را در حالت test mode ایجاد نماید. سپس یک collection را به نام user ایجاد کرده و فیلدهای زیر را به آن اضافه کنید:
Age :number Fullname :string Mobile : string
npm install --save firebase @angular/fire
@NgModule({ declarations: [AppComponent, RegisterComponent,AboutComponent, UserListComponent], imports: [ BrowserModule, FormsModule, HttpClientModule, HttpClientModule, SharedModule, AppRoutingModule, AngularFireModule.initializeApp(environmentFirebase.firebase), AngularFireDatabaseModule, ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }), ], providers: [FirebaseService], bootstrap: [AppComponent] }) export class AppModule {}
export const environment ={ production: true, firebase: { apiKey: "AIz×××××××××××××××××××××××××××××××××8", authDomain: "pwaangular-6c041.firebaseapp.com", databaseURL: "https://pwaangular-6c041.firebaseio.com", projectId: "pwaangular-6c041", storageBucket: "pwaangular-6c041.appspot.com", messagingSenderId: "545522081966" } }
FirebaseService در قسمت providers مربوط به سرویس crud میباشد. اگر وارد فایل مربوطه شوید، چند عمل اصلی به صورت زیر در آن پیاده سازی شده است:
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import * as firebase from 'firebase'; import { AngularFireDatabase } from '@angular/fire/database'; import { HttpClient } from '@angular/common/http'; import { map } from 'rxjs/operators'; import { ThrowStmt } from '@angular/compiler'; @Injectable({ providedIn: 'root' }) export class FirebaseService { ref = firebase.firestore().collection('users'); constructor(public db: AngularFireDatabase,public _http:HttpClient) { } getUsers(): Observable<any> { return new Observable((observer) => { this.ref.onSnapshot((querySnapshot) => { let User = []; querySnapshot.forEach((doc) => { let data = doc.data(); User.push({ key: doc.id, fullname: data.fullname, age: data.age, mobile: data.mobile }); }); observer.next(User); }); }); } getUser(id: string): Observable<any> { return new Observable((observer) => { this.ref.doc(id).get().then((doc) => { let data = doc.data(); observer.next({ key: doc.id, title: data.title, description: data.description, author: data.author }); }); }); } postUser(user): Observable<any> { return new Observable((observer) => { this.ref.add(user).then((doc) => { observer.next({ key: doc.id, }); }); }); } updateUser(id: string, data): Observable<any> { return new Observable((observer) => { this.ref.doc(id).set(data).then(() => { observer.next(); }); }); } deleteUser(id: string): Observable<{}> { return new Observable((observer) => { this.ref.doc(id).delete().then(() => { observer.next(); }); }); } getDataOnApi(){ return this._http.get('https://site.com/api/General/Getprovince') .pipe( map((res: Response) => { return res; }) ); } getOnApi(){ return this._http.get("https://site.com/api/General/Getprovince",).pipe( map((response:any) => { return response } ) ); } }
با دستورات زیر میتوانید مجددا پروژه را اجرا کنید:
ng build --prod cd dist/Pwa-WepApp Http-server -o
تست وب اپلیکیشن بر روی پلتفرمهای مختلف
برای اینکه بتوانیم خروجی وب اپلیکیشن را بر روی پلتفرمهای مختلفی تست کنیم، میتوانیم آن را آپلود کرده و مثل یک سایت اینترنتی، با وارد کردن دومین، وارده پروژه شد. ولی کم هزینهترین راه، استفاده از ابزار ngrok میباشد. میتوانید توسط این مقاله پروژه خودتان در لوکال بر روی https سوار کنید.
نکته! توجه کنید apiهای مربوط به firebase را نمیتوان کش کرد.
کدهای مربوط به این قسمت را میتوانید از این repository دریافت کنید .
با توجه به ابتدای آموزش، کدهای زیر را در ترمینال وارد میکنیم:
sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet/ trusty main" > /etc/apt/sources.list.d/dotnetdev.list' sudo apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893 sudo apt-get update
در خط دوم، کلید اختصاصی این پکیج جهت اعتبارسنجی معرفی میگردد که در سایت جاری قبلا به آن پرداخته شده است. در خط آخر هم مخازن موجود را به روزرسانی میکنیم تا آماده استفاده شود.
در سایت مایکروسافت از شما خواسته میشود که کد زیر را وارد کنید:
sudo apt-get install dotnet-dev-1.0.0-preview1-002702
sudo apt-get install dotnet-dev-1.0.0-preview2-003096
The following packages have unmet dependencies: dotnet-dev-1.0.0-preview1-002702 : Depends: dotnet-sharedframework-microsoft.netcore.app-1.0.0-rc2-3002702 but it is not going to be installed E: Unable to correct problems, you have held broken packages.
sudo dpkg -i libicu52_52.1-3ubuntu0.4_amd64.deb
sudo apt-get install dotnet-sharedframework-microsoft.netcore.app-1.0.0-rc2-3002702 sudo apt-get install dotnet-dev-1.0.0-preview2-003096
dotnet --version
1.0.0-preview2-003096
inject$ در AngularJs
ابتدا مثال زیر را به روشهای قبلی پیاده سازی میکنیم:
var app = angular.module('myApp', []); app.factory('bookService', function () { var books = [ { name: 'A' }, { name: 'B' }, { name: 'C' } ]; return books; }); app.controller('bookCtrl', function ($scope, bookService) { $scope.books = bookService; })
<script type="text/javascript" src="~/scripts/Modules/module5.js"></script> <div ng-app="myApp"> <div ng-controller="bookCtrl"> <table> <tr ng-repeat="book in books"> <td> {{book.name}} </td> </tr> </table> </div> </div>
var bookCtrl = function (sc,bs) { sc.books = bs; };
app.controller('bookCtrl',bookCtrl);
bookCtrl.$inject = ['$scope','bookService'];
var app = angular.module('myApp', []); app.factory('bookService', function () { var books = [ { name: 'A' }, { name: 'B' }, { name: 'C' } ]; return books; }); var bookCtrl = function (sc,bs) { sc.books = bs; }; bookCtrl.$inject = ['$scope','bookService']; app.controller('bookCtrl',bookCtrl);
از این پس در هنگام فراخوانی تابع کنترلر bookCtrl سرویسهای scope$ و bookService به ترتیب به عنوان آرگومانهای اول و دوم در اختیار کنترلر قرار میگیرند. میتوان به جای فراخوانی مستقیم inject$، تزریق وابستگیها را در هنگام تعریف توابع سازنده به صورت زیر نیز فراهم ساخت:
app.controller('bookCtrl', ['$scope', 'bookService', function (sc, bs) { sc.books = bs; }])
xcopy /s /y D:\Project\Framework\Framework.Web\bin\Debug\Framework.dll D:\Project\Current\DependentDLL xcopy /s /y D:\Project\Framework\Framework.Web\bin\Debug\Framework.Common.dll D:\Project\Current\DependentDLL xcopy /s /y D:\Project\Framework\Framework.Web\bin\Debug\Framework.Business.dll D:\Project\Current\DependentDLL xcopy /s /y D:\Project\Framework\Framework.Web\bin\Debug\Framework.Web.dll D:\Project\Current\DependentDLL
MVC Scaffolding #1
کل سری ASP.NET MVC
به همراه کل سری EF Code First
MVC Scaffolding چیست؟
MVC Scaffolding ابزاری است برای تولید خودکار کدهای «اولیه» برنامه، جهت بالا بردن سرعت تولید برنامههای ASP.NET MVC مبتنی بر EF Code First.
بررسی مقدماتی MVC Scaffolding
امکان اجرای ابزار MVC Scaffolding از دو طریق دستورات خط فرمان Powershell و یا صفحه دیالوگ افزودن یک کنترلر در پروژههای ASP.NET MVC وجود دارد. در ابتدا حالت ساده و ابتدایی استفاده از صفحه دیالوگ افزودن یک کنترلر را بررسی خواهیم کرد تا با کلیات این فرآیند آشنا شویم. سپس در ادامه به خط فرمان Powershell که اصل توانمندیها و قابلیتهای سفارشی MVC Scaffolding در آن قرار دارد، خواهیم پرداخت.
برای این منظور یک پروژه جدید MVC را آغاز کنید؛ ابزارهای مقدماتی MVC Scaffolding از اولین به روز رسانی ASP.NET MVC3 به بعد با VS.NET یکپارچه هستند.
ابتدا کلاس زیر را به پوشه مدلهای برنامه اضافه کنید:
using System; using System.ComponentModel; using System.ComponentModel.DataAnnotations; namespace MvcApplication1.Models { public class Task { public int Id { set; get; } [Required] public string Name { set; get; } [DisplayName("Due Date")] public DateTime? DueDate { set; get; } [DisplayName("Is Complete")] public bool IsComplete { set; get; } [StringLength(450)] public string Description { set; get; } } }
همانطور که ملاحظه میکنید در قسمت قالبها، تولید کنترلرهایی با اکشن متدهای ثبت و نمایش اطلاعات مبتنی بر EF Code First انتخاب شده است. کلاس مدل نیز به کلاس Task فوق تنظیم گردیده و در زمان انتخاب DbContext مرتبط، گزینه new data context را انتخاب کرده و نام پیش فرض آنرا پذیرفتهایم. زمانیکه بر روی دکمه Add کلیک کنیم، اتفاقات ذیل رخ خواهند داد:
الف) کنترلر جدید TasksController.cs به همراه تمام کدهای Insert/Update/Delete/Display مرتبط تولید خواهد شد.
ب) کلاس DbContext خودکاری به نام MvcApplication1Context.cs در پوشه مدلهای برنامه ایجاد میگردد تا کلاس Task را در معرض دید EF Code first قرار دهد. (همانطور که عنوان شد یکی از پیشنیازهای بحث Scaffolding آشنایی با EF Code first است)
ج) در پوشه Views\Tasks، پنج View جدید را جهت مدیریت فرآیندهای نمایش صفحات Insert، حذف، ویرایش، نمایش و غیره تهیه میکند.
د) فایل وب کانفیگ برنامه جهت درج رشته اتصالی به بانک اطلاعاتی تغییر کرده است. حالت پیش فرض آن استفاده از SQL CE است و برای استفاده از آن نیاز است قسمت 15 سری EF سایت جاری را پیشتر مطالعه کرده باشید (به چه اسمبلیهای دیگری مانند System.Data.SqlServerCe.dll برای اجرا نیاز است و چطور باید اتصال به بانک اطلاعاتی را تنظیم کرد)
معایب:
کیفیت کد تولیدی پیش فرض قابل قبول نیست:
- DbContext در سطح یک کنترلر وهله سازی شده و الگوی Context Per Request در اینجا بکارگرفته نشده است. واقعیت یک برنامه ASP.NET MVC کامل، داشتن چندین Partial View تغدیه شونده از کنترلرهای مختلف در یک صفحه واحد است. اگر قرار باشد به ازای هر کدام یکبار DbContext وهله سازی شود یعنی به ازای هر صفحه چندین بار اتصال به بانک اطلاعاتی باید برقرار شود که سربار زیادی را به همراه دارد. (قسمت 12 سری EF سایت جاری)
- اکشن متدها حاوی منطق پیاده سازی اعمال CRUD یا همان Create/Update/Delete هستند. به عبارتی از یک لایه سرویس برای خلوت کردن اکشن متدها استفاده نشده است.
- از ViewModel تعریف شدهای به نام Task هم به عنوان Domain model و هم ViewModel استفاده شده است. یک کلاس متناظر با جداول بانک اطلاعاتی میتواند شامل فیلدهای بیشتری باشد و نباید آنرا مستقیما در معرض دید یک View قرار داد (خصوصا از لحاظ مسایل امنیتی).
مزیتها:
قسمت عمدهای از کارهای «اولیه» تهیه یک کنترلر و همچنین Viewهای مرتبط به صورت خودکار انجام شدهاند. کارهای اولیهای که با هر روش و الگوی شناخته شدهای قصد پیاده سازی آنها را داشته باشید، وقت زیادی را به خود اختصاص داده و نهایتا آنچنان تفاوت عمدهای هم با کدهای تولیدی در اینجا نخواهند داشت. حداکثر فرمهای آنرا بخواهید با jQuery Ajax پیاده سازی کنید یا کنترلهای پیش فرض را با افزونههای jQuery غنی سازی نمائید. اما شروع کار و کدهای اولیه چیزی بیشتر از این نیست.
نصب بسته اصلی MVC Scaffolding توسط NuGet
بسته اصلی MVC Scaffolding را با استفاده از دستور خط فرمان Powershell ذیل، از طریق منوی Tools، گزینه Library package manager و انتخاب Package manager console میتوان به پروژه خود اضافه کرد:
Install-Package MvcScaffolding
Attempting to resolve dependency 'T4Scaffolding'. Attempting to resolve dependency 'T4Scaffolding.Core'. Attempting to resolve dependency 'EntityFramework'. Successfully installed 'T4Scaffolding.Core 1.0.0'. Successfully installed 'T4Scaffolding 1.0.8'. Successfully installed 'MvcScaffolding 1.0.9'. Successfully added 'T4Scaffolding.Core 1.0.0' to MvcApplication1. Successfully added 'T4Scaffolding 1.0.8' to MvcApplication1. Successfully added 'MvcScaffolding 1.0.9' to MvcApplication1.
پس از اینکه بسته MvcScaffolding به پروژه جاری اضافه شد، همان مراحل قبل را که توسط صفحه دیالوگ افزودن یک کنترلر انجام دادیم، اینبار به کمک دستور ذیل نیز میتوان پیاده سازی کرد:
Scaffold Controller Task
نکته و مزیت مهم دیگری که در اینجا در دسترس میباشد، سوئیچهای خط فرمانی است که به همراه صفحه دیالوگ افزودن یک کنترلر وجود ندارند. برای مثال دستور Scaffold Controller را تایپ کرده و سپس یک خط تیره را اضافه کنید. اکنون دکمه tab را مجددا بفشارید. منویی ظاهر خواهد شد که بیانگر سوئیچهای قابل استفاده است.
برای مثال اگر بخواهیم دستور Scaffold Controller Task را با جزئیات اولیه کاملتری ذکر کنیم، مانند تعیین نام دقیق کلاس مدل و کنترلر تولیدی به همراه نام دیگری برای DbContext مرتبط، خواهیم داشت:
Scaffold Controller -ModelType Task -ControllerName TasksController -DbContextType TasksDbContext
بهبود مقدماتی کیفیت کد تولیدی MVC Scaffolding
در همان کنسول پاروشل NuGet، کلید up arrow را فشار دهید تا مجددا دستور قبلی اجرا شده ظاهر شود. اینبار دستور قبلی را با سوئیچ جدید Repository (استفاده از الگوی مخزن) اجرا کنید:
Scaffold Controller -ModelType Task -ControllerName TasksController -DbContextType TasksDbContext -Repository
Scaffold Controller -ModelType Task -ControllerName TasksController -DbContextType TasksDbContext -Repository -Force
public class TasksController : Controller { private readonly ITaskRepository taskRepository; // If you are using Dependency Injection, you can delete the following constructor public TasksController() : this(new TaskRepository()) { } public TasksController(ITaskRepository taskRepository) { this.taskRepository = taskRepository; }
public interface ITaskRepository : IDisposable { IQueryable<Task> All { get; } IQueryable<Task> AllIncluding(params Expression<Func<Task, object>>[] includeProperties); Task Find(int id); void InsertOrUpdate(Task task); void Delete(int id); void Save(); }
پیاده سازی این اینترفیس در حالت متد Save آن شامل فراخوانی context.SaveChanges است. این مورد باید به الگوی واحد کار (که در اینجا تعریف نشده) منتقل شود. زیرا در یک دنیای واقعی حاصل کار بر روی چندین موجودیت باید در یک تراکنش ذخیره شوند و قرارگیری متد Save داخل کلاس مخزن یا سرویس برنامه، مخزنهای تعریف شده را تک موجودیتی میکند.
اما در کل با توجه به اینکه پیاده سازی منطق کار با موجودیتها به کلاسهای مخزن واگذار شدهاند و کنترلرها به این نحو خلوتتر گردیدهاند، یک مرحله پیشرفت محسوب میشود.
public class MyController : Controller { [ImportingConstructor] public MyController(MyViewModel viewModel) { ViewModelCore = viewModel; } public MyViewModel ViewModelCore { get; private set; } public void Run() { AddWeakEventListener(ViewModelCore , ViewModelCoreChanged) } private void ViewModelCoreChanged(object sender , PropertyChangedEventArgs e) { if(e.PropertyName=="CurrentItem") { } } }
از آنجا که در دات نت 4.5 یک پیاده سازی خاص از الگوی WeakEvent در کلاس PropertyChangedEventManager موجود در اسمبلی WindowsBase و فضای نام System.ComponentModel انجام شده است در نتیجه توسعه دهندگان این کتابخانه نیز تصمیم به استفاده از این روش گرفتند که نتیجه آن Obsolete شدن کلاس پایه کنترلر در نسخههای 3 به بعد آن است. در روش جدید کافیست به صورت زیر عمل نمایید:
[Export] public class BookController { [ImportingConstructor] public BookController(BookViewModel viewModel) { ViewModelCore = viewModel; } public BookViewModel ViewModelCore { get; private set; } public DelegateCommand RemoveItemCommand { get; private set; } private void ExecuteRemoveItemCommand() { ViewModelCore.Books.Remove(ViewModelCore.CurrentItem); } private bool CanExecuteRemoveItemCommand() { return ViewModelCore.CurrentItem != null; } private void Initialize() { RemoveItemCommand = new DelegateCommand(ExecuteRemoveItemCommand , CanExecuteRemoveItemCommand); ViewModelCore.RemoveItemCommand = RemoveItemCommand; } public void Run() { var result = new List<Book>(); result.Add(new Book { Code = 1, Title = "Book1" }); result.Add(new Book { Code = 2, Title = "Book2" }); result.Add(new Book { Code = 3, Title = "Book3" }); Initialize(); ViewModelCore.Books = new ObservableCollection<Models.Book>(result); PropertyChangedEventManager.AddHandler(ViewModelCore, ViewModelChanged, "CurrentItem"); (ViewModelCore.View as IBookView).Show(); } private void ViewModelChanged(object sender,PropertyChangedEventArgs e) { if(e.PropertyName == "CurrentItem") { RemoveItemCommand.RaiseCanExecuteChanged(); } } }
»ابتدا متدی به نام CanExecuteRemoveItemCommand ایجاد کردیم و کدهای اعتبارسنجی را در آن قرار دادیم؛
»هنگام تعریف Command مربوطه متد بالا را به DelegateCommand رجیستر کردیم:
RemoveItemCommand = new DelegateCommand(ExecuteRemoveItemCommand , CanExecuteRemoveItemCommand);
PropertyChangedEventManager.AddHandler(ViewModelCore, ViewModelChanged, "CurrentItem");
اجرای برنامه:
ابتدا دکمه RemoveItem غیر فعال است:
بعد از انتخاب یکی از گزینه و فراخوانی مجدد متد CanExecuteRemoveItemCommand دکمه مورد نظر فعال میشود:
و در نهایت دکمه RemoveItem فعال خواهد شد:
دانلود سورس پروژه
+ پس از مدتی کار با NET Core. به این نتیجه خواهید رسید که هیچ نیازی به استفاده از استراکچرمپ و یا IoC Containers ثالث در اینجا نیست و امکانات توکار خود آن برای مدیریت اغلب پروژهها کافی است. در کل وابستگی ثالث کمتر = نگهداری سادهتر پروژه در دراز مدت و همچنین سربار اجرایی کمتر.
- اگر سورس پروژههای منتشر شدهی مبتنی بر NET Core. را در طی این چندسال بررسی کنید، در عمل کسی از IoC Continers ثالث در اینجا استفاده نمیکند و اغلب پروژهها (حتی پروژههای بزرگ) از همان امکانات توکار تزریق وابستگیهای آن استفاده میکنند.
با انتخاب ok باز نیز با قالب جدیدی به شکل زیر برای انتخاب پروژه مواجه میشوید.
اینجا همه چیز تکراری است به غیر از گزینه Configure Authentication.
همهی گزینهها تکراری اند به غیر از گزینه Individual User Accounts. البته این همان FormsAuthentication قبلی است. نکته قابل توجه، یکپارچی آن با سرویسهای اجتماعی و شبکههای سرویس دهنده است. البته در نسخهی قبلی نیز این سیستم وجود داشت، ولی این دفعه با ASP.NET Identity یک پارچه است که در ادامه بیشتر آن را خواهید دید.
البته گویا حالت دیگری به نام Organizational Accounts نیز وجود دارد که گویا برای فعال سازی،باید یک بستهی به روز رسانی دریافت میکردم، که من نکردم.(اینترنت حجمی و شبانه دانلود کردن...)
این حالت که در شکل زیر مشخص است، امکان یکپارچگی احراز هویت با Active Directory در windows server و azure را دارد.
با توجه به پوشهی مدل این را متوجه میشویم که مایکروسافت هم به لزوم ViewModel اعتقاد پیدا کرده است.
با اجرا کردن پروژه bootstrap و responsive بودن آن، خودنمایی میکنند.