مزیت مدیریت وابستگیها
public class ShoppingCartController : Controller { public ActionResult GetCart() { //shopping cart service as a concrete dependency ShoppingCartService shoppingCartService = new ShoppingCartService(); ShoppingCart cart = shoppingCartService.GetContents(); return View("Cart", cart); } public ActionResult AddItemToCart(int itemId, int quantity) { //shopping cart service as a concrete dependency ShoppingCartService shoppingCartService = new ShoppingCartService(); ShoppingCart cart = shoppingCartService.AddItemToCart(itemId, quantity); return View("Cart", cart); } }
public class ShoppingCartController : Controller { private ShoppingCartService _shoppingCartService; public ShoppingCartController() { _shoppingCartService = new ShoppingCartService(); } public ActionResult GetCart() { //now using the shared instance of the shoppingCartService dependency ShoppingCart cart = _shoppingCartService.GetContents(); return View("Cart", cart); } public ActionResult AddItemToCart(int itemId, int quantity) { //now using the shared instance of the shoppingCartService dependency ShoppingCart cart = _shoppingCartService.AddItemToCart(itemId, quantity); return View("Cart", cart); } }
معرفی سرویس IActionDescriptorCollectionProvider در ASP.NET Core
فرض کنید میخواهیم لیست تمام کنترلرهای یک برنامهی ASP.NET Core را با ساختار ذیل تهیه کنیم که شامل نام کنترلر، نام اکشن متد و نام ناحیهی متناظر با آن (در صورت تنظیم) میباشد:
public class MvcActionViewModel { public string ControllerName { get; set; } public string ActionName { get; set; } public string AreaName { get; set; } }
public interface IMvcActionsDiscoveryService { ICollection<MvcActionViewModel> MvcActions { get; } } public class MvcActionsDiscoveryService : IMvcActionsDiscoveryService { public MvcActionsDiscoveryService(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider) { var actionDescriptors = actionDescriptorCollectionProvider.ActionDescriptors.Items; foreach (var actionDescriptor in actionDescriptors) { var descriptor = actionDescriptor as ControllerActionDescriptor; if (descriptor == null) { continue; } var controllerTypeInfo = descriptor.ControllerTypeInfo; var actionMethodInfo = descriptor.MethodInfo; MvcActions.Add(new MvcActionViewModel { ControllerName = descriptor.ControllerName, ActionName = descriptor.ActionName, AreaName = controllerTypeInfo.GetCustomAttribute<AreaAttribute>()?.RouteValue }); } } public ICollection<MvcActionViewModel> MvcActions { get; } = new HashSet<MvcActionViewModel>(); }
- در کلاس آغازین برنامه نیازی به ثبت سرویس IActionDescriptorCollectionProvider نیست و اینکار پیشتر توسط خود ASP.NET Core انجام شدهاست.
- این provider حاوی لیست اطلاعات تمام اکشن متدهای ثبت شدهی توسط ASP.NET Core است. در اینجا تنها کافی است حلقهای را بر روی لیست آیتمهای آن تشکیل داده و سپس مقادیر ControllerName و یا ActionName را بدست بیاوریم.
- اگر نیاز به اطلاعات بیشتری از کنترلر و اکشن متد جاری در حال بررسی توسط حلقهی تهیه شده بود، میتوان از ControllerTypeInfo و MethodInfo آن استفاده کرد. این TypeInfoها با استفاده از Reflection، امکان دسترسی به اطلاعاتی مانند ویژگیهای اعمال شدهی به کنترلر یا اکشنی خاص را میسر میکنند. برای مثال در اینجا توسط اطلاعات نوع یک کنترلر در حال بررسی توانستهایم متد GetCustomAttribute را فراخوانی کرده و سپس بررسی کنیم که آیا دارای ویژگی جدید Area هست یا خیر؟ و اگر بله، مقدار RouteValue آن را که در حقیقت مقدار یا نام Area آن کنترلر است، بازگشت میدهیم.
نحوهی استفاده از سرویس IMvcActionsDiscoveryService تهیه شده
اگر دقت کرده باشید اطلاعات لیست MvcActions، در سازندهی این کلاس مقدار دهی شدهاند. علت اینجا است که اگر این کلاس را به صورت singleton ثبت کنیم، تنها یکبار در طول عمر برنامه و در همان آغاز کار، این لیست پر شده و سپس کش خواهد شد. بنابراین دسترسیهای بعدی به MvcActions، شامل فراخوانی سازندهی این کلاس نخواهند بود:
public static class MvcActionsDiscoveryServiceExtensions { public static IServiceCollection AddMvcActionsDiscoveryService(this IServiceCollection services) { services.AddSingleton<IMvcActionsDiscoveryService, MvcActionsDiscoveryService>(); return services; } }
public void ConfigureServices(IServiceCollection services) { services.AddMvcActionsDiscoveryService(); }
همانطور که قبلا ذکر کردیم یک اسمبلی شامل کدهای IL و متادیتا هاست. IL یک زبان غیر وابسته به معماری سی پی یو است که مایکروسافت پس از مشاورههای زیاد از طریق نویسندگان کامپایلر و زبانهای آکادمی و تجاری آن را ایجاد کرده است. IL یک زبان کاملا سطح بالا نسبت به زبانهای ماشین سی پی یو است. IL میتواند به انواع اشیاء دسترسی داشته و آنها را دستکاری نماید و شامل دستورالعمل هایی برای ایجاد و آماده سازی اشیاست. صدا زدن متدهای مجازی بر روی اشیاء و دستکاری المانهای یک آرایه به صورت مستقیم، از جمله کارهایی است که انجام میدهد. همچنین شامل دستوراتی برای صدور و کنترل استثناء هاست . شما میتوانید IL را به عنوان یک زبان ماشین شیء گرایی تصور کنید.
معمولا برنامه نویسها در یک زبان سطح بالا چون سی شارپ به نوشتن میپردازند و کمپایلر کد IL آنها را ایجاد میکند و این کد IL میتواند به صورت اسمبلی نوشته شود. به همین علت مایکروسافت ابزار ILASM.exe و برای دی اسمبل کردن ILDASM.exe را ارائه کرده است.
این را همیشه به یاد داشته باشید که زبانهای سطح بالا تنها به زیر قسمتی از قابلیتهای CLR دسترسی دارند؛ ولی در IL Assembly توسعه دهنده به تمامی قابلیتهای CLR دسترسی دارد. این انتخاب شما در زبان برنامه نویسی است که میخواهید تا چه حد به قابلیتهای CLR دسترسی داشته باشید. البته یکپارچه بودن محیط در CLR باعث پیوند خوردن کدها به یکدیگر میشود. برای مثال میتوانید قسمتی از یک پروژه که کار خواندن و نوشتن عملیات را به عهده دارد بر دوش #C قرار دهید و محاسبات امور مالی را به APL بسپارید.
برای اجرا شدن کدهای IL، ابتدا CLR باید بر اساس معماری سی پی یو کد ماشین را به دست آورد که وظیفهی تبدیل آن بر عهده Jit یا Just in Time است . شکل زیر نحوه انجام این کار را انجام میدهد:
موقعیکه کنسول اولین متدش مثلا WriteLine را فراخوانی میکند، کامپایلر جیت صدا زده میشود. تابع کامپایلر جیت مسئولیت تبدیل کدهای IL را به کدهای بومی آن پلتفرم، به عهده دارد. از آنجایی که عمل کامپایل در همان لحظه یا در جا اتفاق میافتد (Just in time)، عموم این کامپایر را Jitter یا Jit Compiler مینامند.
موقعیکه صدا زدن آن متد به سمت jit انجام شد، جیت متوجه میشود که چه متدی درخواست شده و نحوهی تعریف آن متد به چه صورتی است. جیت هم در متادیتای یک اسمبلی به جست و جو پرداخته و کدهای IL آن متد را دریافت میکند. سپس کدها را تایید و عملیات کامپایل به سمت کدهای بومی را آغاز میکند. در ادامه این کدهای بومی را در قطعهای از حافظه ذخیره میکند. سپس جیت به جایی بر میگردد که CLR از آنجا جیت را وارد کار کرده؛ یعنی مدخل ورودی متد writeline و سپس آدرس آن قطعه حافظه را که شامل کد بومی است، بجای آن قطعه که به کد IL اشاره میکند، جابجا میکند و کد بومی شده را اجرا و نهایتا به محدودهی main باز میگردد.
در شکل زیر مجددا همان متد صدا زده شده است. ولی از آنجا که قبلا کد کامپایل شده را به دست آوردیم، از همان استفاده میکنیم و دیگر تابع جیت را صدا نمیزنیم.
توجه داشته باشید، در متدهای چند ریختی که شکلهای متفاوتی از پارامترها را دارند، هر کدام کمپایل جداگانهای صورت میگیرد. یعنی برای متدهای زیر جیت برای هر کدام جداگانه فراخوانی میشود.
WriteLine("Hello"); WriteLine();
در مقالهی آینده عملکرد جیت را بیشتر مورد بررسی قرار میدهیم و در مورد دیباگ کردن و به نظرم برتری CLR را نسبت به زبانهای مدیریت نشده، بررسی میکنیم.
ویدیوهای آموزشی QT
در کمال ناباوری، یک مجموعهی آموزشی 88 قسمتی، از فریم ورکی به نام QT را در یوتیوب پیدا کردم [+] که نتیجهاش دریافت و آپلود مجدد آنها جهت سهولت دریافت بود. حجم کل آنها 2.14 گیگابایت است که در 13 قسمت جهت علاقمندان آپلود شده است (مجوز ویدیوهای یوتیوب، Creative Commons است و امکان توزیع مجدد آنها وجود دارد: [+] و [+]). برای باز کردن مجموعه فایلهای دریافت شده از برنامه 7-Zip میشود استفاده کرد.
وبلاگها و سایتهای ایرانی
Visual Studio
امنیت
- رمزنگاری کوانتمی و شبکهای رمزنگاری شده با این روش
ASP. Net
طراحی وب
اسکیوال سرور
به روز رسانیها
ابزارها
- نگارش جدید برنامه RSS Bandit . (برنامهای سورس باز نوشته شده با سی شارپ)
- Visual Round Trip Analyzer (استفاده از NetMon API)
سیشارپ
- Interactive GUI Shell از توسعه دهندگان تیم Mono
عمومی دات نت
- آشنایی با کلاس CommaDelimitedStringCollection در دات نت فریم ورک
- مونو و دات نت گزارشی از PDC2008
CPP
دلفی
- CompilerPlugin برای دلفی 2009. (توسط آن میتوان پروژههای دلفی 2007 را با دلفی 2009 نیز کامپایل کرد)
- نسخه جدید CnPack منتشر شد. (با پشتیبانی دلفی 5 تا 2009)
ویندوز
- آنالیز crash dumps ویندوز . (آیا میدانید صفحات آبی ویندوز را چگونه باید تفسیر کرد؟)
Office
- آشنایی با یک سری از اصطلاحات outlook 2007 برای برنامه نویسها. (اگر قصد داشته باشید یک add-in را برای outlook 2007 با استفاده از امکانات VSTO توسعه دهید، آشنایی با این اصطلاحات بسیار ضروری خواهد بود)
متفرقه
احتمالا جستجو در وب سایت مورد نظر در دو صفحه مجزا طراحی شده :
1.جستجویهای طبقه بندی شده بر اساس اطلاعات استخراجی شان از ابزارها ارزیابی وب سایتها مانند Google analytics (راهنما در کامنت قبل)
2. جستجوی لحظه ای در محتوای سایت
این نکته در متا تگهای ایجاد شده نیز قابل مشاهده است :
تعداد نتایج یافت شده متفاوت این دو صفحه (با یک عنوان جستجو) نشان از تایید مطلب دارد.
در نگارش 2
public virtual DateTime? LockoutEndDateUtc { get; set; }
public virtual DateTimeOffset? LockoutEnd { get; set; }
مشکل ساختار DateTime چیست؟
تمام کسانیکه مدتی با NET Framework. کار کردهاند، قطعا از ساختار DateTime برای ذخیره سازی اطلاعاتی زمانی محلی استفاده کردهاند. اما مشکل DateTime چیست؟
فرض کنید در حال استفادهی از یک وب سرویس قرار گرفتهی در یک منطقهی زمانی غربی هستید و این وب سرویس تاریخ تولد افراد را با یک چنین فرمتی ارائه میدهد:
2012-03-01 00:00:00-05:00
var dateString = "2012-03-01 00:00:00-05:00"; var birthDay = DateTime.Parse(dateString);
2012-02-29 11:00:00 PM
چگونه میتوان offset را در تاریخ ذکر کرد، اما از تبدیل آن به زمان محلی جلوگیری کرد؟ این مورد جاییاست که ساختار DateTimeOffset بکار خواهد آمد.
DateTimeOffset و ذخیرهی DateTime به همراه Offset
ساختار کلی DateTimeOffset بسیار واضح بوده و تشکیل شدهاست از Date + Time + Offset. اهمیت آن نیز به ذخیره سازی اطلاعات منطقهی زمانی، در قسمت Offset ساختار ارائه شده بر میگردد. ساختار DateTimeOffset در بسیاری از موارد با DateTime متداول یکسان است و تفاوتهای آن شامل خواص اضافی ذیل هستند:
- DateTime: قسمت DateTime مقدار را بدون توجه به offset باز میگرداند (به زمان محلی تبدیل نخواهد شد).
- LocalDateTime: قسمت DateTime را با توجه به منطقه زمانی سروری که برنامه بر روی آن اجرا میشود، بر میگرداند.
- Offset: فاصلهی زمانی با UTC را بیان میکند. یک TimeSpan است که فاصلهی با UTC را بیان میکند.
- UtcDateTime: قسمت DateTime را با توجه به UTC time ارائه میکند.
در این ساختار خواص Now و UtcNow نیز یک DateTimeOffset را باز میگردانند.
چه زمانی از DateTime و چه زمانی از DateTimeOffset استفاده کنیم؟
اگر هدف شما ذخیره سازی اطلاعات زمانی محلی (جایی که سرور برنامه قرار دارد) است، از DateTime استفاده کنید. اما اگر میخواهید مقادیر زمانی را در مناطق زمانی دیگری نیز مورد استفاده قرار دهید و علاقمندید که قسمت TimeZone این اطلاعات نیز حفظ شود، از DateTimeOffset استفاده نمائید.
در این حالت روش پردازش صحیح مثال ابتدای بحث به صورت ذیل خواهد بود:
string birthDay = "2012-03-01 00:00:00-05:00"; var dtOffset = DateTimeOffset.Parse(birthDay);
var theDay = dtOffset.Date;
SQL Server و پشتیبانی از DateTimeOffset
ساختار دادهای datetime در SQL Server نیز اطلاعات منطقهی زمانی را ذخیره نمیکند و درصورت بازیابی آن در برنامه، این زمان، به زمان محلی تبدیل خواهد شد. برای رفع این مشکل، از زمان ارائهی SQL Server 2008، ساختار DateTimeOffset نیز به نوعهای دادهآی SQL Server اضافه شدهاست:
این ساختار، اطلاعات +00:00 timezone را نیز ذخیره میکند.
مشکلات نوع datetime در بانکهای اطلاعاتی برای ذخیره سازی اطلاعات UTC در آنها
یکی از روشهای توصیه شدهی جهت ذخیره سازی اطلاعات زمانی در بانکهای اطلاعاتی، استفادهی از DateTime.UtcNow است. اما زمانیکه از DateTime.UtcNow برای ذخیره سازی اطلاعاتی زمانی استفاده میکنیم، به معنای دریافت زمان محلی بر اساس و نسبت به UTC است. در این حالت هنگامیکه آنرا از یک فیلد datetime بانک اطلاعاتی بازیابی میکنیم، از نوع Unspecified خواهد بود (DateTimeKind.Unspecified) و به صورت خودکار به DateTimeKind.Local ترجمه میشود. یعنی مقدار آن مجددا به زمان محلی شیفت پیدا خواهد کرد چون نوع datetime بانک اطلاعاتی درکی از DateTimeKind و منطقهی زمانی ندارد.
به همین جهت روش بازیابی صحیح این زمان UTC، نیاز به قید صریح DateTimeKind.Utc را خواهد داشت:
public static class SqlDataReaderExtensions { public static DateTime GetDateTimeUtc(this SqlDataReader reader, string name) { int fieldOrdinal = reader.GetOrdinal(name); DateTime unspecified = reader.GetDateTime(fieldOrdinal); return DateTime.SpecifyKind(unspecified, DateTimeKind.Utc); } }
خلاصهی بحث
اگر برنامهی وب شما امروز در یک سرور در اروپا هاست میشود و سال بعد در یک سرور کانادایی، استفادهی DateTime.UtcNow کمک زیادی به برنامه نکرده و خروجی SQL Server در این حالت DateTimeKind.Unspecified است و این زمان مجددا بر اساس محل سرور جدید و تنظیمات منطقهی زمانی آن، به حالت DateTimeKind.Local شیفت داده میشود که الزاما خروجی صحیحی را به همراه نخواهد داشت و یا اگر قرار است از وب سرویس شما در مناطق زمانی مختلفی استفاده کنند نیز DateTime.UtcNow انتخاب مناسبی نیست. جهت درج فاصلهی صحیح با UTC و ذخیره سازی آن در بانک اطلاعاتی، روش توصیه شده، استفاده از نوع DateTimeOffset است و در این حالت دیگر SQL Server اطلاعات را با فرمت زمانی Unspecified بازگشت نمیدهد و در سمت کلاینت نیازی به تبدیلات خاصی نخواهد بود.
تلاشهای بسیاری توسط توسعه گران صورت پذیرفته است تا فرایند ایجاد وب سرویس WCF در بستر HTTP آسان شود. امروزه وب سرویس هایی که از قالب REST استفاده میکنند مطرح هستند.
ASP.NET Web API از مفاهیم موجود در ASP.NET MVC مانند Controllerها استفاده میکند و بر مبنای آنها ساخته شده است. بدین شکل، توسعه گر میتواند با دانش موجود خود به سادگی وب سرویسهای مورد نظر را ایجاد کند. Web API، پروتوکل SOAP را به کتابهای تاریخی! سپرده است تا از آن به عنوان روشی برای تعامل بین سیستمها یاد شود. امروزه به دلیل فراگیری پروتوکل HTTP، بیشتر محیطهای برنامه نویسی و سیستم ها، از مبانی اولیهی پروتوکل HTTP مانند اَفعال آن پشتیبانی میکنند.
حال قصد داریم تا وب سرویسی را که در قسمت اول با WCF ایجاد کردیم، این بار با استفاده از Web API ایجاد کنیم. به تفاوت این دو دقت کنید.
using System.Web.Http; namespace MvcApplication1.Controllers { public class ValuesController : ApiController { // GET api/values/5 public string Get(int id) { return string.Format("You entered: {0}", id); } } }
نحوهی برگشت یک مقدار از متدها در Web API، مانند WCF است. میتوانید خروجی متد Get را با اجرای پروژهی قبل در Visual Studio و تست آن با یک مرورگر ملاحظه کنید. دقت داشته باشید که یکی از اصولی که Web API به آن معتقد است این است که وب سرویسها میتوانند ساده باشند. در Web API، تست و دیباگ وب سرویسها بسیار راحت است. با مرورگر Internet Explorer به آدرس http://localhost:{port}/api/values/3 بروید. پیش از آن، برنامهی Fiddler را اجرا کنید. شکل ذیل، نتیجه را نشان میدهد.
در اینجا نتیجه، عبارت "You entered: 3" است که به صورت یک متن ساده برگشت داده شده است.
ایجاد یک پروژهی Web API
در Visual Studio، مسیر ذیل را طی کنید.
File> New> Project> Installed Templates> Visual C#> Web> ASP.NET MVC 4 Web Application
نام پروژه را HelloWebAPI بگذارید و بر روی دکمهی OK کلیک کنید (شکل ذیل)در فرمی که باز میشود، گزینهی Web API را انتخاب و بر روی دکمهی OK کلیک کنید (شکل ذیل). البته دقت داشته باشید که ما همیشه مجبور به استفاده از قالب Web API برای ایجاد پروژههای خود نیستیم. میتوان در هر نوع پروژه ای از Web API استفاده کرد.
اضافه کردن مدل
مدل، شی ای است که نمایانگر دادهها در برنامه است. Web API میتواند به طور خودکار، مدل را به فرمت JSON، XML یا فرمت دلخواهی که خود میتوانید برای آن ایجاد کنید تبدیل و سپس دادههای تبدیل شده را در بدنهی پاسخ HTTP به Client ارسال کند. تا زمانی که Client بتواند فرمت دریافتی را بخواند، میتواند از آن استفاده کند. بیشتر Clientها میتوانند فرمت JSON یا XML را پردازش کنند. به علاوه، Client میتواند نوع فرمت درخواستی از Server را با تنظیم مقدار هدر Accept در درخواست ارسالی تعیین کند. اجازه بدهید کار خود را با ایجاد یک مدل ساده که نمایانگر یک محصول است آغاز کنیم.
بر روی پوشهی Models کلیک راست کرده و از منوی Add، گزینهی Class را انتخاب کنید.
نام کلاس را Product گذاشته و کدهای ذیل را در آن بنویسید.
namespace HelloWebAPI.Models { public class Product { public int Id { get; set; } public string Name { get; set; } public string Category { get; set; } public decimal Price { get; set; } } }
مدل ما، چهار Property دارد که در کدهای قبل ملاحظه میکنید.
اضافه کردن Controller
در پروژه ای که با استفاده از قالب پیش فرض Web API ایجاد میشود، دو Controller نیز به طور خودکار در پروژهی Controller قرار میگیرند:
- HomeController: یک Controller معمول ASP.NET MVC است که ارتباطی با Web API ندارد.
- ValuesController: یک Controller مختص Web API است که به عنوان یک مثال در پروژه قرار داده میشود.
توجه: Controllerها در Web API بسیار شبیه به Controllerها در ASP.NET MVC هستند، با این تفاوت که به جای کلاس Controller، از کلاس ApiController ارث میبرند و بزرگترین تفاوتی که در نگاه اول در متدهای این نوع کلاسها به چشم میخورد این است که به جای برگشت Viewها، داده برگشت میدهند.
کلاس ValuesController را حذف و یک Controller به پروژه اضافه کنید. بدین منظور، بر روی پوشهی Controllers، کلیک راست کرده و از منوی Add، گزینهی Controller را انتخاب کنید.
توجه: در ASP.NET MVC 4 میتوانید بر روی هر پوشهی دلخواه در پروژه کلیک راست کرده و از منوی Add، گزینهی Controller را انتخاب کنید. پیشتر فقط با کلیک راست بر روی پوشهی Controller، این گزینه در دسترس بود. حال میتوان کلاسهای مرتبط با Controllerهای معمول را در یک پوشه و Controllerهای مربوط به قابلیت Web API را در پوشهی دیگری قرار داد.
نام Controller را ProductsController بگذارید، از قسمت Template، گزینهی Empty API Controller را انتخاب و بر روی دکمهی OK کلیک کنید (شکل ذیل).
فایلی با نام ProductsController.cs در پوشهی Controllers قرار میگیرد. آن را باز کنید و کدهای ذیل را در آن قرار دهید.
namespace HelloWebAPI.Controllers { using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using HelloWebAPI.Models; public class ProductsController : ApiController { Product[] products = new Product[] { new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1.39M }, new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } }; public IEnumerable<Product> GetAllProducts() { return products; } public Product GetProductById(int id) { var product = products.FirstOrDefault((p) => p.Id == id); if (product == null) { var resp = new HttpResponseMessage(HttpStatusCode.NotFound); throw new HttpResponseException(resp); } return product; } public IEnumerable<Product> GetProductsByCategory(string category) { return products.Where( (p) => string.Equals(p.Category, category, StringComparison.OrdinalIgnoreCase)); } } }
برای ساده نگهداشتن مثال، لیستی از محصولات را در یک آرایه قرار داده ایم اما واضح است که در یک پروژهی واقعی، این لیست از پایگاه داده بازیابی میشود. در مورد کلاسهای HttpResponseMessage و HttpResponseException بعداً توضیح میدهیم.
در کدهای Controller قبل، سه متد تعریف شده اند:
- متد GetAllProducts که کل محصولات را در قالب نوع <IEnumerable<Product برگشت میدهد.
- متد GetProductById که یک محصول را با استفاده از مشخصهی آن (خصیصهی Id) برگشت میدهد.
- متد GetProductsByCategory که تمامی محصولات موجود در یک دستهی خاص را برگشت میدهد.
تمام شد! حال شما یک وب سرویس با استفاده از Web API ایجاد کرده اید. هر یک از متدهای قبل در Controller، به یک آدرس به شرح ذیل تناظر دارند.
GetAllProducts به api/products/
GetProductById به api/products/id/
GetProductsByCategory به api/products/?category=category/
در آدرسهای قبل، id و category، مقادیری هستند که همراه با آدرس وارد میشوند و در پارامترهای متناظر خود در متدهای مربوطه قرار میگیرند. یک Client میتواند هر یک از متدها را با ارسال یک درخواست از نوع GET اجرا کند.
در قسمت بعد، کار خود را با تست پروژه و نحوهی تعامل jQuery با آن ادامه میدهیم.
Gulp #5
در مقالات قبلی به طور کامل با گالپ آشنا شدیم و گفتیم که میتواند ما را در بهینه سازی ورک فلویمان کمک کند. در این قسمت یاد خواهیم گرفت که چگونه تجربهی کاربری بهتری را از سرعت بارگذاری سایتمان ایجاد کنیم.
افزایش کارآیی Performance وب با گالپ
۱− کنار هم قرار دادن و فشرده کردن فایلهای جاوا اسکریپت
npm install --save-dev gulp-uglify gulp-concat
// first load all required js files // concat them in to script.min.js // and minify it. gulp.task('js', function() { return gulp.src([ config.bowerDir + '/jquery/dist/jquery.min.js', // این فایل وابستگی فایلهای زیر است config.bowerDir + '/materialize/dist/js/materialize.min.js', './resources/js/app.js' ]) .pipe(concat('script.min.js')) .pipe(uglify()) .pipe(size()) .pipe(gulp.dest('./public/js')); });
فشرده کردن جاوا اسکریپت، حجم فایلها را ۳۰ تا ۹۰ درصد کاهش میدهد.
۲− حذف سکلتورهای بدون استفاده css
npm install gulp-uncss --save-dev
gulp.task('css', function() { return sass(config.sassPath + '/style.scss', { style: 'compressed', loadPath: [ './resources/sass', config.bowerDir + '/materialize/sass' ] }) .on('error', util.log) .pipe(size()) .pipe(uncss({ html: ['./index.html', './posts.html'] })) .pipe(gulp.dest('./public/css')) .pipe(size()) .pipe(connect.reload()); });
gulp.task('css', function() { return sass(config.sassPath + '/style.scss', { style: 'compressed', loadPath: [ './resources/sass', config.bowerDir + '/materialize/sass' ] }) .on('error', util.log) .pipe(size()) .pipe(uncss({ html: ['./index.html', './posts.html'], timeout : 2000, // wait for load js files ignore: [ ".waves-ripple ", ".drag-target", "#sidenav-overlay", ".waves-effect", ".waves-effect .waves-ripple", ".waves-effect.waves-pinck .waves-ripple", ".waves-block.waves-light" ] })) .pipe(minifyCss()) .pipe(size()) .pipe(gulp.dest('./public/css')) .pipe(connect.reload()); });