I've been doing some work the last couple of weeks with Angular2. I really like it. Not just because it uses typescript, but also because it feels really natural and straightforward while working with it. No more string based dependency injection, or strange digest cycle stuff, it just seems to work. This last week I've migrated our beta-13 Angular app to the latest rc-1, and used that to keep track of the fun and easy stuff Angular 2 provides. Note though, that the application we're developing is really that complex, so I can only assume we'll run into more complex Angular2 features in the near future. For now, though, let me share some general tips and tricks we've encountered thus far (in no particular order). Oh, all examples are in typescript, since after using that, I really don't want to go back to plain old javascript (POJS?).
جهت اینکار یک پروژه از نوع class library ایجاد کنید. فایل class1.cs را که به طور پیش فرض ایجاد میشود، حذف کنید و رفرنسهای Microsoft.Web.Management.dll و Microsoft.Web.Administration.dll را از مسیر زیر اضافه کنید:
\Windows\system32\inetsrv
در مرحله بعدی در تب Build Events کد زیر را در بخش Post-build event command line اضافه کنید. این کد باعث میشود بعد از هر بار کامپایل پروژه، به طور خودکار در GAC ثبت شود:
call "%VS80COMNTOOLS%\vsvars32.bat" > NULL gacutil.exe /if "$(TargetPath)"
نکته:در صورتی که از VS2005 استفاده میکنید در تب Debug در قسمت Start External Program مسیر زیر را قرار بدهید. اینکار برای تست و دیباگینگ پروژه به شما کمک خواهد کرد. این تنظیم شامل نسخههای اکسپرس نمیشود.\windows\system32\inetsrv\inetmgr.exe
ساخت یک Module Provider
رابطهای کاربری IIS همانند هسته و کل سیستمش، ماژولار و قابل خصوصی سازی است. رابط کاربری، مجموعهای از ماژول هایی است که میتوان آنها را حذف یا جایگزین کرد. تگ ورودی یا معرفی برای هر UI یک module provider است. خیلی خودمانی، تگ ماژول پروایدر به معرفی یک UI در IIS میپردازد. لیستی از module providerها را میتوان در فایل زیر در تگ بخش <modules> پیدا کرد.
%windir%\system32\inetsrv\Administration.config
در اولین گام یک کلاس را به اسم imageCopyrightUIModuleProvider.cs ایجاد کرده و سپس آنرا به کد زیر، تغییر میدهیم. کد زیر با استفاده از ModuleDefinition یک نام به تگ Module Provider داده و کلاس imageCopyrightUI را که بعدا تعریف میکنیم، به عنوان مدخل entry رابط کاربری معرفی کرده:
using System; using System.Security; using Microsoft.Web.Management.Server; namespace IIS7Demos { class imageCopyrightUIProvider : ModuleProvider { public override Type ServiceType { get { return null; } } public override ModuleDefinition GetModuleDefinition(IManagementContext context) { return new ModuleDefinition(Name, typeof(imageCopyrightUI).AssemblyQualifiedName); } public override bool SupportsScope(ManagementScope scope) { return true; } } }
با ارث بری از کلاس module provider، سه متد بازنویسی میشوند که یکی از آن ها SupportsScope هست که میدان عمل پروایدر را مشخص میکند، مانند اینکه این پرواید در چه میدانی باید کار کند که میتواند سه گزینهی server,site,application باشد. در کد زیر مثلا میدان عمل application انتخاب شده است ولی در کد بالا با برگشت مستقیم true، همهی میدان را جهت پشتیبانی از این پروایدر اعلام کردیم.
public override bool SupportsScope(ManagementScope scope) { return (scope == ManagementScope.Application) ; }
حالا که پروایدر (معرف رابط کاربری به IIS) تامین شده، نیاز است قلب کار یعنی ماژول معرفی گردد. اصلیترین متدی که باید از اینترفیس ماژول پیاده سازی شود متد initialize است. این متد جایی است که تمام عملیات در آن رخ میدهد. در کلاس زیر imageCopyrightUI ما به معرفی مدخل entry رابط کاربری میپردازیم. در سازندههای این متد، پارامترهای نام، صفحه رابط کاربری وتوضیحی در مورد آن است. تصویر کوچک و بزرگ جهت آیکن سازی (در صورت عدم تعریف آیکن، چرخ دنده نمایش داده میشود) و توصیفهای بلندتر را نیز شامل میشود.
internal class imageCopyrightUI : Module { protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) { base.Initialize(serviceProvider, moduleInfo); IControlPanel controlPanel = (IControlPanel)GetService(typeof(IControlPanel)); ModulePageInfo modulePageInfo = new ModulePageInfo(this, typeof(imageCopyrightUIPage), "Image Copyright", "Image Copyright",Resource1.Visual_Studio_2012,Resource1.Visual_Studio_2012); controlPanel.RegisterPage(modulePageInfo); } }
شیء ControlPanel مکانی است که قرار است آیکن ماژول نمایش داده شود. شکل زیر به خوبی نام همه قسمتها را بر اساس نام کلاس و اینترفیس آنها دسته بندی کرده است:
پس با تعریف این کلاس جدید ما روی صفحهی کنترل پنل IIS، یک آیکن ساخته و صفحهی رابط کاربری را به نام imageCopyrightUIPage، در آن ریجستر میکنیم. این کلاس را پایینتر شرح دادهایم. ولی قبل از آن اجازه بدهید تا انواع کلاس هایی را که برای ساخت صفحه کاربرد دارند، بررسی نماییم. در این مثال ما با استفاده از پایهایترین کلاس، سادهترین نوع صفحه ممکن را خواهیم ساخت. 4 کلاس برای ساخت یک صفحه وجود دارند که بسته به سناریوی کاری، شما یکی را انتخاب میکنید.
ModulePage | شامل اساسیترین متدها و سورسها شده و هیچگونه رابط کاری ویژهای را در اختیار شما قرار نمیدهد. تنها یک صفحهی خام به شما میدهد که میتوانید از آن استفاده کرده یا حتی با ارث بری از آن، کلاسهای جدیدتری را برای ساخت صفحات مختلف و ویژهتر بسازید. در حال حاضر که هیچ کدام از ویژگیهای IIS فعلی از این کلاس برای ساخت رابط کاربری استفاده نکردهاند. |
ModuleDialogPage | یک صفحه شبیه به دیالوگ را ایجاد میکند و شامل دکمههای Apply و Cancel میشود به همراه یک سری متدهای اضافیتر که اجازهی override کردن آنها را دارید. همچنین یک سری از کارهایی چون refresh و از این دست عملیات خودکار را نیز انجام میدهد. از نمونه رابطهایی که از این صفحات استفاده میکنند میتوان machine key و management service را اسم برد. |
ModulePropertiesPage | این صفحه یک رابط کاربری را شبیه پنجره property که در ویژوال استادیو وجود دارد، در دسترس شما قرار میدهد. تمام عناصر آن در یک حالت گرید grid لیست میشوند. از نمونههای موجود میتوان به CGI,ASP.Net Compilation اشاره کرد. |
ModuleListPage | این کلاس برای مواقعی کاربرد دارد که شما قرار است لیستی از آیتمها را نشان دهید. در این صفحه شما یک ListView دارید که میتوانید عملیات جست و جو، گروه بندی و نحوهی نمایش لیست را روی آن اعمال کنید. |
public sealed class imageCopyrightUIPage : ModulePage { public string message; public bool featureenabled; public string color; ComboBox _colCombo = new ComboBox(); TextBox _msgTB = new TextBox(); CheckBox _enabledCB = new CheckBox(); public imageCopyrightUIPage() { this.Initialize(); } void Initialize() { Label crlabel = new Label(); crlabel.Left = 50; crlabel.Top = 100; crlabel.AutoSize = true; crlabel.Text = "Enable Image Copyright:"; _enabledCB.Text = ""; _enabledCB.Left = 200; _enabledCB.Top = 100; _enabledCB.AutoSize = true; Label msglabel = new Label(); msglabel.Left = 150; msglabel.Top = 130; msglabel.AutoSize = true; msglabel.Text = "Message:"; _msgTB.Left = 200; _msgTB.Top = 130; _msgTB.Width = 200; _msgTB.Height = 50; Label collabel = new Label(); collabel.Left = 160; collabel.Top = 160; collabel.AutoSize = true; collabel.Text = "Color:"; _colCombo.Left = 200; _colCombo.Top = 160; _colCombo.Width = 50; _colCombo.Height = 90; _colCombo.Items.Add((object)"Yellow"); _colCombo.Items.Add((object)"Blue"); _colCombo.Items.Add((object)"Red"); _colCombo.Items.Add((object)"White"); Button apply = new Button(); apply.Text = "Apply"; apply.Click += new EventHandler(this.applyClick); apply.Left = 200; apply.AutoSize = true; apply.Top = 250; Controls.Add(crlabel); Controls.Add(_enabledCB); Controls.Add(collabel); Controls.Add(_colCombo); Controls.Add(msglabel); Controls.Add(_msgTB); Controls.Add(apply); } public void ReadConfig() { try { ServerManager mgr; ConfigurationSection section; mgr = new ServerManager(); Configuration config = mgr.GetWebConfiguration( Connection.ConfigurationPath.SiteName, Connection.ConfigurationPath.ApplicationPath + Connection.ConfigurationPath.FolderPath); section = config.GetSection("system.webServer/imageCopyright"); color = (string)section.GetAttribute("color").Value; message = (string)section.GetAttribute("message").Value; featureenabled = (bool)section.GetAttribute("enabled").Value; } catch { } } void UpdateUI() { _enabledCB.Checked = featureenabled; int n = _colCombo.FindString(color, 0); _colCombo.SelectedIndex = n; _msgTB.Text = message; } protected override void OnActivated(bool initialActivation) { base.OnActivated(initialActivation); if (initialActivation) { ReadConfig(); UpdateUI(); } } private void applyClick(Object sender, EventArgs e) { try { UpdateVariables(); ServerManager mgr; ConfigurationSection section; mgr = new ServerManager(); Configuration config = mgr.GetWebConfiguration ( Connection.ConfigurationPath.SiteName, Connection.ConfigurationPath.ApplicationPath + Connection.ConfigurationPath.FolderPath ); section = config.GetSection("system.webServer/imageCopyright"); section.GetAttribute("color").Value = (object)color; section.GetAttribute("message").Value = (object)message; section.GetAttribute("enabled").Value = (object)featureenabled; mgr.CommitChanges(); } catch { } } public void UpdateVariables() { featureenabled = _enabledCB.Checked; color = _colCombo.Text; message = _msgTB.Text; } }
mgr.CommitChanges();
%vs110comntools%\vsvars32.bat
GACUTIL /l ClassLibrary1
<add name="imageCopyrightUI" type="ClassLibrary1.imageCopyrightUIProvider, ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d0b3b3b2aa8ea14b"/>
%windir%\system32\inetsrv\config\administration.config
از آنجا که این مقاله طولانی شده است، باقی موارد ویرایشی روی این UI را در مقاله بعدی بررسی خواهیم کرد.
ایجاد یک request bin جدید
برای مشاهدهی محتوای ارسالی توسط postman بدون برپایی وب سرویس خاصی، از سایت requestbin استفاده خواهیم کرد. در اینجا با کلیک بر روی دکمهی create a request bin، یک آدرس موقتی را مانند http://requestbin.fullcontact.com/1gdduy21 برای شما تولید میکند. میتوان انواع و اقسام درخواستها را به این آدرس ارسال کرد و سپس با ریفرش کردن آن در مرورگر، دقیقا محتوای ارسالی به سمت سرور را بررسی نمود.
برای مثال اگر همین آدرس را در postman وارد کرده و سپس بر روی دکمهی send آن کلیک کنیم، پس از ریفرش صفحه، چنین تصویری حاصل میشود:
Encoding کوئری استرینگها در postman
مثال زیر را درنظر بگیرید:
در اینجا با استفاده از گرید ساخت Query Params، دو کوئری استرینگ جدید را ایجاد کردهایم که در دومی، مقدار وارد شده، دارای فاصله است. اگر این درخواست را ارسال کنیم، مشاهده خواهیم کرد که مقدار ارسالی توسط آن encoded نیست:
برای رفع این مشکل میتوان بر روی تکستباکس ورود مقدار یک کلید، کلیک راست کرد و از منوی باز شده، گزینهی encode URI component را انتخاب نمود:
البته برای اینکه این گزینه درست عمل کند، نیاز است یکبار کل متن را انتخاب کرد و سپس بر روی آن کلیک راست نمود، تا انتخاب گزینهی encode URI component، به درستی اعمال شود:
امکان تعریف متغیرها در آدرسهای HTTP
Postman از امکان تعریف path variables پشتیبانی میکند. برای مثال مسیر api.example.com/users/5/contracts/2 را در نظر بگیرید که میتواند سبب نمایش اطلاعات قرارداد دوم کاربر پنجم شود. برای پویا کردن یک چنین آدرسی در postman میتوان از مسیری مانند api.example.com/users/:userid/contracts/:contractid استفاده کرد:
اگر به تصویر فوق دقت کنیم، متغیرهای شروع شدهی با :، در قسمت path variables ذکر شدهاند و به سادگی قابل تغییر و مقدار دهی میباشند (در گریدی همانند گرید کوئری استرینگها) که برای آزمایش دستی، بسیار مفید هستند.
امکان ارسال فایلها به سمت سرور
زمانیکه برای مثال، نوع درخواست به Post تغییر میکند، امکان تنظیم بدنهی آن نیز مسیر میشود. در این حالت اگر گزینهی form-data را انتخاب کنیم، با نزدیک کردن اشارهگر ماوس به هر ردیف جدید (پیش از ورود کلید آن ردیف)، میتوان نوع Text و یا File را انتخاب کرد:
در اینجا پس از انتخاب گزینهی File، میتوان علاوه بر تعیین کلید این ردیف، با استفاده از دکمهی select files، چندین فایل را نیز برای ارسال انتخاب کرد:
روش انتقال درخواستهای پیچیده به Postman
تا اینجا روش ساخت درخواستهای متداولی را بررسی کردیم که آنچنان پیچیده، طولانی و به همراه جزئیات زیادی (مانند کوکیها،انواع و اقسام هدرها و ...) نبودند. فرض کنید میخواهید درخواست ارسال یک امتیاز جدید را به مطلبی در سایت جاری، توسط Postman شبیه سازی کنیم. برای اینکار، توسط مرورگر کروم به سایت وارد شده و پس از لاگین و تنظیم خودکار کوکیهای اعتبارسنجی، برگهی developer tools مرورگر را باز کرده و در آن، قسمت network را انتخاب کنید:
در اینجا گزینهی preserve log را نیز انتخاب کنید تا پس از ارسال درخواستی، سابقهی عملیات، پاک نشود. سپس به صورت معمولی به مطلبی امتیاز دهید. اکنون بر روی مدخل درخواست آن کلیک راست کرده و از منوی ظاهر شده، گزینهی Copy->Copy as cURL را انتخاب کنید تا این عملیات و تمام جزئیات مرتبط با آنرا تبدیل به یک دستور cURL کرده و به حافظه کپی کند.
سپس در postman، از منوی بالای صفحه، سمت چپ آن، گزینهی Import را انتخاب کنید:
در ادامه این دستور کپی شدهی در حافظه را در قسمت Paste Raw Text، قرار دهید و بر روی دکمهی import کلیک کنید:
در این حالت postman این دستور را پردازش کرده و فیلدهای ساخت یک درخواست را به صورت خودکار پر میکند.
یک نکتهی مهم: در حالت انتخاب Copy->Copy as cURL در مرورگر کروم، دو گزینهی cmd و bash موجود هستند. حالت bash را باید انتخاب کنید تا توسط postman به دسترسی parse شود. حالت cmd یک چنین خروجی مشکل داری را در postman تولید میکند که قابل ارسال به سمت سرور نیست:
اما جزئیات حالت bash آن، به درستی parse شدهاست و قابلیت send مجدد را دارد:
کار با کوکیها در Postman
کوکیها نیز در اصل به صورت یک هدر HTTP به صورت خودکار توسط مرورگرها به سمت سرور ارسال میشوند؛ اما Postman روش سادهتری را برای تعریف و کار با آنها ارائه میدهد (و ترجیح میدهد که بین کوکیها و هدرها تفاوت قائل شود؛ هم در زمان ارسال و هم در زمان نمایش response که در کنار قسمت هدرهای دریافتی از سرور، لیست کوکیهای دریافتی نیز به صورت مجزایی نمایش داده میشوند).
با کلیک بر روی لینک Cookies، در ذیل قسمتی که آدرس یک درخواست تنظیم میشود، قسمت مدیریت کوکیها نیز ظاهر خواهد شد که با انتخاب هر نامی در اینجا، میتوان مقدار آنرا ویرایش و یا حتی حذف کرد. در این لیست، تمام کوکیهایی را که تاکنون تنظیم کرده باشید، میتوانید مشاهده کنید (و مختص به برگهی خاصی نیست) و همانند قسمت مدیریت کوکیهای یک مرورگر رفتار میکند.
روش کار با آن نیز به این صورت است: ابتدا باید یک دومین را اضافه کنید. سپس ذیل دومین اضافه شده، دکمهی Add cookie ظاهر میشود و به هر تعدادی که لازم باشد، میتوان برای آن دومین کوکی تعریف کرد:
پس از تعریف کوکیها، در حین کلیک بر روی دکمهی send، کوکیهای متعلق به دومین وارد شدهی در قسمت آدرس درخواست، از قسمت مدیریت کوکیها به صورت خودکار دریافت شده و به سمت سرور ارسال خواهند شد.
به اشتراک گذاری سابقهی درخواستها
در قسمت اول مشاهده کردیم که برای ذخیره سازی درخواستها، باید آنها را در مجموعههای Postman، ذخیره و ساماندهی کرد. برای گرفتن خروجی از این مجموعهها و به اشتراک گذاشتن آنها، اگر اشارهگر ماوس را بر روی نام یک مجموعه حرکت دهیم، یک دکمهی جدید با برچسب ... ظاهر میشود:
با کلیک بر روی آن، یکی از گزینههای آن، export نام دارد که جزئیات تمام درخواستهای یک مجموعه را به صورت یک فایل JSON ذخیره میکند. برای نمونه فایل JSON خروجی دو قسمت قبل این سری را میتوانید از اینجا دریافت کنید: httpbin.postman_collection.json
پس از تولید این فایل JSON، برای بازیابی آن میتوان از دکمهی Import که در منوی سمت چپ، بالای postman قرار دارد، استفاده کرد که نمونهای از آنرا برای Import جزئیات درخواستهای cURL پیشتر مشاهده کردید. در اینجا، همان اولین گزینهی دیالوگ Import که Import file نام دارد، دقیقا برای همین منظور تدارک دیده شدهاست.
ترجیحا نوع Typescript را انتخاب کردم. البته در داخل فایل ts. امکان نوشتن جاوا اسکریپت هم هست. بعد از ایجاد پروژه اگر با تصویری شبیه به تصویر زیر روبرو شدید، در نتیجه تنظیمات نصب و راه اندازی به درستی صورت گرفته است.
اگر به قسمت solution explorer دقت کنید، فایلی به نام config.xml را مشاهده خواهید کرد. با کلیک بر روی این فایل، یک صفحهی گرافیکی باز خواهد شد که این امکان را به شما میدهد که پلاگینهای مورد نیاز خود، تنظیمات مربوط به نرم افزار تولیدی (مانند تنظیم ورژن ویندوزی که میخواهید app شما بر روی آن اجرا شود) و تنظیمات مربوط به هر یک از پلتفرمها را به صورت مجزا در اختیار داشته باشید.
یک فایل index.html هم در قالب پیشفرض قرار داده شده که بعدا میتوانید آن را تغییر دهید و یا صفحات دیگری را اضافه کنید. همان طور که در قسمتهای قبل گفته شد، قرار است ما یک وب اپلیکیشن طراحی کنیم و آن را درون Container بومی Cordova بسته بندی کنیم. لذا محدودیتی برای استفادهی از کتابخانههای مرتبط با CSS ، HTML و JavaScript نداریم و در ادامهی مقالات با مثالهای متعددی از آنها استفاده خواهیم کرد.
در فولدر scripts-->typeings-->cordova-->plugins اینترفیسهایی که برای دسترسی به امکانات بومی دستگاه تلفن فعلا در Cordova پشتیبانی میشوند، قرار گرفته است.
برای استفاده از تکنولوژیهای وب در محیط بومی دستگاه، در طی فرآیند کامپایل، Cordova یک اپلیکیشن را به وسیله دو چیز مهم که در زیر اشاره شده است، خواهد ساخت.
- یک اپلیکیشن با یک کامپوننت WebView که با مرورگر یکپارچه شده است.
- یه سری از منابعی که در داخل فایلهای اپلیکیشن وب ما قرار دارند.
برای یکپارچه شدن APIهای Cordova با وب پیج موجود، اندکی کد نیاز داریم که برای انکار لینکی شبیه لینک زیر را در فایل html خود استفاده میکنیم که فقط بعد از کامپایل وجود خارجی دارد؛ به صورت زیر:
<script src="cordova.js"></script>
در پایان هم برای فهمیدن اینکه APIهای Cordova در دسترس هستند، میتوانیم رخداد مربوط به devicerady را مدیریت کنیم؛ به صورت زیر:
document.addEventListener("deviceready", onDeviceReady, false); function onDeviceReady() { /* INIT */ }
برای مدیریت رخدادهای مربوط به pause و resume هم که نشان دهندهی ادامه برنامه (خارج شدن از حالت pause) و حالت تعلیق هستند، میتوان به شکل زیر عمل کرد:
function onDeviceReady() { // Handle the Cordova pause and resume events document.addEventListener('pause', onPause, false); document.addEventListener('resume', onResume, false); // TODO: Cordova has been loaded. Perform any initialization that requires Cordova here. } function onPause() { // TODO: This application has been suspended. Save application state here. } function onResume() { // TODO: This application has been reactivated. Restore application state here. }
حال قصد داریم پروژهی خود را که قرار است یک متن ساده را نشان دهد، با استفاده از شبیه ساز اجر ا کنیم. برای این منظور از قسمت toolbar ویژوال استودیو ، Solution Platform خود را انتخاب کنید و سپس میتوانید شبیه ساز مورد نظر خود را انتخاب کرده و برنامه را اجرا کنید. در اینجا محیط مورد نظر من اندروید است و برای این منظور هم میتوانم از شبیه ساز Android Emulator یا Ripple استفاده کنم. به دلیل سرعت کم شبیه ساز اندروید، میتوانید شبیه ساز YouWave را دانلود و اجرا کرده و در قسمتی که شبیه ساز را از toolbar ویژوال انتخاب میکردید، این بار گزینهی Device را انتخاب کنید. بعد از کامپایل برنامهی شما، فایل apk تولید شده بر روی شبیه ساز نصب خواهد شد و شما قادر خواهید بود آنرا اجرا کنید.
نتیجهی نهایی
با شبیه ساز Ripple
مطالعه بیشتر
https://msdn.microsoft.com/en-us/library/dn879821(v=vs.140).aspx
http://blog.falafel.com/getting-started-with-cordova-and-multi-device-hybrid-app-in-visual-studio/
http://www.codeproject.com/Articles/860150/Visual-Studio-and-Apache-Cordova
نکته : وقتی پروژه را برای اولین بار اجرا میکنید شاید کمی طول بکشد تا نتیجهی نهایی را ببنید و آن هم به دلیل این است که ویژوال استودیو باید مجموعهای از package های مورد نیاز Cordova را دانلود کند.
در مقاله بعد با jQuery Mobile آشنا خواهیم شد و یک مثال برای کار کردن با آن در نظر خواهم گرفت.
ادامه دارد ...