پیرو مطلب قلمهایی حاوی آیکون که خصوصا در برنامههای مترو بیشتر مرسوم شدهاند، شاید بد نباشد کار برنامه Character Map ویندوز را با WPF شبیه سازی کنیم.
ابتدا Model و ViewModel این برنامه را درنظر بگیرید:
namespace CrMap.Models { public class Symbol { public char Character { set; get; } public string CharacterCode { set; get; } } }
using System; using System.Collections.Generic; using System.Windows.Media; using CrMap.Models; namespace CrMap.ViewModels { public class CrMapViewModel { public IList<Symbol> Symbols { set; get; } public int GridRows { set; get; } public int GridCols { set; get; } public CrMapViewModel() { fillDataSource(); } private void fillDataSource() { Symbols = new List<Symbol>(); GridCols = 15; var fontFamily = new FontFamily(new Uri("pack://application:,,,/"), "/Fonts/#whhglyphs"); GlyphTypeface glyph = null; foreach (var typeface in fontFamily.GetTypefaces()) { if (typeface.TryGetGlyphTypeface(out glyph) && (glyph != null)) break; } if (glyph == null) throw new InvalidOperationException("Couldn't find a GlyphTypeface."); GridRows = (glyph.CharacterToGlyphMap.Count / GridCols) + 1; foreach (var item in glyph.CharacterToGlyphMap) { var index = item.Key; Symbols.Add(new Symbol { Character = Convert.ToChar(index), CharacterCode = string.Format("&#x{0:X}", index) }); } } } }
یک سری قابلیت جالب در WPF برای استخراج اطلاعات قلمها وجود دارند که در فضای نام System.Windows.Media اسمبلی PresentationCore.dll قرار گرفتهاند. برای نمونه پس از وهله سازی FontFamily بر اساس یک قلم مدفون شده در برنامه، امکان استخراج تعداد گلیفهای موجود در این قلم وجود دارد که نحوه انجام آنرا در متد fillDataSource ملاحظه میکنید.
این اطلاعات استخراج شده و لیست Symbols برنامه را تشکیل میدهند. در نهایت برای نمایش این اطلاعات، از ترکیب ItemsControl و UniformGrid استفاده خواهیم کرد:
<Window x:Class="CrMap.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:CrMap.ViewModels" Title="MainWindow" WindowStartupLocation="CenterScreen" WindowState="Maximized" Height="350" Width="525"> <Window.Resources> <vm:CrMapViewModel x:Key="vmCrMapViewModel" /> </Window.Resources> <ScrollViewer VerticalScrollBarVisibility="Visible"> <ItemsControl DataContext="{StaticResource vmCrMapViewModel}" ItemsSource="{Binding Symbols}" Name="MainItemsControl" VerticalAlignment="Top" HorizontalAlignment="Center" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="4"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <UniformGrid HorizontalAlignment="Center" VerticalAlignment="Center" Columns="{Binding GridCols}" Rows="{Binding GridRows}"> </UniformGrid> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <ContentControl> <Border BorderBrush="SlateGray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderThickness="1" CornerRadius="3" Margin="3"> <StackPanel Margin="3" Orientation="Vertical"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Fonts/#whhglyphs" Foreground="DarkRed" FontSize="17" Text="{Binding Character}" /> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding CharacterCode}" /> </StackPanel> </Border> </ContentControl> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </ScrollViewer> </Window>
دریافت مثال این مطلب
CrMap.zip
در یک طبقه بندی کلی، عملگرهای پرس و جو بر اساس ورودی و خروجی آنها به سه دسته تقسیم میشوند:
1- نتیجهی توالی ورودی، بصورت یک توالی، به خروجی ارسال میشود.
2- نتیجهی توالی ورودی، بصورت یک عنصر یکتا و واحد به خروجی ارسال میشود.
3- اثری از ورودی در توالی خروجی وجود ندارد (این عملگرها عناصر خودشان را تولید میکنند).
دستهی آخر شاید کمی عجیب به نطر برسد. این عملگرها هیچ توالی ورودی را دریافت نمیکنند. مثلا میتوان از طریق این عملگرها، یک توالی از اعداد صحیح را تولید کرد.
تقسیم بندی عملگرهای پرس و جو بر اساس عملکرد به صورت زیر میباشد :
- محدود کننده (Restriction)
where
- بازتابی (Projection)
Select,SelectMany
- جداکننده (Partitioning)
Take,Skip,TakeWhile,SkipWhile
- مرتب سازی (Ordering)
OrderBy,OrderByDescending,ThenBy,ThenByDescending,Reverse
- گروه بندی (Grouping)
GroupBy
- مجموعه (Set)
Concat,Union,Intersect,Except
- تبدیل (Conversion)
ToArray,ToList,ToDictionary,ToLookup,OfType,Cast
- عنصر(Element)
First,FirstOrDefault,Last,LastOrDefalt,Single,SingleOrDefault
- عنصر در (ElementAt)
ElementAtOrDefault,DefaultIfEmpty
- تولید (Generation)
Empty,Range,Report
- کمی (Quantifier)
Any,All,Contains,SequenceEqual
- مجموعه (Aggregate)
Count,LongCount,Sum,Min,Max,Average,Aggregate
- اتصال (Join)
Join,GroupJoin,Zip
در این مطلب عملگرهای محدود کننده، بازتابی و جداکننده، بررسی خواهند شد. بعد از معرفی هر عملگر، معادل عبارتهای پرس و جوی آنها نیز معرفی خواهند شد.
این عملگر، عناصری را به خروجی ارسال میکند که با گزارهی (Predicate) تعریف شده مطابقت داشته باشند.
نکته : گزاره (Predicate) تابعی است که اگر شرط آن تامین شود، مقدار true و در غیر اینصورت مقدار false را باز میگرداند.
مثال :
Ingredient[] ingredients = { new Ingredient{Name = "Sugar", Calories=500}, new Ingredient{Name = "Egg", Calories=100}, new Ingredient{Name = "Milk", Calories=150}, new Ingredient{Name = "Flour", Calories=50}, new Ingredient{Name = "Butter", Calories=200}, }; IEnumerable<Ingredient> query = ingredients.Where(x => x.Calories >= 200); foreach (var ingredient in query) { Console.WriteLine(ingredient.Name); }
خروجی کد بالا:
Sugar Butter
IEnumerable<Ingredient> query = ingredients.Where((ingredient, index) => ingredient.Name == "Sugar" || index == 4);
پیاده سازی توسط عبارتهای پرس و جو
در روش عبارتهای پرس و جو، کلمهی کلیدی where بههمراه یک عبارت منطقی در پرس و جو ظاهر میشود:
IEnumerable<Ingredient> gueryExpression = from i in ingredients where i.Calories >= 200 select i;
عملگرهای بازتاب (Projection Operators)
عملگرهای پرس و جوی بازتابی، یک توالی ورودی را دریافت و با تبدیل عناصر آنها، یک توالی خروجی را تولید میکنند.
Select
عملگر پرس و جوی select هر عنصر توالی ورودی را به یک عنصر در توالی خروجی تبدیل میکند. تعداد عناصر ورودی و خروجی در این حالت یکسان میباشند.
پرس و جوی زیر عناصر توالی ورودی Ingredient را به عناصر رشتهای در توالی خروجی بازتاب میکند. عبارت Lambda تعریف شده، نحوهی بازتاب عناصر را مشخص میکند (هر عنصر ingredient به یک عنصر رشتهای بازتاب میشود):
IEnumerable<string> query = ingredients.Select(x => x.Name);
IEnumerable<int> query = ingredients.Select(x => x.Name.Length);
در عملیات بازتاب میتوان یک شیء جدید را در توالی خروجی ایجاد کرد. در کد زیر عناصر Ingredient به یک عنصر جدید از نوع IngredientNameAndLenght بازتاب شده است.
class IngredientNameAndLength { public string Name { get; set; } public int Length { get; set; } public override string ToString() { return Name + " " + Length; } } IEnumerable<IngredientNameAndLength> query = ingredients.Select(x => new IngredientNameAndLength { Name = x.Name, Length = x.Name.Length });
var query = ingredients.Select(x => new { Name = x.Name, Length = x.Name.Length });
{ Name = Sugar, Length = 5 } { Name = Egg, Length = 3 } { Name = Milk, Length = 4 } { Name = Flour, Length = 5 } { Name = Butter, Length = 6 }
پیاده سازی توسط عبارتهای پرس و جو
کلمهی کلیدی select در عبارتهای پرس و جو، به شکل زیر استفاده میشود:
var query = from i in ingredients select new { Name=i.Name, Length=i.Name.Length };
برعکس دستور select که به ازای هر عنصر در توالی ورودی، یک عنصر را در توالی خروجی بازتاب میکرد، دستور SelectMany ممکن است تعداد عناصر کمتر و یا بیشتری را در توالی خروجی بازتاب کند (انتخاب مقادیر یک مجموعه از مجموعهی دیگر).
عبارت Lambda نوشته شده در عملگر Select، یک مقدار را باز میگرداند. اما عبارت Lambda نوشته شده در عملگر SelectMany، یک توالی فرزند (Child Sequence) را ایجاد میکند. توالی فرزند ممکن است حاوی تعداد مختلفی از عناصر به ازای هر عنصر در توالی ورودی باشد.
در مثال زیر عبارت Lambda یک توالی فرزند از کاراکترها ایجاد میکند (یک کاراکتر به ازای هر حرف از هر عنصر توالی ورودی). بهطور مثال عنصر ورودی Sugar، پس از پردازش توسط عبارت Lambda، یک توالی فرزند با 5 عنصر 's','u','g','e','r' فراهم میکند. هر رشتهی در توالی Ingredient میتواند تعداد حروف متفاوتی داشته باشد. در نتیجه عبارت Lambda، توالیهای فرزندی با طولهای مختلف ایجاد میکند.
مثال:
string[] ingredients = {"Sugar","Egg","Milk","Flour","Butter"}; IEnumerable<char> query = ingredients.SelectMany(x => x.ToCharArray()); foreach (var item in query) { Console.WriteLine(item); }
S u g a r E g g M i l k F l o u r B u t t e r
پیاده سازی توسط عبارتهای پرس و جو
در روش عبارتهای پرس و جو یک عبارت (clause) اضافی from برای تولید یک توالی فرزند به کار برده میشود. خروجی کد زیر مشابه کد قبلی است:
string[] ingredients = {"Sugar","Egg","Milk","Flour","Butter"}; IEnumerable<char> query2 = from i in ingredients from c in i.ToCharArray() select c; foreach (var item in query2) { Console.WriteLine(item); }
عملگرهای جداکننده، یک توالی ورودی را دریافت و آنها را از هم جدا میکنند.
Take
عملگر Takeیک توالی ورودی را دریافت کرده و تعداد مشخصی از توالی را باز میگرداند.
مثال: عملگر Take، سه عضو اول توالی Ingredient را باز میگرداند:
Ingredient[] ingredients = { new Ingredient{Name = "Sugar", Calories=500}, new Ingredient{Name = "Egg", Calories=100}, new Ingredient{Name = "Milk", Calories=150}, new Ingredient{Name = "Flour", Calories=50}, new Ingredient{Name = "Butter", Calories=200}, }; IEnumerable<Ingredient> query = ingredients.Take(3); foreach (var ingredient in query) { Console.WriteLine(ingredient.Name); }
Sugar Egg Milk
Ingredient[] ingredients = { new Ingredient{Name = "Sugar", Calories=500}, new Ingredient{Name = "Egg", Calories=100}, new Ingredient{Name = "Milk", Calories=150}, new Ingredient{Name = "Flour", Calories=50}, new Ingredient{Name = "Butter", Calories=200}, }; IEnumerable<Ingredient> query = ingredients.Where(x=>x.Calories>100).Take(2); foreach (var ingredient in query) { Console.WriteLine(ingredient.Name); }
Sugar Milk
پیاده سازی توسط عبارتهای پرس و جو
کلمهی کلیدی (Key word) جایگزینی برای عملگر Take وجود ندارد، ولی میتوان با ترکیب دو روش نوشتن پرس و جو، خروجی مورد نظر را تولید کرد:
IEnumerable<Ingredient> query = (from i in ingredients where i.Calories > 100 select i).Take(2); TakeWhile
کد زیر تا زمانی که خصوصیت Calorie توالی ورودی بزرگتر و مساوی 100 باشد، عناصر را جدا میکند.
Ingredient[] ingredients = { new Ingredient{Name = "Sugar", Calories=500}, new Ingredient{Name = "Egg", Calories=100}, new Ingredient{Name = "Milk", Calories=150}, new Ingredient{Name = "Flour", Calories=50}, new Ingredient{Name = "Butter", Calories=200}, }; IEnumerable<Ingredient> query = ingredients.TakeWhile(x => x.Calories >= 100); foreach (var ingredient in query) { Console.WriteLine(ingredient.Name); }
Sugar Egg Milk
پیاده سازی توسط عبارتهای پرس و جو
برای این عملگر هم کلمهی کلیدی (Key word) جایگزینی وجود ندارد و با ترکیب دو روش نوشتن پرس و جو نتیجهی دلخواه حاصل میشود.
Skip
این عملگر تعداد مشخصی از عناصر را از ابتدای توالی نادیده گرفته و باقی عناصر را باز میگرداند.
کد زیر سه عضو اول توالی را نادیده گرفته و مابقی را باز میگرداند:
Ingredient[] ingredients = { new Ingredient{Name = "Sugar", Calories=500}, new Ingredient{Name = "Egg", Calories=100}, new Ingredient{Name = "Milk", Calories=150}, new Ingredient{Name = "Flour", Calories=50}, new Ingredient{Name = "Butter", Calories=200}, }; IEnumerable<Ingredient> query = ingredients.Skip(3); foreach (var ingredient in query) { Console.WriteLine(ingredient.Name); }
Flour Butter
پیاده سازی توسط عبارتهای پرس و جو
برای این عملگر هم کلمهی کلیدی (Key word) جایگزینی وجود ندارد و با ترکیب دو روش نوشتن پرس و جو، نتیجهی دلخواه حاصل میشود.
با ترکیب عملگر Take و Skip میتوان اطلاعات را بهصورت صفحه بندی به کاربر ارائه کرد. مثال زیر این حالت را نشان میدهد.
IEnumerable<Ingredient> firstPage = ingredients.Take(2); IEnumerable<Ingredient> secondPage = ingredients.Skip(2).Take(2); IEnumerable<Ingredient> thirdPage = ingredients.Skip(4).Take(2); Console.WriteLine("First Page : "); foreach (var ingredient in firstPage) { Console.WriteLine(" - " + ingredient.Name); } Console.WriteLine("Second Page : "); foreach (var ingredient in secondPage) { Console.WriteLine(" - " + ingredient.Name); } Console.WriteLine("Third Page : "); foreach (var ingredient in thirdPage) { Console.WriteLine(" - " + ingredient.Name); }
First Page : - Sugar - Egg Second Page : - Milk - Flour Third Page : - Butter SkipWhile
مثال:
Ingredient[] ingredients = { new Ingredient{Name = "Sugar", Calories=500}, new Ingredient{Name = "Egg", Calories=100}, new Ingredient{Name = "Milk", Calories=150}, new Ingredient{Name = "Flour", Calories=50}, new Ingredient{Name = "Butter", Calories=200}, }; IEnumerable<Ingredient> query = ingredients.SkipWhile(x => x.Name != "Milk"); foreach (var ingredient in query) { Console.WriteLine(ingredient.Name); }
Milk Flour Butter
EF Code First #1
public class Blog { public int Id { set; get; } public string Title { set; get; } public string AuthorName { set; get; } public IList<Post> Posts { set; get; } }
get { return ? } set { //push calculated private field to db ? }
@using System.Text; @using System.Text.RegularExpressions; @functions { private static string RemoveAccent(string text) { /* defined in https://www.dntips.ir/post/1529*/ } public static string GenerateSlug(string title, int maxLenghtSlug = 50) { /* defined in https://www.dntips.ir/post/1529*/ } } @{ var value = GenerateSlug("this is a test"); } <a asp-controller="Home" asp-action="ViewDetails" asp-route-id="@value">View Details</a>
ASP.NET Web API فریم ورکی برای ساختن APIهای وب بر روی فریم ورک دات نت است. در این مقاله با استفاده از این فریم ورک، API وبی خواهیم ساخت که لیستی از محصولات را بر میگرداند. صفحه وب کلاینت، با استفاده از jQuery نتایج را نمایش خواهد داد.
یک پروژه Web API بسازید
در ویژوال استودیو 2013 پروژه جدیدی از نوع ASP.NET Web Application بسازید و نام آن را "ProductsApp" انتخاب کنید.
در دیالوگ New ASP.NET Project قالب Empty را انتخاب کنید و در قسمت "Add folders and core references for" گزینه Web API را انتخاب نمایید.
می توانید از قالب Web API هم استفاده کنید. این قالب با استفاده از ASP.NET MVC صفحات راهنمای API را خواهد ساخت. در این مقاله از قالب Empty استفاده میکنیم تا تمرکز اصلی، روی خود فریم ورک Web API باشد. بطور کلی برای استفاده از این فریم ورک لازم نیست با ASP.NET MVC آشنایی داشته باشید.
افزودن یک مدل
یک مدل (model) آبجکتی است که داده اپلیکیشن شما را معرفی میکند. ASP.NET Web API میتواند بصورت خودکار مدل شما را به JSON, XML و برخی فرمتهای دیگر مرتب (serialize) کند، و سپس داده مرتب شده را در بدنه پیام HTTP Response بنویسد. تا وقتی که یک کلاینت بتواند فرمت مرتب سازی دادهها را بخواند، میتواند آبجکت شما را deserialize کند. اکثر کلاینتها میتوانند XML یا JSON را تفسیر کنند. بعلاوه کلاینتها میتوانند فرمت مورد نظرشان را با تنظیم Accept header در پیام HTTP Request مشخص کنند.
بگذارید تا با ساختن مدلی ساده که یک محصول (product) را معرفی میکند شروع کنیم.
کلاس جدیدی در پوشه Models ایجاد کنید.
نام کلاس را به "Product" تغییر دهید، و خواص زیر را به آن اضافه کنید.
namespace ProductsApp.Models { public class Product { public int Id { get; set; } public string Name { get; set; } public string Category { get; set; } public decimal Price { get; set; } } }
افزودن یک کنترلر
در Web API کنترلرها آبجکت هایی هستند که درخواستهای HTTP را مدیریت کرده و آنها را به اکشن متدها نگاشت میکنند. ما کنترلری خواهیم ساخت که میتواند لیستی از محصولات، یا محصولی بخصوص را بر اساس شناسه برگرداند. اگر از ASP.NET MVC استفاده کرده اید، با کنترلرها آشنا هستید. کنترلرهای Web API مشابه کنترلرهای MVC هستند، با این تفاوت که بجای ارث بری از کلاس Controller از کلاس ApiController مشتق میشوند.
کنترلر جدیدی در پوشه Controllers ایجاد کنید.
در دیالوگ Add Scaffold گزینه Web API Controller - Empty را انتخاب کرده و روی Add کلیک کنید.
در دیالوگ Add Controller نام کنترلر را به "ProductsController" تغییر دهید و روی Add کلیک کنید.
توجه کنید که ملزم به ساختن کنترلرهای خود در پوشه Controllers نیستید، و این روش صرفا قراردادی برای مرتب نگاه داشتن ساختار پروژهها است. کنترلر ساخته شده را باز کنید و کد زیر را به آن اضافه نمایید.
using ProductsApp.Models; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Web.Http; namespace ProductsApp.Controllers { public class ProductsController : ApiController { Product[] products = new Product[] { new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, 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 IHttpActionResult GetProduct(int id) { var product = products.FirstOrDefault((p) => p.Id == id); if (product == null) { return NotFound(); } return Ok(product); } }
کنترلر ما دو متد برای دریافت محصولات تعریف میکند:
- متد GetAllProducts لیست تمام محصولات را در قالب یک <IEnumerable<Product بر میگرداند.
- متد GetProductById سعی میکند محصولی را بر اساس شناسه تعیین شده پیدا کند.
همین! حالا یک Web API ساده دارید. هر یک از متدهای این کنترلر، به یک یا چند URI پاسخ میدهند:
URI | Controller Method |
api/products/ | GetAllProducts |
api/products/id/ | GetProductById |
برای اطلاعات بیشتر درباره نحوه نگاشت درخواستهای HTTP به اکشن متدها توسط Web API به این لینک مراجعه کنید.
فراخوانی Web API با جاوا اسکریپت و jQuery
در این قسمت یک صفحه HTML خواهیم ساخت که با استفاده از AJAX متدهای Web API را فراخوانی میکند. برای ارسال درخواستهای آژاکسی و بروز رسانی صفحه بمنظور نمایش نتایج دریافتی از jQuery استفاده میکنیم.
در پنجره Solution Explorer روی نام پروژه کلیک راست کرده و گزینه Add, New Item را انتخاب کنید.
در دیالوگ Add New Item قالب HTML Page را انتخاب کنید و نام فایل را به "index.html" تغییر دهید.
حال محتوای این فایل را با لیست زیر جایگزین کنید.
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Product App</title> </head> <body> <div> <h2>All Products</h2> <ul id="products" /> </div> <div> <h2>Search by ID</h2> <input type="text" id="prodId" size="5" /> <input type="button" value="Search" onclick="find();" /> <p id="product" /> </div> <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.0.3.min.js"></script> <script> var uri = 'api/products'; $(document).ready(function () { // Send an AJAX request $.getJSON(uri) .done(function (data) { // On success, 'data' contains a list of products. $.each(data, function (key, item) { // Add a list item for the product. $('<li>', { text: formatItem(item) }).appendTo($('#products')); }); }); }); function formatItem(item) { return item.Name + ': $' + item.Price; } function find() { var id = $('#prodId').val(); $.getJSON(uri + '/' + id) .done(function (data) { $('#product').text(formatItem(data)); }) .fail(function (jqXHR, textStatus, err) { $('#product').text('Error: ' + err); }); } </script> </body> </html>
گرفتن لیستی از محصولات
برای گرفتن لیستی از محصولات، یک درخواست HTTP GET به آدرس "api/products/" ارسال کنید.
تابع getJSON یک درخواست آژاکسی ارسال میکند. پاسخ دریافتی هم آرایه ای از آبجکتهای JSON خواهد بود. تابع done در صورت موفقیت آمیز بودن درخواست، اجرا میشود. که در این صورت ما DOM را با اطلاعات محصولات بروز رسانی میکنیم.
$(document).ready(function () { // Send an AJAX request $.getJSON(apiUrl) .done(function (data) { // On success, 'data' contains a list of products. $.each(data, function (key, item) { // Add a list item for the product. $('<li>', { text: formatItem(item) }).appendTo($('#products')); }); }); });
گرفتن محصولی مشخص
برای گرفتن یک محصول توسط شناسه (ID) آن کافی است یک درخواست HTTP GET به آدرس "api/products/id/" ارسال کنید.
function find() { var id = $('#prodId').val(); $.getJSON(apiUrl + '/' + id) .done(function (data) { $('#product').text(formatItem(data)); }) .fail(function (jqXHR, textStatus, err) { $('#product').text('Error: ' + err); }); }
اجرای اپلیکیشن
اپلیکیشن را با F5 اجرا کنید. صفحه وب باز شده باید چیزی مشابه تصویر زیر باشد.
برای گرفتن محصولی مشخص، شناسه آن را وارد کنید و روی Search کلیک کنید.
اگر شناسه نامعتبری وارد کنید، سرور یک خطای HTTP بر میگرداند.
استفاده از F12 برای مشاهده درخواستها و پاسخ ها
هنگام کار با سرویسهای HTTP، مشاهدهی درخواستهای ارسال شده و پاسخهای دریافتی بسیار مفید است. برای اینکار میتوانید از ابزار توسعه دهندگان وب استفاده کنید، که اکثر مرورگرهای مدرن، پیاده سازی خودشان را دارند. در اینترنت اکسپلورر میتوانید با F12 به این ابزار دسترسی پیدا کنید. به برگه Network بروید و روی Start Capturing کلیک کنید. حالا صفحه وب را مجددا بارگذاری (reload) کنید. در این مرحله اینترنت اکسپلورر ترافیک HTTP بین مرورگر و سرور را تسخیر میکند. میتوانید تمام ترافیک HTTP روی صفحه جاری را مشاهده کنید.
به دنبال آدرس نسبی "api/products/" بگردید و آن را انتخاب کنید. سپس روی Go to detailed view کلیک کنید تا جزئیات ترافیک را مشاهده کنید. در نمای جزئیات، میتوانید headerها و بدنه درخواستها و پاسخها را ببینید. مثلا اگر روی برگه Request headers کلیک کنید، خواهید دید که اپلیکیشن ما در Accept header دادهها را با فرمت "application/json" درخواست کرده است.
اگر روی برگه Response body کلیک کنید، میتوانید ببینید چگونه لیست محصولات با فرمت JSON سریال شده است. همانطور که گفته شده مرورگرهای دیگر هم قابلیتهای مشابهی دارند. یک ابزار مفید دیگر Fiddler است. با استفاده از این ابزار میتوانید تمام ترافیک HTTP خود را مانیتور کرده، و همچنین درخواستهای جدیدی بسازید که این امر کنترل کاملی روی HTTP headers به شما میدهد.
قدمهای بعدی
<embed height="400" width="500" flashvars="config=http://www.aparat.com//video/video/config/videohash/BA9Md/watchtype/embed" allowfullscreen="true" quality="high" name="aparattv_BA9Md" id="aparattv_BA9Md" src="http://host10.aparat.com/public/player/aparattv" type="application/x-shockwave-flash">
using System.Web.Mvc; namespace MvcApplication1 { public static class AparatPlayerHelper { public static MvcHtmlString AparatPlayer(this HtmlHelper helper, string mediafile, int height, int width) { var player = @"<embed height=""{0}"" width=""{1}"" flashvars=""config=http://www.aparat.com//video/video/config/videohash/{2}/watchtype/embed"" allowfullscreen=""true"" quality=""high"" name=""aparattv_{2}"" id=""aparattv_{2}"""" src=""http://host10.aparat.com/public/player/aparattv"" type=""application/x-shockwave-flash"">"; player = string.Format(player, height, width, mediafile); return new MvcHtmlString(player); } } }
@Html.AparatPlayer("BA9Md", 400, 500)
using System; using System.Drawing; using System.Web.Mvc; namespace MvcApplication1 { public static class YouTubePlayerHelper { public static MvcHtmlString YouTubePlayer(this HtmlHelper helper, string playerId, string mediaFile, YouTubePlayerOption youtubePlayerOption) { const string baseURL = "http://www.youtube.com/v/"; // YouTube Embedded Code var player = @"<div id=""YouTubePlayer_{7}""width:{1}px; height:{2}px;""> <object width=""{1}"" height=""{2}""> <param name=""movie"" value=""{6}{0}&fs=1&border={3}&color1={4}&color2={5}""></param> <param name=""allowFullScreen"" value=""true""></param> <embed src=""{6}{0}&fs=1&border={3}&color1={4}&color2={5}"" type = ""application/x-shockwave-flash"" width=""{1}"" height=""{2}"" allowfullscreen=""true""></embed> </object> </div>"; // Replace All The Value player = String.Format(player, mediaFile, youtubePlayerOption.Width, youtubePlayerOption.Height, (youtubePlayerOption.Border ? "1" : "0"), ConvertColorToHexa.ConvertColorToHexaString(youtubePlayerOption.PrimaryColor), ConvertColorToHexa.ConvertColorToHexaString(youtubePlayerOption.SecondaryColor), baseURL, playerId); //Retrun Embedded Code return new MvcHtmlString(player); } } public class YouTubePlayerOption { int _width = 425; int _height = 355; Color _color1 = Color.Black; Color _color2 = Color.Aqua; public YouTubePlayerOption() { Border = false; } public int Width { get { return _width; } set { _width = value; } } public int Height { get { return _height; } set { _height = value; } } public Color PrimaryColor { get { return _color1; } set { _color1 = value; } } public Color SecondaryColor { get { return _color2; } set { _color2 = value; } } public bool Border { get; set; } } public class ConvertColorToHexa { private static readonly char[] HexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; public static string ConvertColorToHexaString(Color color) { var bytes = new byte[3]; bytes[0] = color.R; bytes[1] = color.G; bytes[2] = color.B; var chars = new char[bytes.Length * 2]; for (int i = 0; i < bytes.Length; i++) { int b = bytes[i]; chars[i * 2] = HexDigits[b >> 4]; chars[i * 2 + 1] = HexDigits[b & 0xF]; } return new string(chars); } } }
@Html.YouTubePlayer("Casablanca", "iLdqKUkkM6w", new YouTubePlayerOption() { Border = true })
الگوی Composite
الگوی Composite در عمل یک Collection Pattern (الگوی مجموعه ای) است. که میتوان در درون آن ترکیبی از زیر مجموعههای مختلف را قرار داد و سپس هر زیر مجموعه را به نوبه خود فراخوانی نمود.به بیان دیگر الگوی Composite به ما کمک میکند که در یک ساختار درختی بتوانیم مجموعه ای (Collection ی)،از بخشی از آبجکتهای سلسله مراتبی را نمایش دهیم. این الگو به Client اجازه میدهد، که رفتار یکسانی نسبت به یک Collection ی از آبجکتها یا یک آبجکت تنها داشته باشد.
مثالهای متعددی میتوان از الگوی Composite زد، که در ذیل به چند نمونه از آنها میپردازیم:
نمونه اول: همانطور که میدانیم یک سازمان از بخشهای مختلفی تشکیل شده است، که بصورت سلسله مراتبی با یکدیگر در ارتباط میباشند، چنانچه بخواهیم بخشها و زیر مجموعههای تابعه آنها را بصورت آبجکت نگهداری نماییم، یکی از بهترین الگوهای پیشنهاد شده الگوی Composite میباشد.
نمونه دوم: در بحث حسابداری،یک حساب کل از چندین حساب معین تشکیل شده است و هر حساب معین نیز از چندین سرفصل حسابداری تشکیل میشود. بنابراین برای نگهداری آبجکتهای معین مرتبط به حساب کل، میتوان آنها را در یک Collection قرار داد. و هر حساب معین را میتوان،در صورت داشتن چندین سرفصل در مجموعه خود به عنوان یک Collection در نظر گرفت. برای دسترسی به هر حساب معین و سرفصلهای زیر مجموعه آن نیز میتوان از الگوی Composite استفاده نمود.
نمونه سوم: یک File System را در نظر بگیرید،که ساختارش از File و Folder تشکیل شده است. و میتواند یک ساختار سلسله مراتبی داشته باشد.بطوریکه درون هر Folder میتواند یک یا چند File یا Folder قرار گیرد. و در درون Folderهای زیر مجموعه میتوان چندین File یا Folder دیگر قرار داد.اگر بخواهیم به عنوان نمونه شکل ساختار درختی File و فولدر را نمایش دهیم بصورت زیر خواهد بود:
در ساختار درختی به Folder شاخه یا Branch گویند، چون میتواند زیر شاخههای دیگری نیز در خود داشته باشد. و به File برگ یا Leaf گویند.برگ نمیتواند زیر مجموعه ای داشته باشد. در واقع برگ (Leaf) بیانگر انتهای یک شاخه میباشد.
نمونه آخر:می توان به ساختار منوها در برنامهها اشاره نمود.هر منو میتواند شامل چندین زیر منو باشد. و همان زیر منوها میتوانند از چندین زیر منوی دیگر تشکیل شوند. این ساختار نیز یک ساختار سلسله مراتبی میباشد، و برای نگهداری آبجکتهای یک مجموعه میتوان از الگوی Composite استفاده نمود.
الگوی Composite از سه Component اصلی تشکیل شده است،که یکایک آنها را بررسی میکنیم:
- Component: کلاس پایه ای است که در آن متدها یا Functionalityهای مشترک تعریف میگردد. Component میتواند یک Abstract Class یا Interface باشد.
- Leaf : به آبجکتهای گفته میشود که هیچ Child ی ندارند. و فقط یک آبجکت مستقل تنها میباشد. کلاس Leaf متدهای مشترک تعریف شده در Component را پیاده سازی میکند.اگر مثال File و Folder را بخاطر آورید،File یک آبجکت از نوع Leaf است چون نمیتواند هیچ فرزندی داشته باشد و یک آبجکت تنها میباشد.
- Composite: کلاس فوق Collection ی از آبجکتها را در خود نگهداری میکند، به عبارتی در Composite میتوان بخشی از ساختار درختی را قرار داد، که این ساختار میتواند ترکیبی از آبجکتهای Leaf و Composite باشد. در مثال File و Folder، یک Folder را میتوان به عنوان Composite در نظر گرفت،زیرا که یک Folder میتواند چندین File یا Folder را در خود جای دهد. در کلاس Composite معمولا متدهایی همچون Add (افزودن Remove،( Child (حذف یک Child) و غیرو... وجود دارد.
public interface Icomponent { void Display(int depth); }
public class Leaf:Icomponent { private String name = string.Empty; public Leaf(string name) { this.name = name; } public void Display(int depth) { Console.WriteLine(new String('-', depth) + ' ' + name); } }
public class Composite:Icomponent { private List<Icomponent> _children = new List<Icomponent>(); private String name = String.Empty; public Composite(String sname) { this.name = sname; } public void Add(Icomponent component) { _children.Add(component); } public void Remove(Icomponent component) { _children.Remove(component); } public void Display(int depth) { Console.WriteLine(new String('-', depth) + ' ' + name); // Recursively display child nodes foreach (Icomponent component in _children) { component.Display(depth + 2); } } }
class Program { static void Main(string[] args) { // Create a tree structure Composite root = new Composite("root"); root.Add(new Leaf("Leaf A")); root.Add(new Leaf("Leaf B")); Composite comp = new Composite("Composite X"); comp.Add(new Leaf("Leaf XA")); comp.Add(new Leaf("Leaf XB")); root.Add(comp); root.Add(new Leaf("Leaf C")); // Add and remove a leaf Leaf leaf = new Leaf("Leaf D"); root.Add(leaf); root.Remove(leaf); // Recursively display tree root.Display(1); Console.ReadKey(); } }