بازبینی اشاره گر ها:
در کنار هر گره علامتی نمایان میشود که وضعیت code amp در آن لحظه برای آن گره را نمایش میدهد.
تغییر نمای دیاگرام:
برای تغییر نمای گراف code map و نمایش بهتر آن از گزینه layout یکی از حالات موجود را میتوانید انتخاب نمایید. هر وقت گره ای اضافه شود که قبلا اضافه شده باشد رنگ آن سبر میشود برای پاک کردن این چنین گرههای گزینه clear Result Highlighting را انتخاب نمایید.
Sqlite دیتابیس مناسبی برای برنامههای چندسکویی است و عموما به عنوان اولین گزینه استفاده میشود. برای کار با این دیتابیس، ما از ماژول sql.js که یکی از ماژولهای معروف در جاوااسکریپت است، استفاده میکنیم. برای نصب آن از طریق npm، به شکل زیر اقدام میکنیم:
npm install sql.js --save
const{app,BrowserWindow}=require("electron"); let win; function onLoad() { win=new BrowserWindow({ width:800, height:600 }); win.loadURL(`file://${__dirname}/index.html`); } app.on("ready",onLoad());
var path=require("path"); path.exists('filepath",(status)=> { .... }); var status=path.existsSync("file"); //=============================== var fs=require("fs"); fs.exists('filepath",(status)=> { .... }); var status=path.existsSync("file");
fs.stat('foo.txt', function(err, stat) { if(err == null) { console.log('فایل موجوده'); } else if(err.code == 'ENOENT') { // فایل وجود نداره fs.writeFile('log.txt', 'Some log\n'); } else { //خطای دیگری رخ داده است } });
try { stats = fs.statSync(path); console.log("File exists."); } catch (e) { console.log("File does not exist."); }
const fs = require('fs'); const sql = require('sql.js'); dbPath = './mydb.sqlite'; dbExists=false; try { dbExists = fs.statSync(dbPath); } catch (e) { } if(!dbExists) { //create Database var sqlStr=fs.readFileSync("./sql.txt"); var db = new sql.Database(); db.run(String(sqlStr)); //write to disk var data=db.export(); var buffer=new Buffer(data); fs.writeFileSync(dbPath,buffer); } else{ var buffer = fs.readFileSync(dbPath); var db = new sql.Database(buffer); }
CREATE TABLE numbers ( id INT PRIMARY KEY UNIQUE NOT NULL, fname VARCHAR (20) NOT NULL, lname VARCHAR (30) NOT NULL, number VARCHAR (15) NOT NULL ); insert into numbers values(1,'ali','yeganeh','03111223344'); insert into numbers values(2,'xxx','yyy','45454555');
بعد از آن نیاز است تا دیتابیس در دسترس Render Processها قرار بگیرد که در مقاله "شیوه کدنویسی در الکترون " در مورد global صحبت کردهایم و نحوه استفاده از آن را فرا گرفتیم:
global.db=db;
در پایان اجرای برنامه لازم است که دیتابیس توسط دستور close بسته شود. سپس کد زیر را در رویداد windows-all-closed مینویسیم:
app.on('window-all-closed', () => { db.close(); if (process.platform !== 'darwin') { app.quit(); } });
(چند مورد خارج از بحث): کد بعدی که مورد استفاده قرار گرفته است و در مقالات قبلی در مورد آن صحبت نکردهایم این است که در سیستمهای مک، وضعیت به این قرار است که اگر شما برنامه را ببیندید، آن برنامه بسته نشده و در پس زمینه فعال است و میتوانید آن را از طریق dock اطراف صفحه، مجددا فعال کنید. ولی با نوشتن کد بالا، ما این وضعیت را اعلام کردهایم که اگر تمامی پنجرهها بسته شدند، کل برنامه را ببند.
همچنین بسیار خوب است که کد زیر را هم همیشه اضافه کنید:
win.on('closed', () => { win = null; });
پس اگر این کد را نوشتید، وضعیت سیستم عامل مک را به خاطر داشته باشید و مجبور هستید کد زیر را نیز اضافه کنید:
app.on('activate', () => { if (win === null) { createWindow(); } });
بعد از اینکه دیتابیس را به شیء global دادیم، در صفحه html کد زیر را وارد میکنیم:
<html> <head> <script src="./jquery.min.js"></script> <link href="./bootstrap-3.3.6-dist/css/bootstrap.min.css" rel="stylesheet"></link> <meta charset="utf-8"> <title></title> <script> const {remote}=require("electron"); let db=remote.getGlobal("db"); </script> </head> <body> <table id="people" class="table table-hover table-striped"> <th> <tr> <td>First Name</td> <td>last Name</td> <td>Phone Number</td> </tr> </th> <tbody> </tbody> </table> </body> </html>
$(document).ready(()=> { //show data var tableBody=$("#people"); db.each("select * from numbers",(row)=>{ let rowTemplate=`<tr><td>${row.fname}</td><td>${row.lname}</td><td>${row.number}</td></tr>`; tableBody.append(rowTemplate); });
حال وقت آن رسیده است که خروجی کار را ببینیم. پس کد npm start را اجرا میکنیم. همانطور که میبینید خروجی به راحتی نمایش داده میشود. در مقاله بعدی بیشتر در این مورد صحبت میکنیم.
کار با Visual Studio
در این مقاله، یکسری توضیحاتی در مورد ویژگیهای کلیدی ویژوال استودیو به برنامه نویسهای (توسعه دهندههای) پروژههای Asp.net Core MVC ارائه میدهیم.
ایجاد یک پروژه
در ابتدا یک پروژهی وب جدید Asp.net core را به نام Working و بر اساس قالب Empty ایجاد میکنیم. سپس در کلاس startup، قابلیت MVC را فعال میکنیم (کدهای این قسمت، در فصل 5 کامل شرح داده شدهاست)
namespace Working { public class Startup { // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //app.Run(async (context) => //{ // await context.Response.WriteAsync("Hello World!"); //}); } } }
ایجاد مدل:
یک پوشه جدید را به نام Models ایجاد میکنیم و بعد در این پوشه یک کلاس جدید را به نام Product ایجاد میکنیم و کدهای زیر را در کلاس ایجاد شده قرار میدهیم (این قسمت در فصل 5 نیز شرح داده شدهاست):
namespace Working.Models { public class Product { public string Name { get; set; } public decimal Price { get; set; } } }
namespace WorkingWithVisualStudio.Models { public class SimpleRepository { private static SimpleRepository sharedRepository = new SimpleRepository(); private Dictionary<string, Product> products = new Dictionary<string, Product>(); public static SimpleRepository SharedRepository => sharedRepository; public SimpleRepository() { var initialItems = new[] { new Product { Name = "Kayak", Price = 275M }, new Product { Name = "Lifejacket", Price = 48.95M }, new Product { Name = "Soccer ball", Price = 19.50M }, new Product { Name = "Corner flag", Price = 34.95M } }; foreach (var p in initialItems) { AddProduct(p); } } public IEnumerable<Product> Products => products.Values; public void AddProduct(Product p) => products.Add(p.Name, p); } }
نکته: من یک مشخصه (Property) استاتیک را به نام SharedRepository تعریف کردم که دسترسی به SimpleRepository را فراهم میکند و میتواند در طول برنامه از آن استفاده شود. این بهترین کار نیست، ولی میخواهم یک مشکل رایج را که در توسعه MVC روبرو میشوید، نشان دهم. من راه بهتری را برای کار با اجزای مشترک، در فصل 18 توضیح میدهم.
ایجاد Controller و View
در پوشه Controllers، یک فایل جدید را به نام HomeController.cs ایجاد میکنیم و کدهای زیر را در آن قرار میدهیم:
namespace WorkingWithVisualStudio.Controllers { public class HomeController : Controller { public IActionResult Index() => View(SimpleRepository.SharedRepository.Products); } }
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>>Working with Visual Studio</title> </head> <body> <table> <thead> <tr> <td>Name</td> <td>Price</td> </tr> </thead> <tbody> @foreach (var p in Model) {<tr> <td>@p.Name</td> <td>@p.Price</td> </tr>} </tbody> </table> </body> </html>
دو نوع مختلف از بستههای نرم افزاری مورد نیاز برای Asp.Net Core MVC وجود دارند.
معرفی NuGet
ویژوال استودیو به همراه یک ابزار گرافیکی برای مدیریت بستههای NET. است که در یک پروژه گنجانده شدهاست. برای باز کردن این ابزار، گزینه Management NuGet Packages for Solution را از منوی Tools ➤ NuGet Package Manager انتخاب کنید. به این ترتیب ابزار NuGet باز میشود و لیستی از بستههایی که قبلا نصب شدهاند، نمایش داده میشود؛ همانطور که در شکل زیر نشان داده شدهاست:
برگهی Installed، خلاصهای از بستههایی را که قبلا در پروژه نصب شدهاند، نشان میدهد. از برگهی Browse، برای یافتن و نصب بستههای جدید میتوان استفاده کرد و برگهی Updates، فهرست package هایی را که نسخههای اخیر آنها منتشر شدهاند، نمایش میدهد.
معرفی بستهی MICROSOFT.ASPNETCORE.ALL
اگر شما از نسخههای قبلی Asp.Net Core استفاده کرده باشید، باید یک لیست طولانی از بستههای NuGet را به پروژه جدید خود اضافه نمایید. Asp.Net Core2 یک بستهی متفاوت را به نام Microsoft.AspNetCore.All معرفی میکند.
معرفی بستههای Nuget و موقعیت ذخیره سازی آنها
ابزار NuGet لیست بستههای پروژه را در فایل projectname.csproj نگهداری میکند. در اینجا <projectname> با نام پروژه جایگزین میشود. برای مثال در پروژه فوق اطلاعات Nuget، در فایل WorkingWithVisualStudio.csproj ذخیره میشوند. ویژوال استودیو محتویات فایل csproj را در پنجرهی Solution Explorer نمایش نمیدهد. برای ویرایش این فایل، روی پروژه در پنجرهی Solution Explorer راست کلیک کنید و گزینهی Edit WorkWithVisualStudio.csproj را از منوی باز شده، انتخاب کنید. ویژوال استودیو فایل را برای ویرایش باز میکند. فایل csproj یک فایل XML است و شما در آن عنصری را مانند قطعه کد زیر در آن میبینید که Asp.net Core Meta package را به پروژه اضافه میکند:
<ItemGroup> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> </ItemGroup>
معرفی Bower
یک بسته Client-Side، شامل محتوایی است که به مشتری ارسال میشود؛ مانند فایلهای جاوا اسکریپت، Css Stylesheets و یا تصاویر. از Nuget برای مدیریت این نوع فایلها در پروژه نیز استفاده میشود. اما اکنون Asp.Net Core MVC پشتیبانی توکاری را از یک ابزار مدیریت بستههای سمت کاربر، به نام Bower نیز ارائه میدهد. Bower یک ابزار منبع باز ( Open Source ) است که در خارج از مایکروسافت و دنیای NET. توسعه داده شده و نگهداری میشود.
نکته: Bower به تازگی منسوخ شده اعلام گردیدهاست. ممکن است هشدارهایی را که ابزارهای جایگزین را پیشنهاد میکنند نیز مشاهده کنید. با این حال پشتیبانی از Bower با ویژوال استودیو یکپارچه شدهاست و در نگارش 2.1 ابزار مدیریت سمت کلاینت جدید دیگری را نیز بجای آن معرفی کردهاند.
معرفی لیست بستههای Bower
بستههای Bower از طریق فایل ویژهی bower.json مشخص میشوند. برای ایجاد این فایل در پنجره Solution Explorer روی پروژه WorkingWithVisualStudio راست کلیک کنید و Add -> New Item را از منوی باز شده انتخاب کنید. سپس قالب مورد نظر Bower Configuration File را از Asp.net Core -> Web -> General Category انتخاب نمائید؛ مانند تصویر زیر:
ویژوال استودیو نام bower.json را برای آن قرار میدهد. برروی ok کلیک میکنیم و یک فایل جدید، با محتویات پیشفرض زیر به پروژه اضافه میشود:
{ "name": "asp.net", "private": true, "dependencies": {} }
نکته: منبع بستههای Bower در لینک http://bower.io/search وجود دارد. شما میتوانید بستهها مورنظر را در اینجا جستجو و به پروژه اضافه کنید.
بعد از اینکه بستهها نصب شدند، محتویات فایل bower.json به صورت زیر میباشد:
{ "name": "asp.net", "private": true, "resolutions": { "jquery": "3.3.1" } }
فرمت | توضیحات |
3.3.7 | بیان شماره مستقیم بسته نصب شده و تطبیق دقیق آن با شمار نسخه ، e.g ، 3.3.7 |
* | با استفاده از یک ستاره به Bower اجازه نصب آخرین نسخه را میدهد |
3.3.7 =<3.3.7< | پیشوند یک شماره نسخه با < یا =< به Bower اجازه میدهد تا هر نسخه از بستهای که بزرگتر یا بزرگتر مساوی آن نسخهی معین است، نصب شود |
3.3.7 =>3.3.7> | پیشوند یک شماره نسخه با > یا => به Bower اجازه میدهد تا هر نسخه از بستهای را که کوچکتر یا کوچکتر و مساوی نسخهی معین است، نصب شود |
3.3.7~ | پیشوند یک شماره نسخه با یک tilde (با کاراکتر ~ ) به نسخههایی که دو شماره
اولیه آنها مشابه باشند، اجازه نصب میدهد؛ حتی اگر شماره آخر آن نسخه متفاوت
باشد. مانند نسخههای 3.3.9 و 3.3.8 و اجازه نصب نسخه 3.4.0 را نمیدهد؛ چون
شماره دوم آن متفاوت است. |
3.3.7^ | پیشوند یک شماره نسخه با یک قلم (کاراکتر ^) به نسخههایی که شماره اول آنها مشابه باشند، اجازه نصب میدهد؛ حتی اگر شماره دوم آنها متفاوت باشد. مانند نسخههای 3.3.1 و 3.4.1 و 3.5.1 اما نسخه 4.0.0 اجازه نصب ندارد |
مانند Nuget نیز Bower وابستگیهای مرتبط با بستههای اضافه شدهی به یک پروژه را مدیریت میکند. BootStrap برای دسترسی به برخی از ویژگیهای پیشرفته، به JQuery که یک کتابخانهی جاوا اسکریپتی است، تکیه میکند. به همین دلیل است که دو بسته را در شکل فوق نشان داده است. شما میتوانید لیست بستهها و وابستگیهای آنها را به صورت باز شده در بخش مورد نظر در Solution Explorer مشاهده کنید.
در ادامه کتاب، من از نسخه قبلی Bootstrap CSS framework استفاده میکنم. هنگامی که دارم این را مینویسم، تیم Bootstrap در حال توسعهی نسخهی 4 bootStrap است و چندین بار منتشر شدهاست. این نسخهها به عنوان "آلفا" برچسب گذاری شدهاند، اما کیفیت آنها بالا است و برای استفاده در نمونههای این کتاب به اندازه کافی پایدار است. با توجه به انتخاب نوشتن این کتاب با استفاده از Bootstrap 3 و نسخه پیش از نسخه بوت استرپ 4 و به زودی بایگانی شدن آن، تصمیم گرفتم از نسخه جدید استفاده کنم؛ حتی اگر برخی از نامهای کلاسها که برای شیوه نامههای عناصر HTML استفاده میشوند، احتمالا قبل از انتشار نهایی تغییر یابند. این مورد به این معنا است که شما باید همان نسخه از Bootstrap را که برای گرفتن نتایج موردنظر از خروجی نیاز دارید، استفاده کنید.
برای به روزرسانی بسته Bootstrap، شماره نسخه را در فایل bower.json تغییر دهید. مانند کد زیر:
{ "name": "asp.net", "private": true, "dependencies": { "bootstrap": "4.0.0-alpha.6" } }
توسعه نرم افزار وب اغلب میتواند یک فرآیند تکراری باشد، جایی که تغییرات کوچکی را به ویووها یا کلاسها میدهید و برنامه را اجرا میکنید تا اثرات آن را آزمایش کنید. MVC و ویژوال استودیو همکاری میکنند تا از این رویکرد مداوم استفاده کنند تا تغییرات را سریعتر و آسانتر ببینید.
اعمال تغییرات در Razor Views
در زمان توسعه، تغییراتی که به Razor View اعمال میشوند، به محض رسیدن درخواستهای HTTP، از مرورگر دریافت میشوند. برای اینکه ببینید چطور کار میکند، برنامه را با انتخاب گزینه Start Debugging از منوی Debug اجرا کنید و هنگامیکه یک برگهی مرورگر باز شد و اطلاعات نمایش داده شد، تغییراتی را که در زیر نمایش میدهم در فایل Index.cshtml اعمال کنید.
@model IEnumerable<WorkingWithVisualStudio.Models.Product> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>>Working with Visual Studio</title> </head> <body> <h3>Products</h3> <table> <thead> <tr> <td>Name</td> <td>Price</td> </tr> </thead> <tbody> @foreach (var p in Model) { <tr> <td>@p.Name</td> <td>@($"{p.Price:C2}")</td> </tr>} </tbody> </table> </body> </html>
اعمال تغییرات در کلاسهای #C
برای کلاسهای #C، از جمله کنترلرها و مدلها، دو رویکرد موجود را که از طریق آیتمهای مختلف در منوی Debug انتخاب میشوند، شرح میدهم:
Start Without Debugging
تغییرات در کلاسها در پروژه به صورت خودکار زمانیکه یک درخواست HTTP دریافت میشود، برای مشاهدهی یک تجربهی توسعهی پویا، کامپایل میشوند. در این حالت برنامه بدون امکانات دیباگ و اشکالزادیی اجرا میشود.
Start Debugging
به شما اجزا میدهد صریح تغییرات را کامپایل کنید و برنامه را اجرا کنید ، بررسی مشکلات هم در زمان اجرا پروژه انجام میگیرد.به شما اجرا بررسی و تجزیه و تحلیل هر گونه مشکل در کد را میدهد.
کامپایل خودکار کلاس ها
در طول توسعه عادی، این چرخه کامپایل سریع به شما اجازه میدهد تا فورا تاثیر تغییرات خود را ببینید؛ حالا میتواند این تغییر اضافه نمودن یک اکشن جدید و یا ویرایش نمایش اطلاعات یک Model باشد. برای ارائهی این نوع از توسعه، ویژوال استودیو به محض رسیدن درخواست HTTP از مرورگر، تغییرات را دریافت و کلاسها را به صورت خودکار کامپایل میکند. برای دیدن اینکه چگونه کار میکند، گزینه Start Without Debugging را از منوی Debug در ویژوال استودیو انتخاب کنید. هنگامیکه مرورگر دادههای برنامه را نمایش میدهد، تغییرات زیر را در فایل Home controller ایجاد کنید:
namespace WorkingWithVisualStudio.Controllers { public class HomeController : Controller { public IActionResult Index() => View(SimpleRepository.SharedRepository.Products .Where(p => p.Price < 50)); } }
namespace WorkingWithVisualStudio.Models { public class SimpleRepository { private static SimpleRepository sharedRepository = new SimpleRepository(); private Dictionary<string, Product> products = new Dictionary<string, Product>(); public static SimpleRepository SharedRepository => sharedRepository; public SimpleRepository() { var initialItems = new[] { new Product { Name = "Kayak", Price = 275M }, new Product { Name = "Lifejacket", Price = 48.95M }, new Product { Name = "Soccer ball", Price = 19.50M }, new Product { Name = "Corner flag", Price = 34.95M } }; foreach (var p in initialItems) { AddProduct(p); } products.Add("Error", null); } public IEnumerable<Product> Products => products.Values; public void AddProduct(Product p) => products.Add(p.Name, p); } }
namespace WorkingWithVisualStudio { public class Startup { // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseDeveloperExceptionPage(); } } } }
استفاده از Debugger
ویژوال استادیو از اجرای یک برنامه MVC با استفاده از Debugger نیز پشتیبانی میکند که اجازه میدهد برنامه برای بررسی وضعیت نرم افزار و دنبال کردن درخواستی که به برنامه ارسال میشود، متوقف و از این طریق، پیگیری شود. این مورد نیاز به یک سبک متفاوت از توسعه را دارد. زیرا تغییراتی را در کلاسهای #C میدهیم، تا زمانیکه برنامه مجددا راه اندازی نشود، اعمال نمیشوند ( هرچند تغییرات Razor View هنوز هم به صورت خودکار اعمال میشوند). این سبک توسعه به همراه استفادهی از ویژگی کامپایل خودکار نیست؛ اما Debugger ویژوال استودیو عالی است و میتواند بینش عمیقتری را در مورد نحوهی کارکرد برنامه داشته باشد. برای اجرای برنامه با استفاده Debugger، در ویژوال استودیو از منوی Debug گزینهی Start Debugging را انتخاب کنید. ویژوال استودیو کلاسهای #C در پروژه را قبل از اجرای برنامه کامپایل میکند. اما شما همچنان میتوانید با استفاده از موارد موجود در منوی Build، کد خود را به صورت دستی نیز کامپایل کنید.
Debugger عامل اصلی خطا را نمایش نمیدهد؛ تنها مکان آنرا آشکار میکند. عبارتیکه ویژوال استودیو برجسته میکند نشان میدهد که این مشکل زمانی رخ میدهد که فیلتر کردن اشیاء با استفاده از LINQ انجام شود، اما یک کار کوچک لازم است تا از جزئیات کاسته شود و به علت اصلی برسد.
Breakpoint عبارتی است که به Debugger میگوید تا برنامه را متوقف کند و کنترل دستی برنامه را به برنامه نویس میدهد. شما میتوانید وضعیت برنامه را بازبینی کنید و ببینید چه اتفاقی میافتد و به صورت اختیاری روند کاری را دوباره ادامه دهید.
برای ایجاد Breakpoint، روی عبارت راست کلیک کنید و در منوی باز شده، گزینه Breakpoint -> Insert Breakpoint را انتخاب کنید.
به عنوان مثال: یک Breakpoint به خط کد AddProduct در کلاس SimpleRepository اعمال کنید. همانطور که در شکل زیر نمایش داده میشود:
برنامه را اجرا کنید؛ با استفاده از Debug -> Start Debugging و یا با استفاده از Debug -> Restart برنامه را Restart میکنیم. در طی درخواست اولیه HTTP، برنامه اجرا میشود تا به نقطهای که Break Point دارد برسد و در آنجا برنامه متوقف میشود. در این نقطه، شما میتوانید از آیتمهای منوی Debug ویژوال استودیو یا کنترلها در بالای پنجره، برای کنترل اجرای برنامه استفاده کنید؛ یا از نمایشهای مختلف Debugger موجود از طریق Debug -> Windows برای بررسی وضعیت برنامه استفاده میکنیم.
اگر اشارهگر ماوس را بر روی پارامتر p به متد AddProduct که توسط Debugger برجسته شدهاست، حرکت دهید، یک فرم ظاهر خواهد شد که ارزش فعلی p را نشان میدهد؛ همانطور که در شکل زیر نشان داده شدهاست. من یک نمونه بزرگ شده از محتویات فرم ظاهر شده را نمایش میدهم تا به راحتی بتوانید متن در آن را بخوانید.
این مورد ممکن است مؤثر به نظر نرسد، چون شیء داده در یک سازنده همانند BreakPoint تعریف شدهاست. اما این ویژگیها برای هر متغیری کار میکند. شما میتوانید مقادیر را مشاهده کنید تا مقادیر خود و فیلد آنها را ببینید. هر مقدار دارای یک دکمه پین کوچک به سمت راست است. برای زمانیکه کد در حال اجراست، برای نظارت بر مقدار، از آن استفاده کنید.
اشارهگر ماوس را بر روی متغیر P قرار دهید و مرجع محصول را پین کنید. مرجع پیوست شده را باز کنید تا بتوانید نام و قیمت را نیز ببینید؛ مانند شکل زیر:
گزینه Continue را از منوی Debug در ویژوال استادیو انتخاب کنید تا برنامه ادامه پیدا کند. از آنجا که در برنامه حلقه Foreach وجود دارد، برنامه که دوباره اجرا میشود، وقتی مجددا به BreakPoint رسید، برنامه متوقف میشود. مقادیر پین شده در شکل زیر نشان میدهند که چگونه متغیر P و خواص آن تغییر میکنند.
استفاده از پنجره متغیرهای محلی ( Local Windows )
یکی از ویژگیهای مرتبط، پنجره Locals است که با انتخاب گزینهی منوی Debug ➤ Windows ➤ Locals باز میشود. پنجرهی Locals، مقدار متغیرها را به شکلی مشابه پنل پین شده نمایش میدهد، اما در اینجا تمام اشیاء محلی را نسبت به Break Point نمایش میدهد؛ همانطور که در شکل زیر نشان داده شدهاست:
هربار که Continue را انتخاب میکنید، اجرای برنامه ادامه یافته و یک شیء دیگر توسط حلقه foreach پردازش میشود.
اگر ادامه دهید، در زمان ویرایش کد، در هر دو پنجره Locals و در مقادیر پنل پین شده، شما مرجع Null را میبینید. برای کنترل اجرای برنامه، میتوانید جریان را از طریق کد خود در دیباگر دنبال کنید و احساس کنید که چه اتفاقی میافتد.
استفاده از Browser Link
ویژگی Browser Link میتواند روند توسعه را با قرار دادن یک یا چند مرورگر تحت کنترل ویژوال استودیو، ساده سازی کند. این ویژگی مخصوصا مفید است اگر شما نیاز به دیدن اثر تغییرات را در طیف وسیعی از مرورگرها دارید. قابلیت Browser Link با و یا بدون Debugger کار میکند و به این معنا است که میتوانیم هر فایلی را در پروژه تغییر دهیم و تاثیر تغییر را بدون نیاز به تغییری در مرورگر مشاهده کنیم.
راه اندازی BrowserLink
برای فعال کردن Browser Link باید در کلاس Startup، تنظیمات را تغییر دهید. مانند کد زیر:
namespace WorkingWithVisualStudio { public class Startup { // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseBrowserLink(); app.UseDeveloperExceptionPage(); } app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); } } }
استفاده از Browser Link
برای درک اینکه Browser Link چگونه کار میکند، در ویژوال استودیو گزینه Start Without Debugging را از منوی Debug انتخاب میکنیم. ویژوال استودیو برنامه را اجرا میکند و یک برگه جدید مرورگر را برای نمایش نتیجه باز میکند. با بازبینی HTML ارسال شده به مرورگر، شما خواهید دید که حاوی بخش دیگری مانند این است:
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>>Working with Visual Studio</title> </head> <body> <h3>Products</h3> <table> <thead> <tr><td>Name</td><td>Price</td></tr> </thead> <tbody> <tr><td>Lifejacket</td><td>£48.95</td></tr> <tr><td>Soccer ball</td><td>£19.50</td></tr> <tr><td>Corner flag</td><td>£34.95</td></tr> </tbody> </table> <!-- Visual Studio Browser Link --> <script type="application/json" id="__browserLink_initializationData"> {"requestId":"968949d8affc47c4a9c6326de21dfa03","requestMappingFromServer":false} </script> <script type="text/javascript" src="http://localhost:55356/d1a038413c804e178ef009a3be07b262/browserLink" async="async"></script> <!-- End Browser Link --> </body> </html>
ویژوال استادیو یک جفت عناصر اسکریپت را به HTML فرستاده شدهی به مرورگر اضافه میکند که برای بازکردن یک اتصال طولانی مدت HTTP با سرور برنامه کاربردی است؛ تا زمانیکه ویژوال استودیو مجددا برنامه را ریاستارت کند. کد زیر تغییر در فایل Index و تاثیر استفاده از Browser Link را نشان میدهد.
@model IEnumerable<WorkingWithVisualStudio.Models.Product> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>>Working with Visual Studio</title> </head> <body> <h3>Products</h3> <p>Request Time: @DateTime.Now.ToString("HH:mm:ss")</p> <table> <thead> <tr> <td>Name</td> <td>Price</td> </tr> </thead> <tbody> @foreach (var p in Model) { <tr> <td>@p.Name</td> <td>@($"{p.Price:C2}")</td> </tr>} </tbody> </table> </body> </html>
کد جاوا اسکریپتی که در HTML ارسال شده به مرورگر جاسازی شده، صحفه را دوباره بارگذاری میکند؛ برای دیدن تاثیرات کد اضافه شده که اضافه کردن یک timestamp ساده است.
نکته: عناصر اسکریپت Browser Link فقط در پاسخهای موفق جاسازی شده است. به این معنا که اگر یک خطا هنگام کامپایل در هنگام اجرا کردن یک Razor View یا مدیریت یک درخواست ایجاد شود، اتصال بین مرورگر و ویژوال استودیو از بین میرود و شما بعد از حل مشکل باید صفحه را مجدد بارگذاری کنید.
استفاده از مرورگرهای متعدد
Browser Link میتواند برای نمایش یک برنامه در مرورگرهای متعددی به طور همزمان استفاده شود و میتواند زمانی مفید باشد که شما میخواهید تفاوتهای پیاده سازی را بین مرورگرهای مختلف کنترل کنید و یا ببینید که چگونه یک برنامه بر روی ترکیبی از مرورگرهای دسکتاپ و تلفن همراه ارائه میشود.
برای انتخاب مرورگرهایی که استفاده میشوند، مرورگر را با استفاده از دکمه IIS Express در نوار ابزار ویژوال استودیو، انتخاب کنید؛ همانطور که در شکل زیر نشان داده شده است.
ویژوال استادیو معمولا مرورگرهای رایجی را که نصب میشوند، نمایش میدهد. اما شما میتوانید با استفاده از دکمهی Add، برای اضافه کردن مرورگری که به صورت خودکار لیست نشده نیز استفاده کنید. همچنین میتوانید ابزار تست شخص ثالث مانند Browser Stack را نیز راه اندازی کنید که مرورگرها را بر روی سرویسهای ابری میزبان ( cloud-hosted ) و ماشینهای مجازی اجرا میکند.
من سه مرورگر را در شکل انتخاب کردم: Chrome ، Internet Explorer و Edge. با کلیک بر روی دکمه Browse، فعالیت هر سه مرورگر شروع میشود و باعث میشود URL مثال برنامه را بارگذاری کند؛ همانطور که در شکل نشان داده شده است.
با استفاده از منوی Browser Link Dashboard، شما میتوانید ببینید که چه مرورگرهایی در Browser Link انتخاب شدهاند. داشبورد آن نشانی اینترنتی نمایش داده شده توسط هر مرورگر را نشان میدهد و در اینجا هر مرورگر را میتوان به صورت جداگانه رفرش کرد.
آماده سازی جاوا اسکریپت و CSS برای استقرار
هنگامی که Client-Side بخشی از یک برنامه وب را ایجاد میکنید، معمولا تعدادی از فایلهای جاوا اسکریپت و CSS سفارشی را تهیه میکنید که برای تکمیل آنها، از بستههای نصب شدهی توسط Bower استفاده میشود. این فایلها نیاز به پردازش دارند تا آنها را برای تحویل در یک محیط تولید، بهینه سازی کنند تا تعداد درخواستهای HTTP و میزان پهنای باند شبکه مورد نیاز برای ارسال آنها به مشتری، به حداقل برسد. این فرآیند به عنوان بسته بندی شناخته میشود.
فعال کردن تحویل محتوای استاتیک
ASP.Net Core شامل پشتیبانی از ارائه فایلهای استاتیک از پوشه wwwroot به مشتریان است. اما این امکان به صورت پیشفرض در زمان ایجاد یک پروژهی خالی جدید فعال نیست و شما باید با قرار دادن عبارتی در فایل StartUp آن را فعال کنید؛ مانند کد زیر:
namespace WorkingWithVisualStudio { public class Startup { // This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseBrowserLink(); app.UseStaticFiles(); app.UseDeveloperExceptionPage(); } app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); } } }
اضافه کردن محتوای استاتیک به پروژه
برای نشان دادن فرآیند بسته بندی، من نیاز به اضافه کردن تعدادی محتوای استاتیک به پروژه و یکی کردن آنها با برنامهی نمونه را دارم. برای این منظور ابتدا یک پوشهی جدید را به نام wwwroot/css ایجاد کنید که محل متداولی برای فایلهای سفارشی CSS است. من فایلی را به نام First.css با استفاده از قالب آیتم Style Sheet اضافه کردم؛ همانطور که در شکل زیر نشان داده شده است. قالب Style Sheet در مسیر Asp.Net Core -> Web -> Content Section وجود دارد.
فایل First.Css را ویرایش کنید و محتوای زیر را در آن قرار دهید.
h3 { } table, td { border: 2px solid black; border-collapse: collapse; padding: 5px; }
فایلهای جاوا اسکریپت معمولا در پوشه wwwroot/js قرار میگیرند. من این پوشه را ایجاد کردم. فایلهای جاوا اسکریپت را میتوانید در مسیر Asp.Net Core -> Web -> Script انتخاب کنید. همانطور که در شکل زیر نشان داده شده است.
من کد جاوا اسکریپتی ساده زیر را به این فایل جدید اضافه کردم؛ همانطور که در لیست نشان داده شده است.
document.addEventListener("DOMContentLoaded", function () { var element = document.createElement("p"); element.textContent = "This is the element from the third.js file"; document.querySelector("body").appendChild(element); });
من به بیش از یک فایل جاوا اسکریپت نیاز دارم. بنابراین فایل دیگری را به نام fourth.js نیز در پوشه wwwroot ایجاد میکنم و محتوای زیر را در آن قرار میدهم.
document.addEventListener("DOMContentLoaded", function () { var element = document.createElement("p"); element.textContent = "This is the element from the fourth.js file"; document.querySelector("body").appendChild(element); });
به روز رسانی View
گام نهایی، به روز رسانی فایل Index.cshtml برای استفاده از Css و فایل جاوا اسکریپت است. کدهای آن در زیر نشان داده شده است:
@model IEnumerable<WorkingWithVisualStudio.Models.Product> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>>Working with Visual Studio</title> <link rel="stylesheet" href="css/first.css" /> <link rel="stylesheet" href="css/second.css" /> <script src="js/third.js"></script> <script src="js/fourth.js"></script> </head> <body> <h3>Products</h3> <p>Request Time: @DateTime.Now.ToString("HH:mm:ss")</p> <table> <thead> <tr> <td>Name</td> <td>Price</td> </tr> </thead> <tbody> @foreach (var p in Model) { <tr> <td>@p.Name</td> <td>@($"{p.Price:C2}")</td> </tr>} </tbody> </table> </body> </html>
یکی کردن فایلهای سمت کلاینت در برنامههای MVC
در حال حاضر چهار فایل استاتیک وجود دارند و مرورگر باید چهار درخواست را برای دریافت فایلهای استاتیک ایجاد کند و هر یک از این فایلها نیازمند پهنای باند بیشتری است که باید به مشتری تحویل داده شود؛ زیرا آنها حاوی فضای سفید و نام متغیرها هستند که برای توسعه دهندهها معنا دار هستند؛ اما برای مرورگرها اهمیتی ندارند.
ترکیب فایلهایی هم نوع، تلفیق نامیده میشود و در آن کار ساختن فایلها به صورتی کوچکتر انجام میشود. هر دوی این کارها در برنامه Asp.Net Core MVC توسط Bundler & Minifier مخصوص ویژوال استودیو انجام میشود.
نصب افزونههای ویژوال استودیو
دسته بندی و یکی کردن فایلها
پس از نصب افزونه، ویژوال استودیو را مجددا راه اندازی کنید و پروژه نمونه را باز کنید. با افزودن افزونه، میتوانید چندین فایل هم نوع را در Solution Explorer انتخاب کنید. آنها را با یکدیگر ترکیب کرده و محتویات آنها را کوچکتر کنید. به عنوان مثال فایلهای First.css و Second.css را در Solution Explorer را انتخاب و کلیک راست کرده و سپس Bundler & Minifier -> Bundle and Minify Files را از منوی باز شده انتخاب کنید . همانطور که در شکل زیر نشان داده شده است.
فایل خروجی را با عنوان bundle.css ذخیره کنید. در Solution Explorer یک بسته جدید ایجاد میشود. اگر شما این فایل را باز کنید، خواهید دید که محتویات هر دو فایل CSS جداگانه ترکیب شدهاند و تمام فضای سفید آنها حذف شدهاست. البته شما نمیخواهید به طور مستقیم با این فایل کار کنید؛ اما این فایل کوچکتر است و فقط یک اتصال HTTP را برای ارائه CSS styles به مشتری نیاز دارد.
مراحل قبل را برای فایلهای third.js و fourth.js تکرار کنید تا فایلهای جدید bundle.js و bundle.min.js در پوشه wwwroot ایجاد شوند.
احتیاط: اطمینان حاصل کنید که فایلها را به ترتیبی که توسط مرورگر بارگیری میشوند، انتخاب کنید تا ترتیب دستورات Styleها یا دستورات کد را در فایلهای خروجی حفظ کنید. به عنوان مثال دقت کنید که فایل third.js قبل از فایل fourth.js انتخاب شده باشد تا مطمئن باشید دستورات به ترتیب و به درستی اجرا میشوند.
@model IEnumerable<WorkingWithVisualStudio.Models.Product> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>>Working with Visual Studio</title> <link rel="stylesheet" href="css/bundle.min.css" /> <script src="js/bundle.min.js"></script> </head> <body> <h3>Products</h3> <p>Request Time: @DateTime.Now.ToString("HH:mm:ss")</p> <table> <thead> <tr> <td>Name</td> <td>Price</td> </tr> </thead> <tbody> @foreach (var p in Model) { <tr> <td>@p.Name</td> <td>@($"{p.Price:C2}")</td> </tr>} </tbody> </table> </body> </html>
همان زمان که عملیات جمع آوری و یکی کردن را انجام میدهید، رکورد عملیات انجام شده را در فایلی به نام bundleconfig.json در پوشهی wwwroot پروژه نگهداری میکند. در اینجا یک نمونه از فایل تولیدی را مشاهده میکنید:
[ { "outputFileName": "Views/wwwroot/css/bundle.css", "inputFiles": [ "Views/wwwroot/css/First.css", "Views/wwwroot/css/second.css" ] }, { "outputFileName": "Views/wwwroot/js/bundle.js", "inputFiles": [ "Views/wwwroot/js/fourth.js", "Views/wwwroot/js/third.js" ] } ]
خلاصه
در این بخش من توضیحاتی را در مورد ویژگیهایی که ویژوال استودیو برای طراحی برنامههای وب به توسعه دهندهها ارائه میدهد، شرح دادم که شامل کامپایل خودکار کلاسها، Browser Link و یکی کردن فایلهای سمت کلاینت ( bundling and minification ) بود.
<script> let src = 'https://svelte.dev/tutorial/image.gif'; let name = 'Rick Astley'; </script> <img src={src} alt="{name} dancing">
- نکته اول : اگر در تگ img مقدار alt را وارد نکنیم و یا alt در این تگ وجود نداشته باشد، یک هشدار توسط کامپایلر svelte برای ما با عنوان <img> element should have an alt attribute> ایجاد میشود. زمان ساخت یک برنامه بسیار مهم است تا قوانین نوشتن یک کد html خوب را رعایت کنیم تا برای تمامی کاربران احتمالی برنامه قابل استفاده باشد. در همین مثال با ایجاد یک هشدار Svelte تلاش میکند که ما را از اشتباه در نوشتن کد html مطلع سازد.
- نکته دوم : اگر نام یک آبجکت تعریف شده و یک attribute، برابر باشد میتوانیم از نسخه کوتاه شده یا Shorthand attributes در svelte استفاده کنیم. به طور مثال در مثال بالا میتوانیم از کد زیر در خط 6 استفاده کنیم.
<img {src} alt="{name} dancing">
<script> export let siteName = "dotnettips"; </script> <p>this is a nested component for third tutorial on {siteName}</p>
<script> import Nested from "./Nested.svelte"; export let name; </script> <h1>Hello {name}!</h1> <Nested siteName="dotnettips.info" />
Hello world! this is a nested component for third tutorial on dotnettips.info
در مثال بالا ما یک کامپوننت جدید را ایجاد کرده و از طریق دستور import به App.svelte اضافه کردیم. نکتهای که در اینجا وجود دارد، نحوه مقدار دهی props در کامپوننتها است. اگر به خط 9 دقت کنیم، کامپوننت ما از طریق تگ جدیدی با نام (Nested) به بدنه html برنامه اضافه شده است که یک attribute به نام siteName دارد. siteName متغیر export شده در کامپوننت Nested.svelte است که در کامپوننتها به این صورت مقدار دهی میشود. قبلا نحوه مقدار دهی این خصیصهها را در فایلهای جاوا اسکریپت مشاهده کرده بودیم. نکته دیگری که باید به آن دقت داشت این است که خصیصه siteName مقدار پیش فرض dotnettips را در Nested.svelte به خود اختصاص داده بود. به همین جهت اگر ما siteName را هنگام استفاده از کامپوننت مقدار دهی نکنیم، از مقدار پیش فرض خود استفاده خواهد کرد. ولی اینجا ما با مقدار دهی آن، siteName را به dotnettips.info تغییر دادهایم.
نکته مهم : دقت داشته باشید کامپوننتهای شما همیشه باید با حروف بزرگ شروع شوند؛ به طور مثال در صورت نوشتن <nested/> محتوای کامپوننت نمایش داده نخواهد شد. svelte، از طریق زیر نظر گرفتن حروف کوچک و بزرگ در ابتدای تگها، بین تگهای html و کامپوننتها تمایز قائل میشود.
Spread props :
تا اینجا به صورت خلاصه با props یا خصیصهها آشنا شدهاید و دیدیم که با export کردن یک متغیر در یک کامپوننت، میتوانیم آن را هنگام استفاده مقدار دهی نماییم. برای اینکه تمرینی هم باشد با توجه به مطالبی که تاکنون گفته شده، پروژهی جدیدی را ایجاد کنید و محتوای App.svelte را مانند کد زیر تغییر دهید.
<script> import Info from './Info.svelte'; const pkg = { name: 'svelte', version: 3, speed: 'blazing', website: 'https://svelte.dev' }; </script> <Info name={pkg.name} version={pkg.version} speed={pkg.speed} website={pkg.website}/>
همانطور که در خط دوم کد میبینید، کامپوننتی به نام Info.svelte به این بخش اضافه شدهاست. این کامپوننت را با محتوای زیر ایجاد نمایید:
<script> export let name; export let version; export let speed; export let website; </script> <p> The <code>{name}</code> package is {speed} fast. Download version {version} from <a href="https://www.npmjs.com/package/{name}">npm</a> and <a href={website}>learn more here</a> </p>
اگر برنامه را اجرا کنید یک چنین خروجی را مشاهده خواهید کرد:
The svelte package is blazing fast. Download version 3 from npm and learn more here
<Info {...pkg}/>
<script> let count = 0; function handleClick() { count += 1; } </script> <p>Count : {count}</p> <button on:click={handleClick}> Clicked {count} {count === 1 ? 'time' : 'times'} </button>
<script> let count = 0; let doubled = count * 2; function handleClick() { count += 1; } </script> <button on:click={handleClick}> Clicked {count} {count === 1 ? 'time' : 'times'} </button> <p>{count} doubled is {doubled}</p>
$: doubled = count * 2;
$: console.log(`the count is ${count}`);
$: { console.log(`the count is ${count}`); alert(`I SAID THE COUNT IS ${count}`); }
$: if (count >= 10) { alert(`count is dangerously high!`); count = 9; }
<script> let numbers = [1, 2, 3, 4]; function addNumber() { let newNumber = numbers.length + 1; numbers.push(newNumber); } $: sum = numbers.reduce((t, n) => t + n, 0); </script> <p>{numbers.join(' + ')} = {sum}</p> <button on:click={addNumber}>Add a number</button>
function addNumber() { let newNumber = numbers.length + 1; numbers.push(newNumber); numbers = numbers; }
function addNumber() { let newNumber = numbers.length + 1; numbers = [...numbers, newNumber]; }
مروری بر Two way bindings :
<script> let name = ""; function updateName(event) { name = event.target.value; } </script> <h4>My Name Is {name}</h4> <input value={name} on:input={updateName} />
<script> let name = ""; </script> <h4>My Name Is {name}</h4> <input bind:value={name} />
{#if condition} <!-- you html codes ... --> {/if}
<script> let user = { loggedIn: false }; function toggle() { user.loggedIn = !user.loggedIn; } </script> {#if user.loggedIn} <button on:click={toggle}> Log out </button> {/if} {#if !user.loggedIn} <button on:click={toggle}> Log in </button> {/if}
{#if condition} <!-- you html code when condition is true --> {:else} <!-- you html code when condition is false --> {/if}
{#if user.loggedIn} <button on:click={toggle}> Log out </button> {:else} <button on:click={toggle}> Log in </button> {/if}
{#if condition} <!-- you html code when condition is true --> {:else if condition2} <!-- you html code when condition2 is true --> {:else} <!-- you html code when condition and condition2 are false --> {/if}
{#each list as item} <!-- you html code per each item in list --> {/each}
<script> let cats = [ { id: 'J---aiyznGQ', name: 'Keyboard Cat' }, { id: 'z_AbfPXTKms', name: 'Maru' }, { id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' } ]; </script> <h1>The Famous Cats of YouTube</h1> <ul> {#each cats as cat} <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}"> {cat.name} </a></li> {/each} </ul>
<ul> {#each cats as {id,name}} <li><a target="_blank" href="https://www.youtube.com/watch?v={id}"> {name} </a></li> {/each} </ul>
<ul> {#each cats as { id, name }, i} <li><a target="_blank" href="https://www.youtube.com/watch?v={id}"> {i + 1}: {name} </a></li> {/each} </ul>
نکته : در این بخش من سعی کردم تا حدودی به ترتیب بخش آموزشی خود وبسایت Svelte، موارد را بیان کنم؛ ولی با توجه به اینکه شاید دوستان ترجیح بدهند روش آموزشی خود آن وبسایت که امکان تغییر و نوشتن کد را هم محیا کرده است، امتحان کنند لینک آن را به اشتراک میگذارم.
حذف فضاهای خالی در خروجی صفحات ASP.NET MVC
- در مرورگرهای قدیمی گاها باعث کرش و بسته شدن آنی برنامه میشد.
- کدهای جاوا اسکریپت یا CSS اگر داخل صفحه قرار داشتند، مشکل پیدا میکردند.
- گاهی از همین فضاهای خالی برای اندکی ایجاد فاصله بین عناصر ممکن است استفاده شود. اینها با حذف فواصل خالی به هم میریزند.
- بعضی مرورگرها علاقمند هستند که doctype ابتدای یک فایل HTML، حتما در یک سطر مجزا ذکر شود.
- زمانیکه شما codeایی در صفحه تعریف میکنید، برای پردازش صحیح تگ PRE توسط مرورگر، مهم است که سطر جدیدی وجود داشته باشد، یا فاصله بین عناصر حفظ شود. در غیراینصورت کد نمایش داده شده به هم میریزد.
- الگوریتمهای فشرده سازی اطلاعات مانند GZIP یا Deflate، حداقل کاری را که به خوبی انجام میدهند، فشرده سازی فواصل خالی است.
نگاهی به SignalR Clients
مصرف کنندگان یک Hub میتوانند انواع و اقسام برنامههای کلاینت مانند jQuery Clients و یا حتی یک برنامه کنسول ساده باشند و همچنین Hubهای دیگر نیز قابلیت استفاده از این امکانات Hubهای موجود را دارند. تیم SignalR امکان استفاده از Hubهای آنرا در برنامههای دات نت 4 به بعد، برنامههای WinRT، ویندوز فون 8، سیلورلایت 5، jQuery و همچنین برنامههای CPP نیز مهیا کردهاند. به علاوه گروههای مختلف نیز با توجه به سورس باز بودن این مجموعه، کلاینتهای iOS Native، iOS via Mono و Android via Mono را نیز به این لیست اضافه کردهاند.
بررسی کلاینتهای jQuery
با توجه به پروتکل مبتنی بر JSON سیگنالآر، استفاده از آن در کتابخانههای جاوا اسکریپتی همانند jQuery نیز به سادگی مهیا است. برای نصب آن نیاز است در کنسول پاور شل نوگت، دستور زیر را صادر کنید:
PM> Install-Package Microsoft.AspNet.SignalR.JS
با استفاده از افزونه SignalR jQuery، به دو طریق میتوان به یک Hub اتصال برقرار کرد:
الف) استفاده از فایل proxy تولید شده آن (این فایل، در زمان اجرای برنامه تولید میشود و یا امکان استفاده از آن به کمک ابزارهای کمکی نیز وجود دارد)
نمونهای از آنرا در قسمت قبل ملاحظه کردید؛ همان فایل تولید شده در مسیر /signalr/hubs برنامه. به نوعی به آن Service contract نیز گفته میشود (ارائه متادیتا و قراردادهای کار با یک سرویس Hub). این فایل همانطور که عنوان شد به صورت پویا در زمان اجرای برنامه ایجاد میشود.
امکان تولید آن توسط برنامه کمکی signalr.exe نیز وجود دارد؛ برای دریافت آن میتوان از طریق NuGet اقدام کرد (بسته Microsoft.AspNet.SignalR.Utils) که نهایتا در پوشه packages قرار خواهد گرفت. نحوه استفاده از آن نیز به صورت زیر است:
Signalr.exe ghp http://localhost/
ب) بدون استفاده از فایل proxy و به کمک روش late binding (انقیاد دیر هنگام)
برای کار با یک Hub از طریق jQuery مراحل ذیل باید طی شوند:
1) ارجاعی به Hub باید مشخص شود.
2) روالهای رخدادگردان تنظیم گردند.
3) اتصال به Hub برقرار گردد.
4) متدی فراخوانی شود.
در اینجا باید دقت داشت که امکانات Hub به صورت خواص
$.connection
$.connection.chatHub
خوب، تا اینجا فرض بر این است که یک پروژه خالی ASP.NET را آغاز و سپس فرمان نصب Microsoft.AspNet.SignalR.JS را نیز همانطور که عنوان شد، صادر کردهاید. در ادامه یک فایل ساده html را به نام chat.htm، به این پروژه جدید اضافه کنید (برای استفاده از کتابخانه جاوا اسکریپتی SignalR الزامی به استفاده از صفحات کامل پروژههای وب نیست).
<!DOCTYPE> <html> <head> <title></title> <script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script> <script src="Scripts/jquery.signalR-1.0.1.min.js" type="text/javascript"></script> <script src="http://localhost:1072/signalr/hubs" type="text/javascript"></script> </head> <body> <div> <input id="txtMsg" type="text" /><input id="send" type="button" value="send msg" /> <ul id="messages"> </ul> </div> <script type="text/javascript"> $(function () { var chat; $.connection.hub.logging = true; //اطلاعات بیشتری را در جاوا اسکریپت کنسول مرورگر لاگ میکند chat = $.connection.chat; //این نام مستعار پیشتر توسط ویژگی نام هاب تنظیم شده است chat.client.hello = function (message) { //متدی که در اینجا تعریف شده دقیقا مطابق نام متد پویایی است که در هاب تعریف شده است //به این ترتیب سرور میتواند کلاینت را فراخوانی کند $("#messages").append("<li>" + message + "</li>"); }; $.connection.hub.start(/*{ transport: 'longPolling' }*/); // فاز اولیه ارتباط را آغاز میکند $("#send").click(function () { // Hub's `SendMessage` should be camel case here chat.server.sendMessage($("#txtMsg").val()); }); }); </script> </body> </html>
توضیحات:
همانطور که ملاحظه میکنید ابتدا ارجاعاتی به jquery و jquery.signalR-1.0.1.min.js اضافه شدهاند. سپس نیاز است مسیر دقیق فایل پروکسی هاب خود را نیز مشخص کنیم. اینکار با تعریف مسیر signalr/hubs انجام شده است.
<script src="http://localhost:1072/signalr/hubs" type="text/javascript"></script>
سپس ارجاعی به هاب تعریف شده، تعریف گردیده است. اگر از قسمت قبل به خاطر داشته باشید، توسط ویژگی HubName، نام chat را برگزیدیم. بنابراین connection.chat ذکر شده دقیقا به این هاب اشاره میکند.
سپس سطر chat.client.hello مقدار دهی شده است. متد hello، متدی dynamic و تعریف شده در سمت هاب برنامه است. به این ترتیب میتوان به پیامهای رسیده از طرف سرور گوش فرا داد. در اینجا، این پیامها، به li ایی با id مساوی messages اضافه میشوند.
سپس توسط فراخوانی متد connection.hub.start، فاز negotiation شروع میشود. در اینجا حتی میتوان نوع transport را نیز صریحا انتخاب کرد که نمونهای از آن را به صورت کامنت شده جهت آشنایی با نحوه تعریف آن مشاهده میکنید. مقادیر قابل استفاده در آن به شرح زیر هستند:
- webSockets - forverFrame - serverSentEvents - longPolling
اکنون به صورت جداگانه یکبار برنامه hub را در مرورگر باز کنید. سپس بر روی فایل chat.htm کلیک راست کرده و گزینه مشاهده آن را در مرورگر نیز انتخاب نمائید (گزینه View in browser منوی کلیک راست).
خوب! پروژه کار نمیکند! برای اینکه مشکلات را بهتر بتوانید مشاهده کنید نیاز است به JavaScript Console مرورگر خود مراجعه نمائید. برای مثال در مرورگر کروم دکمه F12 را فشرده و برگه Console آنرا باز کنید. در اینجا اعلام میکند که فاز negotiation قابل انجام نیست؛ چون مسیر پیش فرضی را که انتخاب کرده است، همین مسیر پروژه دومی است که اضافه کردهایم (کلاینت ما در پروژه دوم قرار دارد و نه در همان پروژه اول هاب).
برای اینکه مسیر دقیق hub را در این حالت مشخص کنیم، سطر زیر را به ابتدای کدهای جاوا اسکریپتی فوق اضافه نمائید:
$.connection.hub.url = 'http://localhost:1072/signalr'; //چون در یک پروژه دیگر قرار داریم
using System; using System.Web; using System.Web.Routing; using Microsoft.AspNet.SignalR; namespace SignalR02 { public class Global : HttpApplication { protected void Application_Start(object sender, EventArgs e) { // Register the default hubs route: ~/signalr RouteTable.Routes.MapHubs(new HubConfiguration { EnableCrossDomain = true }); } } }
SignalR: Auto detected cross domain url. jquery.signalR-1.0.1.min.js:10 SignalR: Negotiating with 'http://localhost:1072/signalr/negotiate'. jquery.signalR-1.0.1.min.js:10 SignalR: SignalR: Initializing long polling connection with server. jquery.signalR-1.0.1.min.js:10 SignalR: Attempting to connect to 'http://localhost:1072/signalr/connect?transport=longPolling&connectionToken…NRh72omzsPkKqhKw2&connectionData=%5B%7B%22name%22%3A%22chat%22%7D%5D&tid=3' using longPolling. jquery.signalR-1.0.1.min.js:10 SignalR: Longpolling connected jquery.signalR-1.0.1.min.js:10
در برگه شبکه، مطابق شکل فوق، امکان آنالیز اطلاعات رد و بدل شده مهیا است. برای مثال در حالتیکه سرور پیام دریافتی را به کلیه کلاینتها ارسال میکند، نام متد و نام هاب و سایر پارامترها در اطلاعات به فرمت JSON آن به خوبی قابل مشاهده هستند.
یک نکته:
اگر از ویندوز 8 (یعنی IIS8) و VS 2012 استفاده میکنید، برای استفاده از حالت Web socket، ابتدا فایل وب کانفیگ برنامه را باز کرده و در قسمت httpRunTime، مقدار ویژگی targetFramework را بر روی 4.5 تنظیم کنید. اینبار اگر مراحل negotiation را بررسی کنید در همان مرحله اول برقراری اتصال، از روش Web socket استفاده گردیده است.
تمرین 1
به پروژه ساده و ابتدایی فوق یک تکست باکس دیگر به نام Room را اضافه کنید؛ به همراه دکمه join. سپس نکات قسمت قبل را در مورد الحاق به یک گروه و سپس ارسال پیام به اعضای گروه را پیاده سازی نمائید. (تمام نکات آن با مطلب فوق پوشش داده شده است و در اینجا باید صرفا فراخوانی متدهای عمومی دیگری در سمت هاب، صورت گیرد)
تمرین 2
در انتهای قسمت دوم به نحوه ارسال پیام از یک هاب به هابی دیگر اشاره شد. این MonitorHub را ایجاد کرده و همچنین یک کلاینت جاوا اسکریپتی را نیز برای آن تهیه کنید تا بتوان اتصال و قطع اتصال کلیه کاربران سیستم را مانیتور و مشاهده کرد.
پیاده سازی کلاینت jQuery بدون استفاده از کلاس Proxy
در مثال قبل، از پروکسی پویای مهیای در آدرس signalr/hubs استفاده کردیم. در اینجا قصد داریم، بدون استفاده از آن نیز کار برپایی کلاینت را بررسی کنیم.
بنابراین یک فایل جدید html را مثلا به نام chat_np.html به پروژه دوم برنامه اضافه کنید. سپس محتویات آنرا به نحو زیر تغییر دهید:
<!DOCTYPE> <html> <head> <title></title> <script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script> <script src="Scripts/jquery.signalR-1.0.1.min.js" type="text/javascript"></script> </head> <body> <div> <input id="txtMsg" type="text" /><input id="send" type="button" value="send msg" /> <ul id="messages"> </ul> </div> <script type="text/javascript"> $(function () { $.connection.hub.logging = true; //اطلاعات بیشتری را در جاوا اسکریپت کنسول مرورگر لاگ میکند var connection = $.hubConnection(); connection.url = 'http://localhost:1072/signalr'; //چون در یک پروژه دیگر قرار داریم var proxy = connection.createHubProxy('chat'); proxy.on('hello', function (message) { //متدی که در اینجا تعریف شده دقیقا مطابق نام متد پویایی است که در هاب تعریف شده است //به این ترتیب سرور میتواند کلاینت را فراخوانی کند $("#messages").append("<li>" + message + "</li>"); }); $("#send").click(function () { // Hub's `SendMessage` should be camel case here proxy.invoke('sendMessage', $("#txtMsg").val()); }); connection.start(); }); </script> </body> </html>
کلاینتهای دات نتی SignalR
تا کنون Solution ما حاوی یک پروژه Hub و یک پروژه وب کلاینت جیکوئری است. به همین Solution، یک پروژه کلاینت کنسول ویندوزی را نیز اضافه کنید.
سپس در خط فرمان پاور شل نوگت دستور زیر را صادر نمائید تا فایلهای مورد نیاز به پروژه کنسول اضافه شوند:
PM> Install-Package Microsoft.AspNet.SignalR.Client
پس از نصب آن اگر به پوشه packages مراجعه کنید، نگارشهای مختلف آنرا مخصوص سیلورلایت، دات نتهای 4 و 4.5، WinRT و ویندوز فون8 نیز میتوانید در پوشه Microsoft.AspNet.SignalR.Client ملاحظه نمائید. البته در ابتدای نصب، انتخاب نگارش مناسب، بر اساس نوع پروژه جاری به صورت خودکار صورت میگیرد.
مدل برنامه نویسی آن نیز بسیار شبیه است به حالت عدم استفاده از پروکسی در حین استفاده از jQuery که در قسمت قبل بررسی گردید و شامل این مراحل است:
1) یک وهله از شیء HubConnection را ایجاد کنید.
2) پروکسی مورد نیاز را جهت اتصال به Hub از طریق متد CreateProxy تهیه کنید.
3) رویدادگردانها را همانند نمونه کدهای جاوا اسکریپتی قسمت قبل، توسط متد On تعریف کنید.
4) به کمک متد Start، اتصال را آغاز نمائید.
5) متدها را به کمک متد Invoke فراخوانی نمائید.
using System; using Microsoft.AspNet.SignalR.Client.Hubs; namespace SignalR02.WinClient { class Program { static void Main(string[] args) { var hubConnection = new HubConnection(url: "http://localhost:1072/signalr"); var chat = hubConnection.CreateHubProxy(hubName: "chat"); chat.On<string>("hello", msg => { Console.WriteLine(msg); }); hubConnection.Start().Wait(); chat.Invoke<string>("sendMessage", "Hello!"); Console.WriteLine("Press a key to terminate the client..."); Console.Read(); } } }
نکته مهم
کلیه فراخوانیهایی که در اینجا ملاحظه میکنید غیرهمزمان هستند.
به همین جهت پس از متد Start، متد Wait ذکر شدهاست تا در این برنامه ساده، پس از برقراری کامل اتصال، کار invoke صورت گیرد و یا زمانیکه callback تعریف شده توسط متد chat.On فراخوانی میشود نیز این فراخوانی غیرهمزمان است و خصوصا اگر نیاز است رابط کاربری برنامه را در این بین به روز کنید باید به نکات به روز رسانی رابط کاربری از طریق یک ترد دیگر دقت داشت.
در پنجره ای که باز میشود ، لیست را نام گذاری میکنیم
سپس یک View ایحاد میکنیم . برای این کار از نوار Ribbon بالا ، روی List View کلیک میکینم :
سپس نامی برای این View در نظر میگیریم و این Viewرا به عنوان نمای پیش فرض انتخاب میکنیم
در این مرحله نمای نگاهی به لیست در مرور گر میاندازیم و تعدادی داده برای آزمایش در آن وارد میکنیم
حال برای اعمال تغییرات به SPD برمیگردیم و روی View ساخته شده کلیک میکنیم تا وارد محیط ویرایش آن شویم .
در این مثال میخواهم روی فیلد نام شرکت فیلتر انجام دهم
سپس برای تغییر نحوه نمایش ، روی Set Style کلیک میکنیم :
پس از اعمال تغییرات میتوانید تغییرات را در کد مشاهده کنید
برای اعمال تغییرات در خروجی و ستونهای آن ، روی Add/Remove Columns کلیک میکنیم :
برای مثال در اینجا ستون Job Title را به لیست اضافه کردم :
همچنین برای اعمال Inline Editing به عناصر لیست میتوانید روی دکمه ای با همین نام در Ribbon کلیک کنید
در ادامه میتوانید عملیات مرتب سازی و گروه بندی اطلاعات را هم تنها با چند کلیک مدیریت کنید
در اینجا گروه بندی و مرتب سازی را روی نام شرکت اعمال میکنیم :
تا کنون خروجی پیش نمایش داده شده در SPD به این صورت است :
تغییرات را ذخیره میکنیم :
و خروجی را در مرور گر مشاهده میکنید (همانطور که مشاهده میکنید ، ویرایش خطی برای آیتمها فعال شده است و همین طور گروه بندی بر اساس نام شرکت و مرتب سازی نیز اعمال شده است . همچنین رنگ سطر هایی که نام شرکت آنها Alfa است ، تغییر کرده است ) :
اکنون میخواهم قسمتی از تغییرات اعمال شده را از طریق مرور گر ( و نه SPD) تغییر دهم . برای این کار روی List در Ribbon کلیک میکنیم :
در قسمت Group by تنظیمات ستون را روی none قرار میدهیم تا گروه بندی اعمال نشود :
اکثر کنترلهای تعیین اعتبار ASP.Net بر اساس جاوا اسکریپت کار میکنند (مانند RangeValidator و امثال آن). حال اگر کاربری افزونه no script فایرفاکس را نصب کرده بود چه باید کرد؟
با استفاده از این افزونه، این نوع کنترلها از کار خواهند افتاد (چون دیگر کدهای جاوا اسکریپتی آنها اجرا نخواهند شد).
خوشبختانه برای بررسی صحت عملکرد این کنترلها در ASP.Net امکان بررسی خاصیت Page.IsValid نیز وجود دارد که در ادامه به آن خواهیم پرداخت.
صفحهی بسیار ساده ASP.Net زیر را در نظر بگیرید:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm3.aspx.cs" Inherits="testWebForms87.WebForm3" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="txtData" runat="server"></asp:TextBox>
<asp:RangeValidator ID="RangeValidator1" runat="server" ControlToValidate="txtData"
ErrorMessage="لطفا یک عدد وارد کنید" MaximumValue="100000" MinimumValue="0" SetFocusOnError="True"
Type="Integer"></asp:RangeValidator>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="txtData"
ErrorMessage="لطفا مقداری را وارد نمائید" SetFocusOnError="True"></asp:RequiredFieldValidator>
<br />
<asp:Button ID="btnSubmit" runat="server" OnClick="btnSubmit_Click" Text="Submit" />
<br />
<asp:Label ID="lblValue" runat="server"></asp:Label>
</div>
</form>
</body>
</html>
سپس برای بررسی سمت سرور عملکرد کنترلهای تعیین اعتبار در ASP.Net میتوان به صورت زیر عملکرد:
protected void btnSubmit_Click(object sender, EventArgs e)
{
if (btnSubmit.CausesValidation)
{
// Validate the Page
Page.Validate();
// Ensure Page is Valid
if (!Page.IsValid)
{
lblValue.Text = "لطفا جاوا اسکریپت را در مرورگر خود فعال نمائید";
return;
}
}
lblValue.Text = txtData.Text;
}
راه دیگر بررسی غیرفعال بودن جاوا اسکریپت در یک صفحه استفاده از روش سنتی تگ noscript است:
<noscript>
<meta http-equiv="refresh" content="0;url=http://www.google.com">
</noscript>
در پایان باید خاطر نشان کرد که هیچگاه به کنترلهای تعیین اعتبار سمت کاربر اطمینان نکنید و حتما یا از روش فوق استفاده نمائید، یا در روال submit صفحه به سرور، یکبار دیگر دادهها را به صورت دستی نیز بررسی کنید. برای مثال اگر کاربر قرار است آدرس ایمیلی را وارد کند، حتما یکبار دیگر با استفاده از regular expressions ، در سمت سرور نیز عبارت ورودی را بررسی کنید.
الف) تصاویر رو نمیتونه پیدا کنه، یا صفحه کش شده بیش از حد. قسمت «اجرای کدهای jQuery Ajax فوق، چه تغییری را در صفحه سبب میشوند؟» را بررسی کنید که چه آدرسی توسط کدهای جیکوئری در حال پردازش است.
همچنین کش شدن نتایج قبلی رو هم میشود غیرفعال کرد:
$.ajax({ cache: false /* گاهی از اوقات خصوصا برای آی ایی نیاز است */ });
<script type="text/javascript"> $(function () { // کدهای جیکوئری در اینجا }); </script>