بهبود SEO در ASP.NET MVC
EF Code First #12
لطفا از این پس مطالبی رو که در قسمت نظرات عنوان میکنید متناسب با عنوان موضوع جاری آن (برای مثال context per request در اینجا) باشد. با تشکر.
This is the first of an eight part series where I am joined by Phil Japikse to discuss design patterns. A design pattern is a best practice you can use in your code to solve a common problem. In this episode, Phil demonstrates the Command and Memento patterns.
Episodes in this series:
- Command/Memento patterns (this episode)
- Strategy pattern
- Template Method pattern (to be published 7/20)
- Observer/Publish-Subscribe patterns (to be published 7/25)
- Singleton pattern (to be published 8/8)
- Factory patterns (to be published 8/10)
- Adapter/Facade patterns (to be published 8/15)
- Decorator pattern (to be published 8/17)
در این قسمت با نحوهی تناظر آدرسها توسط Web API به متدهای موجود در Controller آشنا میشوید.
در هر درخواستی که ارسال میشود، Web API، انتخاب Controller مناسب را با رجوع به جدولی با نام جدول مسیرها انجام میدهد. زمانی که یک پروژهی جدید با استفاده از ASP.NET MVC 4 ایجاد میکنید، یک route پیش فرض به صورت ذیل در متد RegisterRoutes قرار میگیرد.
routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );
- {controller} به نام Controller تناظر پیدا میکند.
- نوع درخواست ارسالی (GET، POST، PUT، DELETE) به نام متد تناظر پیدا میکند.
- اگر قسمت {id} در آدرس وجود داشته باشد، به پارامتر id متد انتخاب شده پاس داده میشود.
- اگر آدرس دارای Query String باشد، به پارامترهای همنام خود در متد، تناظر پیدا میکنند.
در ذیل، مثال هایی را از چند آدرس درخواستی و نتیجهی حاصل از فراخوانی آنها مشاهده میکنید.
- آدرس api/products/ با نوع درخواست GET به متد ()GetAllProducts
- آدرس api/products/1/ با نوع درخواست GET به متد (1)GetProductById
- آدرس api/products?category=hardware/ با نوع درخواست GET به متد ("GetProductByCategory("hardware
در آدرس اول، عبارت "products" به ProductsController تطبیق پیدا میکند. درخواست نیز از نوع GET است، بنابراین Web API به دنبال متدی در Controller میگردد که نام آن با عبارت GET "آغاز" شده باشد. همچنین، آدرس شامل قسمت {id} نیز نیست. بنابراین، Web API متدی را انتخاب میکند که پارامتر ورودی ندارد. متد GetAllProducts در ProductsController، تمامی این شروط را دارد، پس انتخاب میشود.
در دومین آدرس، همان حالت قبل وجود دارد، با این تفاوت که در آدرس درخواستی، قسمت {id} وجود دارد. از آنجا که نوع قسمت {id} در متد int ،GetProductById تعریف شده است، باید یک عدد صحیح بعد از آدرس /api/products وجود داشته باشد تا متد GetProductById فراخوانی شود. این عدد به طور خودکار به نوع int تبدیل شده و در پارامتر اول متد GetProductById قرار میگیرد. در ذیل، برخی آدرسها را ملاحظه میکنید که معتبر نیستند و باعث بروز خطا میشوند.
- آدرس api/products/ با نوع درخواست POST، باعث خطای 405Method Not Allowed میشود.
- آدرس api/users/ با نوع درخواست GET، باعث خطای 404Not Found میشود.
- آدرس api/products/abc/ با نوع درخواست GET، باعث خطای 400Bad Request میشود.
در آدرس اول، Client یک درخواست از نوع POST ارسال کرده است. Web API به دنبال متدی میگردد که نام آن با عبارت Post آغاز میشود. اما متدی با این شرط در ProductsController وجود ندارد. بنابراین، پاسخی که دریافت میشود، عبارت "405 Method Not Allowed" است. درخواست برای آدرس /api/users/ نیز معتبر نیست، چون Controllerیی با نام UsersController وجود ندارد. و سومین آدرس نیز بدین دلیل نامعتبر است که قسمت abc نمیتواند به یک عدد صحیح تبدیل شود.
زمانی که با یک وب سرویس کار میکنید، مشاهدهی محتویات درخواست ارسالی و پاسخ دریافتی میتواند کاربرد زیادی در درک نحوهی تعامل بین Client و وب سرویس و کشف خطاهای احتمالی داشته باشد. در Firefox با استفاده از افزونهی Firebug و در Internet Explorer 9 به بالا با ابزار Developer Tools آن میتوان درخواستها و پاسخها را مشاهده کرد. در Internet Explorer، کلید F12 را برای اجرای Developer Tools فشار دهید. از قسمت Network بر روی دکمهی Start Capturing کلیک کنید. حال کلید F5 را برای بارگذاری مجدد صفحه فشار دهید. Internet Explorer، درخواست و پاسخ رد و بدل شده بین مرورگر و Web Server را مانیتور کرده و گزارشی را نشان میدهد (شکل ذیل).
از ستون URL، آدرس /api/products/ را انتخاب و بر روی دکمهی Go to detailed view کلیک کنید. در قسمتی که باز میشود، گزینه هایی برای مشاهدهی هدرهای درخواست، پاسخ و همچنین بدنهی هر یک وجود دارد. به عنوان مثال، اگر قسمت Request headers را انتخاب کنید، خواهید دید که Internet Explorer از طریق هدر Accept، تقاضای پاسخ در قالب JSON را کرده است (شکل ذیل).
اگر قسمت Response body را انتخاب کنید، پاسخ دریافت شده در قالب JSON را خواهید دید.
در این قسمت قصد داریم از امکانات جدید اعتبار سنجی تعریف شده در فضای نام استاندارد System.ComponentModel.DataAnnotations استفاده نمائیم. از سیلورلایت سه به بعد امکان استفاده از این فضای نام به سادگی در برنامههای سیلورلایت میسر است (همچنین در برنامههای ASP.Net MVC)؛ اما برای کار با آن در WPF نیاز به تعدادی متد کمکی میباشد...
فهرست مطالب:
فصل 5- تعیین اعتبار ورودی کاربر و الگوی MVVM
- مقدمه
- معرفی برنامه فصل
- مدل برنامهی فصل
- ViewModel برنامه فصل
- View برنامه فصل
دریافت قسمت پنجم
دریافت مثال قسمت پنجم
تعدادی از منابع و مآخذ مورد استفاده در این سری:
2. Model View ViewModel
3. DataModel-View-ViewModel pattern
4. 5 Minute Overview of MVVM in Silverlight
5. A Field Guide to WPF Presentation Patterns
6. An attempt at simple MVVM with WPF
7. WPF: If Heineken did MVVM Frameworks Part 1 of n
8. Modal dialogs with MVVM and Silverlight 4
9. How do I do… With the Model-View-ViewModel pattern
10. Intro to WPF MVVM
11. Introduction to MVVM pattern in WPF
12. Learning WPF M-V-VM
13. Binding Combo Boxes in WPF with MVVM
14. Model-View-ViewModel Pattern
15. Unit Testable WCF Web Services in MVVM and Silverlight 4
16. MVVM Part 1: Overview
17. Which came first, the View or the Model?
18. Stackoverflow's questions tagged with MVVM
19. WPF: MVVM (Model View View-Model) Simplified
20. WPF and MVVM tutorial 01, Introduction
21. WPF patterns : MVC, MVP or MVVM or…?
22. Silverlight, MVVM and Validation Part III
23. DotNetKicks.com - Stories recently tagged with 'MVVM'
24. DotNetShoutout - Stories tagged with MVVM
25. MVVM Light Toolkit
26. MVVM screen casts
27. What’s new in MVVM Light V3
28. Using RelayCommands in Silverlight 3 and WPF
29. WPF Apps With The Model-View-ViewModel Design Pattern
30. WPF MVVM and Showing Dialogs
SPList list = mWeb.GetList(strUrl); if (list != null) { for (int i = list.ItemCount - 1; i >= 0; i--) { list.Items[i].Delete(); } list.Update(); }
public static void DeleteAllItems(string site, string list) { using (SPSite spSite = new SPSite(site)) { using (SPWeb spWeb = spSite.OpenWeb()) { StringBuilder deletebuilder = BatchCommand(spWeb.Lists[list]); spSite.RootWeb.ProcessBatchData(deletebuilder.ToString()); } } } private static StringBuilder BatchCommand(SPList spList) { StringBuilder deletebuilder= new StringBuilder(); deletebuilder.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Batch>"); string command = "<Method><SetList Scope=\"Request\">" + spList.ID + "</SetList><SetVar Name=\"ID\">{0}</SetVar><SetVar Name=\"Cmd\">Delete</SetVar></Method>"; foreach (SPListItem item in spList.Items) { deletebuilder.Append(string.Format(command, item.ID.ToString())); } deletebuilder.Append("</Batch>"); return deletebuilder; }
// We prepare a String.Format with a String.Format, this is why we have a {{0}} string command = String.Format("<Method><SetList Scope=\"Request\">{0}</SetList><SetVar Name=\"ID\">{{0}}</SetVar><SetVar Name=\"Cmd\">Delete</SetVar><SetVar Name=\"owsfileref\">{{1}}</SetVar></Method>", list.ID); // We get everything but we limit the result to 100 rows SPQuery q = new SPQuery(); q.RowLimit = 100; // While there's something left while (list.ItemCount > 0) { // We get the results SPListItemCollection coll = list.GetItems(q); StringBuilder sbDelete = new StringBuilder(); sbDelete.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Batch>"); Guid[] ids = new Guid[coll.Count]; for (int i=0;i<coll.Count;i++) { SPListItem item = coll[i]; sbDelete.Append(string.Format(command, item.ID.ToString(), item.File.ServerRelativeUrl)); ids[i] = item.UniqueId; } sbDelete.Append("</Batch>"); // We execute it web.ProcessBatchData(sbDelete.ToString()); //We remove items from recyclebin web.RecycleBin.Delete(ids); list.Update(); } }
- ایجاد متغیرها به سادگی با شروع نوشتن نام متغیر با $ و بدون تعریف نوع آنها انجام میشود
- write-host حکم write را دارد و واضح است که نوشتن تنهای آن برای ایجاد یک line break میباشد.
- کامنت کردن با #
- عدم وجود semi colon برای اتمام فرامین
[System.Reflection.Assembly]::Load("Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c") [System.Reflection.Assembly]::Load("Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c") [System.Reflection.Assembly]::Load("Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c") [System.Reflection.Assembly]::Load("System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") write-host # Enter your configuration here $siteUrl = "http://mysharepointsite.example.com/" $listName = "Name of my list" $batchSize = 1000 write-host "Opening web at $siteUrl..." $site = new-object Microsoft.SharePoint.SPSite($siteUrl) $web = $site.OpenWeb() write-host "Web is: $($web.Title)" $list = $web.Lists[$listName]; write-host "List is: $($list.Title)" while ($list.ItemCount -gt 0) { write-host "Item count: $($list.ItemCount)" $batch = "<?xml version=`"1.0`" encoding=`"UTF-8`"?><Batch>" $i = 0 foreach ($item in $list.Items) { $i++ write-host "`rProcessing ID: $($item.ID) ($i of $batchSize)" -nonewline $batch += "<Method><SetList Scope=`"Request`">$($list.ID)</SetList><SetVar Name=`"ID`">$($item.ID)</SetVar><SetVar Name=`"Cmd`">Delete</SetVar><SetVar Name=`"owsfileref`">$($item.File.ServerRelativeUrl)</SetVar></Method>" if ($i -ge $batchSize) { break } } $batch += "</Batch>" write-host write-host "Sending batch..." # We execute it $result = $web.ProcessBatchData($batch) write-host "Emptying Recycle Bin..." # We remove items from recyclebin $web.RecycleBin.DeleteAll() write-host $list.Update() } write-host "Done."
منابع یافتن فایلهای تعاریف نوعها
- بزرگترین مخزن کد فایلهای تعاریف نوعهای TypeScript، در سایت Github و در مخزن کد DefinitelyTyped قابل مشاهده است:
https://github.com/DefinitelyTyped/DefinitelyTyped
- همچنین ابزار دیگری به نام «Typings type definition manager» نیز میتواند برای این منظور بکار رود.
- علاوه بر اینها، بستههای npm نیز میتوانند به همراه تعاریف فایلهای .d.ts باشند.
مفهوم Ambient Modules
پروژههای TypeScript عموما به همراه تعداد زیادی ماژول هستند. به این ترتیب هر ماژول نیاز به d.ts. فایل مخصوص خودش خواهد داشت که نگهداری آنها مشکل خواهد بود. به همین جهت یک Solution متشکل از تعدادی ماژول، میتواند تمام تعاریف نوعها را در یک تک فایل d.ts. نگهداری کند که به آن Ambient Module نیز میگویند. برای نمونه فایل d.ts. ذیل را درنظر بگیرید:
// cardCatalog.d.ts declare module "CardCatalog"{ export function printCard(callNumber: string): void; }
سپس برای استفادهی از این فایل d.ts. خواهیم داشت:
// app.ts /// <reference path="cardCatalog.d.ts" /> import * as catalog from "CardCatalog";
بررسی مخرن DefinitelyTyped
DefinitelyTyped مخزن کد عظیمی از فایلهای تعاریف نوعهای TypeScript است. هرچند دریافت این فایلها از مخزن کد Github آن مانند سایر فایلهای متداول آن سایت، اما چندین روش دیگر نیز برای کار با این مخزن کد وجود دارد:
- استفاده از NuGet. تقریبا تمام فایلهای d.ts. آن به صورت یک بستهی نیوگت مجزا نیز وجود دارند.
- استفاده از برنامهی tsd. این برنامه یا type definition manager، به صورت اختصاصی برای کار با این نوع فایلها طراحی شدهاست.
- استفاده از برنامهی typings. این برنامه نیز یک type definition manager دیگر است. مزیت آن کار با چندین منبع مجزای ارائهی فایلهای d.ts. است که DefinitelyTyped تنها یکی از آنها است.
یک مثال: دریافت مستقیم و افزودن فایل d.ts. مربوط به کتابخانهی جاوا اسکریپتی lodash از مخزن کد DefinitelyTyped
در ادامه قصد داریم فایل تعاریف نوعهای کتابخانهی معروف lodash را به پروژهی جدیدی در VSCode اضافه کنیم. قدم اول، نصب خود کتابخانه است؛ از این جهت که فایلهای d.ts.، فاقد هرگونه پیاده سازی هستند.
در مطلب «چرا TypeScript» نحوهی کار با npm را جهت به روز رسانی کامپایلر TypeScript پیش فرض VSCode ملاحظه کردید. در اینجا نیز از npm برای نصب lodash استفاده میکنیم:
ابتدا خط فرمان را گشوده و سپس به پوشهی پروژهی خود وارد شوید. سپس دو دستور ذیل را صادر کنید:
npm init -f npm install lodash --save
در ادامه به مخزن کد DefinitelyTyped وارد شده و پوشهی مربوط به lodash را با جستجو پیدا کنید:
https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/lodash
در این پوشه تنها به فایل lodash.d.ts آن نیاز است. روی لینک این فایل کلیک کرده و سپس در صفحهی باز شده، بر روی دکمهی raw کلیک نمائید. این فایل نهایی را در ریشهی پروژهی جاری ذخیره کنید.
https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/lodash/lodash.d.ts
اگر به انتهای فایل lodash.d.ts دقت کنید، تعریف ambient module آن چنین شکلی را دارد و export آن lo dash است:
declare module "lodash" { export = _; }
/// <reference path="lodash.d.ts" />
import * as _ from "lodash";
let snakeCaseTitle = _.snakeCase("test this"); console.log(snakeCaseTitle);
برای گرفتن خروجی از این مثال همانند قبل، ابتدا Ctrl+Shift+P را فشرده و سپس انتخاب tasks:Run build task< و در ادامه فشردن F5 برای اجرا برنامه، نیاز است صورت گیرند:
مدیریت فایلهای تعاریف نوعها با استفاده از tsd
tsd یک برنامهی خط فرمان است که کار یافتن و دریافت فایلهای d.ts. را ساده میکند. این برنامه منحصرا با مخزن کد DefinitelyTyped کار میکند و پس از دریافت هر فایل d.ts.، ارجاعی به آنرا در فایل tsd.json در ریشهی پروژه ذخیره میکند. همچنین یک تک فایل tsd.d.ts حاوی تعاریف Triple-Slash Directiveها را نیز تولید میکند که در ادامه میتوان تنها این فایل را به فایلهای مدنظر الحاق کرد.
البته باید دقت داشت که این برنامه در ابتدای سال 2016 منسوخ شده اعلام گردید و با برنامهی typings جایگزین شدهاست؛ هرچند هنوز هم مفید است و قابل استفاده.
روش دریافت tsd را در سایت definitelytyped.org میتوانید مشاهده کنید:
http://definitelytyped.org/tsd
نصب آن نیز به صورت یک بستهی npm است:
npm install tsd -g
https://github.com/Definitelytyped/tsd#readme
برای مثال برای نصب فایل تعاریف نوعهای lodash، ابتدا به پوشهی پروژه از طریق خط فرمان وارد شده و سپس دستور ذیل را صادر کنید:
D:\Prog\1395\VSCodeTypeScript>tsd install lodash --save
[ERR!] Error: connect ECONNREFUSED 10.10.34.36:443
اگر موفق به اجرای این دستور شدید، پوشهی جدید typings در ریشهی پروژه ایجاد خواهد شد. داخل آن فایل tsd.d.ts را نیز میتوان مشاهده کرد که حاوی تعاریف فایلهای نوعهای دریافت شدهاست. از این پس در ابتدای فایلهای ts، بجای تعریف جداگانهی این فایلها، تنها میتوان نوشت:
/// <reference path="./typings/tsd.d.ts" />
مدیریت فایلهای تعاریف نوعها با استفاده از typings
برنامهی typings نیز بسیار شبیه به برنامهی tsd است؛ با این تفاوت که منابع آن منحصر به مخزن کد definitelytyped نیست.
مخزن کد این برنامه در گیتهاب قرار دارد: https://github.com/typings/typings
و نصب آن با استفاده از دستور ذیل است:
npm install typings --global
typings install lodash --ambient --save
typings ERR! caused by Unable to connect to "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/299b5caa22876ef27dc8e9a5b7fd7bf93457b6f4/lodash/lodash-3.10.d.ts" typings ERR! caused by connect ECONNREFUSED 10.10.34.36:443
/// <reference path="./typings/main.d.ts" />