مطالب
افزونه نویسی برای مرورگرها : فایرفاکس : قسمت اول
در دو مقاله پیشین ^ ، ^ به بررسی نوشتن افزونه در مرورگر کروم پرداختیم و اینبار قصد داریم همان پروژه را برای فایرفاکس پیاده کنیم. پس در مورد کدهای تکراری توضیحی داده نخواهد شد و برای فهم آن می‌توانید به دو مقاله قبلی رجوع کنید. همه‌ی ما فایرفاکس را به خوبی می‌شناسیم. اولین باری که این مرورگر آمد سرو صدای زیادی به پا کرد و بازار وسیعی از مرورگر‌ها را که در چنگ IE بود، به دست آورد . این سر و صدا بیشتر به خاطر امنیت و کارآیی بالای این مرورگر، استفاده از آخرین فناوری‌های تحت وب و دوست داشتنی برای طراحان وب بود. همچنین یکی دیگر از مهمترین ویژگی‌های آن، امکان سفارشی سازی آن با افزونه‌ها extensions یا addon بود که این ویژگی در طول این سال‌ها تغییرات زیادی به خود دیده است. در مورد افزونه نویسی برای فایرفاکس در سطح نت مطالب زیادی وجود دارند که همین پیشرفت‌های اخیر در مورد افزونه‌ها باعث شده خیلی از این مطالب به روز نباشند. اگر در مقاله پیشین فکر می‌کنید که کروم چقدر در نوشتن افزونه جذابیت دارد و امکانات خوبی را در اختیار شما می‌گذارد، الان دیگر وقت آن است که نظر خودتان را عوض کنید و فایرفاکس را نه تنها یک سرو گردن بلکه بیشتر از این حرف‌ها بالاتر بدانید.
شرکت موزیالا برای قدرتمندی و راحتی کار طراحان یک sdk طراحی کرده است است و شما با استفاده از کدهای موجود در این sdk قادرید کارهای زیادی را انجام دهید. برای نصب این sdk باید پیش نیازهایی بر روی سیستم شما نصب باشد:
  • نصب پایتون  2.5 یا 2.6 یا 2.7 که فعلا در سایت آن، نسخه‌ی 2.7 در دسترس هست. توجه داشته باشید که هنوز برای نسخه‌ی 3 پایتون پشتیبانی صورت نگرفته است. 
  • آخرین نسخه‌ی sdk را هم می‌توانید از این آدرس  به صورت zip و یا از این آدرس به صورت tar دانلود کنید و در صورتیکه دوست دارید به سورس آن دسترسی داشته باشید یا اینکه از سورس‌های مشارکت شده یا غیر رسمی استفاده کنید، از این صفحه آن را دریافت کنید.
بعد از دانلود sdk به شاخه‌ی bin رفته و فایل activate.bat را اجرا کنید. موقعی که فایل activate اجرا شود، باید چنین چیزی دیده شود:
(C:\Users\aym\Downloads\addon-sdk-1.17) C:\Users\aym\Downloads\addon-sdk-1.17\bin>
برای سیستم‌های عامل Linux,FreeBSD,OS X دستورات زیر را وارد کنید:
اگر یک کاربر پوسته‌ی bash هستید کلمه زیر را در کنسول برای اجرای activate بزنید:
source bin/activate
اگر کاربر پوسته‌ی بش نیستید:
bash bin/activate
نهایتا باید کنسول به شکل زیر در آید یا شبیه آن:
(addon-sdk)~/mozilla/addon-sdk >
بعد از اینکه به کنسول آن وارد شدید، کلمه cfx را در آن تایپ کنید تا راهنمای دستورات و سوییچ‌های آن‌ها نمایش داده شوند. از این ابزار میتوان برای راه اندازی فایرفاکس و اجرای افزونه بر روی آن، پکیج کردن افزونه، دیدن مستندات و آزمون‌های واحد استفاده کرد.

آغاز به کار
برای شروع، فایل‌های زیادی باید ساخته شوند، ولی نگران نباشید cfx این کار را برای شما خواهد کرد. دستورات زیر را جهت ساخت یک پروژه خالی اجرا کنید:
mkdir fxaddon
cd fxaddon
cfx init
یک پوشه را در مسیری که کنسول بالا اشاره میکرد، ساختم و وارد آن شدم و با دستور cfx init دستور ساخت یک پروژه‌ی خالی را دادم و باید بعد از این دستور، یک خروجی مشابه زیر نشان بدهد:
* lib directory created
* data directory created
* test directory created
* doc directory created
* README.md written
* package.json written
* test/test-main.js written
* lib/main.js written
* doc/main.md written
Your sample add-on is now ready for testing:
try "cfx test" and then "cfx run". Have fun!"
در این پوشه یک فایل به اسم package.json هم وجود دارد که اطلاعات زیر داخلش هست:
{
  "name": "fxaddon",
  "title": "fxaddon",
  "id": "jid1-QfyqpNby9lTlcQ",
  "description": "a basic add-on",
  "author": "",
  "license": "MPL 2.0",
  "version": "0.1"
}
این اطلاعات شامل نام و عنوان افزونه، توضیحی کوتاه در مورد آن، نویسنده‌ی افزونه، ورژن افزونه و ... است. این فایل دقیقا معادل manifest.json در کروم است. در افزونه نویسی‌های قدیم این فایل install.rdf نام داشت و بر پایه‌ی فرمت rdf بود. ولی در حال حاضر با تغییرات زیادی که افزونه نویسی در فایرفاکس کرده‌است، الان این فایل بر پایه یا فرمت json است. اطلاعات package را به شرح زیر تغییر می‌دهیم:
{
  "name": "dotnettips",
  "title": ".net Tips Updater",
  "id": "jid1-QfyqpNby9lTlcQ",
  "description": "This extension keeps you updated on current activities on dotnettips.info",
  "author": "yeganehaym@gmail.com",
  "license": "MPL 2.0",
  "version": "0.1"
}

رابط‌های کاربری
Action Button و Toggle Button
فایل main.js را در دایرکتوری lib باز کنید:
موقعی که در کروم افزونه می‌نوشتیم امکانی به اسم browser action داشتیم که در اینجا با نام action button شناخته می‌شود. در اینجا باید کدها را require کرد، همان کاری در خیلی از زبان‌ها مثلا مثل سی برای صدا  زدن سرآیندها می‌کنید. مثلا برای action button اینگونه است:
var button= require('sdk/ui/button/action');
نحوه‌ی استفاده هم بدین صورت است:
buttons.ActionButton({...});
که در بین {} خصوصیات دکمه‌ی مورد نظر نوشته می‌شود. ولی من بیشتر دوست دارم از شیء دیگری استفاده کنم. به همین جهت ما از یک مدل دیگر button که به اسم toggle button شناخته می‌شود، استفاده می‌کنیم. از آن جا که این button دارای دو حالت انتخاب (حالت فشرده شده) و غیر انتخاب (معمولی و آماده فشرده شدن توسط کلیک کاربر) است، بهترین انتخاب هست.

کد زیر یک toggle button را برای فایرفاکس می‌سازد که با کلیک بر روی آن، صفحه‌ی popup.htm  به عنوان یک پنل روی آن رندر می‌شود:
var tgbutton = require('sdk/ui/button/toggle');
var panels = require("sdk/panel");
var self = require("sdk/self");

var button = tgbutton.ToggleButton({
  id: "updaterui",
  label: ".Net Updater",
  icon: {
    "16": "./icon-16.png",
    "32": "./icon-32.png",
    "64": "./icon-64.png"
  },
  onChange: handleChange
});

var panel = panels.Panel({
  contentURL: self.data.url("./popup.html"),
  onHide: handleHide
});

function handleChange(state) {
  if (state.checked) {
    panel.show({
      position: button
    });
  }
}

function handleHide() {
  button.state('window', {checked: false});
}
در سه خط اول، فایل‌هایی را که نیاز است Required شوند، می‌نویسیم و در یک متغیر ذخیره می‌کنیم. اگر در متغیر نریزیم مجبور هستیم همیشه هر کدی را به جای نوشتن عبارت زیر:
 tgbutton.ToggleButton
به صورت زیر بنویسیم:
require('sdk/ui/button/toggle').ToggleButton
که اصلا کار جالبی نیست. اگر مسیرهای نوشته شده را از مبدا فایل zip که اکسترکت کرده‌اید، در دایرکتوری sdk در شاخه lib بررسی کنید، با دیگر موجودیت‌های sdk آشنا خواهید شد.
در خط بعدی به تعریف یک شیء از نوع toggle button به اسم button میپردازیم و خصوصیاتی که به این دکمه داده ایم، مانند یک کد شناسایی، یک برچسب که به عنوان tooltip نمایش داده خواهد شد و آیکن‌هایی در اندازه‌های مختلف که در هرجایی کاربر آن دکمه را قرار داد، در اندازه‌ی مناسب باشد و نهایتا به تعریف یک رویداد می‌پردازیم. تابع handlechange زمانی صدا زده می‌شود که در وضعیت دکمه‌ی ایجاد شده تغییری حاصل شود. در خط بعدی شیء panel را به صورت global میسازیم. شیء self دسترسی ما را به اجزا یا فایل‌های افزونه خودمان فراهم می‌کند که در اینجا دسترسی ما به فایل html در شاخه‌ی data میسر شده است و مقدار مورد نظر را در contentURL قرار می‌دهد. نهایتا هم برای رویداد onhide تابعی را در نظر می‌گیریم تا موقعی که پنجره بسته شد بتوانیم وضعیت toggle button را به حالت قبلی بازگردانیم و حالت فشرده نباشد. چرا که این دکمه تنها با کلیک ماوس به حالت فشرده و حالت معمولی سوییچ میکند. پس اگر کاربر با کلیک بر روی صفحه‌ی مرورگر پنجره را ببندد، دکمه در همان وضعیت فشرده باقی می‌ماند.
همانطور که گفتیم تابع handlechnage موقعی رخ میدهد که در وضعیت دکمه، تغییری رخ دهد و نمیدانیم که این وضعیت فشرده شدن دکمه هست یا از حالت فشرده خارج شده است. پس با استفاده از ویژگی checked بررسی میکنم که آیا دکمه‌ای فشرده شده یا خیر؛ اگر برابر true بود یعنی کاربر روی دکمه، کلیک کرده و دکمه به حالت فشرده رفته، پس ما هم پنل را به آن نشان می‌دهیم و خصوصیات دلخواهی را برای مشخص کردن وضعیت پنل نمایشی به آن پاس می‌کنیم. خصوصیت یا پارامترهای زیادی را می‌توان در حین ساخت پنل برای آن ارسال کرد. با استفاده از خصوصیت position محل نمایش پنجره را مشخص می‌کنیم. در صورتی که ذکر نشود پنجره در وسط مرورگر ظاهر خواهد شد.
تابع onhide زمانی رخ میدهد که به هر دلیلی پنجره بسته شده باشد که در بالا یک نمونه‌ی آن را عرض کردیم. ولی اتفاقی که می‌افتد، وضعیت تابع را با متد state تغییر می‌دهیم و خصوصیت checked آن را false می‌کنیم. بجای پارامتر اولی، دو گزینه را میتوان نوشت؛ یکی window و دیگری tab است. اگر شما گزینه tab را جایگزین کنید، اگر در یک تب دکمه به حالت فشرده برود و به تب دیگر بروید و باعث بسته شدن پنجره بشوید، دکمه تنها در تبی که فعال است به حالت قبلی باز می‌گردد و تب اولی همچنان حالت خود را حفظ خواهد کرد پس می‌نویسیم window تا این عمل در کل پنجره اعمال شود.

Context Menus
برای ساخت منوی کانتکست از کد زیر استفاده می‌کنیم:
var contextMenu = require("sdk/context-menu");

var home = contextMenu.Item({
  label: "صفحه اصلی",
  data: "https://www.dntips.ir/"
});
var postsarchive = contextMenu.Item({
  label: "مطالب سایت",
  data: "https://www.dntips.ir/postsarchive"
});

var menuItem = contextMenu.Menu({
  label: "Open .Net Tips",
  context: contextMenu.PageContext(),
   items: [home, postsarchive],
  image: self.data.url("icon-16.png"),
  contentScript: 'self.on("click", function (node, data) {' +
                 '  window.location.href = data;' +
                 '});'
});
این منو هم مثل کروم دو زیر منو دارد که یکی برای باز کردن صفحه‌ی اصلی و دیگر‌ی برای باز کردن صفحه‌ی مطالب است. هر کدام یک برچسب برای نمایش متن دارند و یکی هم دیتا که برای نگهداری آدرس است. در خط بعدی منوی پدر یا والد ساخته می‌شود که با خصوصیت items، زیر منوهایش را اضافه می‌کنیم و با خصوصیت image، تصویری را در پوشه‌ی دیتا به آن معرفی می‌کنیم که اندازه‌ی آن 16 پیکسل است و دومی هم خصوصیت context است که مشخص می‌کند این گزینه در چه مواردی بر روی context menu نمایش داده شود. الان روی همه چیزی نمایش داده می‌شود. اگر گزینه، SelectionContext باشد، موقعی که متنی انتخاب شده باشد، نمایش می‌یابد. اگر SelectorContext باشد، خود شما مشخص می‌کنید بر روی چه مواردی نمایش یابد؛ مثلا عکس یا تگ p  یا هر چیز دیگری، کد زیر باعث می‌شود فقط روی عکس نمایش یابد:
SelectorContext("img")
کد زیر هم روی عکس و هم روی لینکی که href داشته باشد:
SelectorContext("img,a[href]")
موارد دیگری هم وجود دارند که میتوانید مطالب بیشتری را در مورد آن‌ها در اینجا مطالعه کنید. آخرین خصوصیت باقی مانده، content script است که می‌توانید با استفاده از جاوااسکریپت برای آن کد بنویسید.  موقعی که برای آن رویداد کلیک رخ داد، مشخص شود تابعی را صدا میزند با دو آرگومان؛ گره ای که انتخاب شده و داده‌ای که به همراه دارد که آدرس سایت است و آن را در نوار آدرس درج می‌کند.
آن منوهایی که با متد item ایجاد شده‌اند منوهایی هستند که با کلیک کاربر اجرا می‌شوند؛ ولی والدی که با متد menu ایجاد شده است، برای منویی است که زیر منو دارد و خودش لزومی به اجرای کد ندارد. پس اگر منویی میسازید که زیرمنو ندارد و خودش قرار است کاری را انجام دهد، به صورت همان item بنویسید که پایین‌تر نمونه‌ی آن را خواهید دید.
الان مشکلی که ایجاد می‌شود این است که موقعی که سایت را باز می‌کند، در همان تبی رخ می‌دهد که فعال است و اگر کاربر بر روی صفحه‌ی خاصی باشد، آن صفحه به سمت سایت مقصد رفته و سایت فعلی از دست میرود. روش صحیح‌تر اینست که تبی جدید بار شود و آدرس مقصد در آن نمایش یابد. پس باید از روشی استفاده کنیم که رویداد کلیک توسط کد خود افزونه مدیریت شود، تا با استفاده از شیء tab، یک تب جدید با آدرسی جدید ایجاد کنیم. پس کد را با کمی تغییر می‌نویسیم:
var tabs = require("sdk/tabs");
var menuItem = contextMenu.Menu({
  label: "Open .Net Tips",
  context: contextMenu.PageContext(),
   items: [home, postsarchive],
  image: self.data.url("icon-16.png"),
  contentScript: 'self.on("click", function (node, data) {' +
                 '  self.postMessage(data);' +
                 '});',
 onMessage: function (data) {
     tabs.open(data);
  }
});
با استفاده از postmessage، هر پارامتری را که بخواهیم ارسال می‌کنیم و بعد با استفاده از رویداد onMessage، داده‌ها را خوانده و کد خود را روی آن‌ها اجرا می‌کنیم.
بگذارید کد زیر را هم جهت سرچ مطالب بر روی سایت پیاده کنیم: 
var Url="https://www.dntips.ir/search?term=";
var searchMenu = contextMenu.Item({
  label: "search for",
  context: [contextMenu.PredicateContext(checkText),contextMenu.SelectionContext()],
    image: self.data.url("icon-16.png"),
  contentScript: 'self.on("click", function () {' +
  '  var text = window.getSelection().toString();' +
                 '  if (text.length > 20)' +
                 '   text = text.substr(0, 20);' +
                 '  self.postMessage(text);'+
                '})',
onMessage: function (data) {
     tabs.open(Url+data);
  }
 
});

function checkText(data) {

       if(data.selectionText === null)
           return false;

       console.log('selectionText: ' + data.selectionText);

       //handle showing or hiding of menu items based on the text content.
       menuItemToggle(data.selectionText);

       return true;
};

function menuItemToggle(text){
var searchText="جست و جو برای ";
    searchMenu.label=searchText+text;

};
در ساخت این منو، ما از ContextSelection استفاده کرده‌ایم. بدین معنی که موقعی که چیزی روی صفحه انتخاب شد، این منو ظاهر شود و گزینه‌ی دیگری که در کنارش هست، گزینه contextMenu.PredicateContext وظیفه دارد تابعی که به عنوان آرگومان به آن دادیم را موقعی که منو کانتکست ایجاد شد، صدا بزند و اینگونه میتوانیم بر حسب اطلاعات کانتکست، منوی خود را ویرایش کنیم. مثلا من دوست دارم موقعی که متنی انتخاب می‌شود و راست کلیک می‌کنم گزینه‌ی "جست و جو برای..." نمایش داده شود و به جای ... کلمه‌ی انتخاب شده نمایش یابد. به شکل زیر دقت کنید. این چیزی است که ما قرار است ایجاد کنیم:
در کل موقع ایجاد منو تابع checkText اجرا شده و متن انتخابی را خوانده به عنوان یک آرگومان برای تابع menuItemToggle ارسال می‌کند و به رشته "جست و جو برای" می‌چسباند. در خود پارامترهای آیتم اصلی، گزینه content scrip، با استفاده از جاوااسکریپت، متن انتخاب شده را دریافت کرده و با استفاده از متد postmessage برای تابع  onMessage ارسال کرده و با ساخت یک تب و چسباندن عبارت به آدرس جست و جو سایت، کاربر را به صفحه مورد نظر هدایت کرده و عمل جست و جو در سایت انجام می‌گیرد.

در قسمت آینده موارد بیشتری را در مورد افزونه نویسی در فایرفاکس بررسی خواهیم کرد و افزونه را تکمیل خواهیم کرد
مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 1 - NET Core. چیست؟
NET Core. چیست؟

برای اغلب توسعه دهنده‌های دات نت (برنامه‌های وب و دسکتاپ) تنها یک دات نت فریم ورک شناخته شده وجود دارد: The `Full` .NET Framework
که تنها بر روی ویندوز قابل اجرا است و آخرین نگارش پایدار آن در زمان نگارش این مطلب، 4.6.1 است. این فریم ورک بزرگ، از اجزایی تشکیل شده‌است که در تصویر ذیل قابل مشاهده‌اند:


مهم‌ترین قسمت‌های این فریم ورک «بزرگ» شامل مواردی مانند CLR که کار تبدیل کدهای IL را به کدهای ماشین انجام می‌دهد، BCL که کلاس‌های پایه‌ای را جهت کار با  IO، Text و غیره، فراهم می‌کنند، هستند؛ به علاوه کتابخانه‌هایی مانند Windows Forms، WPF و ASP.NET که برفراز BCL و CLR کار می‌کنند.
هرچند تعدادی از توسعه دهنده‌های دات نت تنها با Full framework کار می‌کنند، اما در طی سال‌های اخیر انشعابات بسیار دیگری از آن به وجود آمده‌اند؛ مانند دات نت‌های ویژه‌ی ویندوزهای 8 و Universal Windows Platform، دات نت مخصوص ویندوز فون 8 و ویندوز فون مبتنی بر پلتفرم سیلورلایت، به علاوه دات نت پلتفرم زامارین برای توسعه‌ی برنامه‌های iOS و Android نیز هم اکنون وجود دارند (البته در اینجا Mono، دات نت میکرو و غیره را هم باید ذکر کرد). این فریم ورک‌ها و انشعابات، به همراه پیاده سازی یک سری موارد مشترک و مواردی کاملا اختصاصی هستند که به سایر پلتفرم‌های دیگر قابل انتقال نیستند.

با زیاد شدن تعداد انشعابات دات نت «بزرگ»، نوشتن کدی که قابل اجرای بر روی تمام پلتفرم‌های یاد شده باشد، مشکل شد. اینجا بود که مفهومی را به نام PCL یا Portable class libraries معرفی کردند:


هدف از PCLها، ساده سازی کامپایل و به اشتراک گذاری کد بین پلتفرم‌های مختلف بود و پشتیبانی قابل توجهی هم از آن در VS.NET وجود دارد. هرچند این روش نسبتا موفق بود اما مشکلاتی را هم به همراه داشت. برای مثال با ارائه‌ی یک انشعاب و پلتفرم دیگری از دات نت «بزرگ»، کتابخانه‌ی PCL موجود، باید برای این انشعاب جدید مجددا کامپایل شود. به علاوه در اینجا تنها محدود به انتخاب امکانات مشترک بین پلتفرم‌های مختلف هستید.

برای رفع این مشکلات در پایان سال 2014، یک «دات نت فریم ورک جدید» به نام NET Core. معرفی شد که سورس باز است و همچنین چندسکویی (از ویندوز، لینوکس و OSX پشتیبانی می‌کند).


هرچند پیشتر Windows Store و ASP.NET Core app به صورت پلتفرم‌هایی مجزا ارائه شده بودند، اما اکنون از یک BCL مشترک به نام CoreFX استفاده می‌کنند و نحوه‌ی توزیع آن‌ها صرفا از طریق نیوگت است. به عبارتی اینبار بجای دریافت یک فریم ورک «بزرگ»، تنها اجزایی را دریافت می‌کنید که از طریق نیوگت سفارش داده‌اید.
به این ترتیب نه تنها کار توزیع برنامه‌های مبتنی بر NET Core. با سهولت بیشتری انجام خواهد شد، بلکه به روز رسانی اجزای یک برنامه، تاثیری بر روی سایر برنامه‌ها نخواهد داشت و مشکلات جانبی را به وجود نمی‌آورد. به علاوه دیگر نیازی نیست تا منتظر یک نگارش «بزرگ» دیگر باشید تا بتوانید آخرین به روز رسانی‌ها را دریافت کنید. اینبار به روز رسانی بسته‌های نیوگت برنامه معادل هستند با به روز رسانی کل فریم ورک در نگارش‌های قبلی «بزرگ» آن. در اینجا حتی CoreCLR و NET Native runtime. که مربوط به Windows runtime است هم از طریق نیوگت به روز رسانی می‌شود.

البته NET Core. انتهای مسیر نیست و هم اکنون NETStandard نیز جهت رفع مشکلات کامپایل مجدد PCLها در حال توسعه است و پس از ارائه‌ی آن، PCLها منسوخ شده درنظر گرفته می‌شوند. در این حالت با انتخاب target platform ایی به نام NETStandard (بجای مثلا انتخاب دات نت 4.5 و ویندوز فون 8)، اینبار دات نت 4.5 و ویندوز فون 8 و تمام پلتفرم‌های دیگر، به صورت یکجا انتخاب می‌شوند و اگر پلتفرم جدیدی برای مثال از NETStandard نگارش 1.1 پشتیبانی کند، به این معنا است که کتابخانه‌ی شما هم اکنون با آن سازگار است و دیگر نیازی به کامپایل مجدد آن نخواهد بود.
به علاوه هر برنامه‌ای که بر اساس NETStandard تهیه شود، قابلیت اجرای بر روی NET Core. را نیز خواهد داشت. به عبارتی برنامه‌های NETStandard همان برنامه‌های مبتنی بر NET Core. هستند.


ASP.NET Core چیست؟

در زمان نگارش این مطلب، دو گزینه‌ی برنامه‌های وب ASP.NET Core 1.0 و همچنین Windows Store apps (مبتنی بر NET Native Runtime.) قابلیت استفاده‌ی از این پلتفرم جدید NET Core. دارند.
ASP.NET Core 1.0، که پیشتر با نام ASP.NET 5 معرفی شده بود، بازنویسی کامل ASP.NET است که با ایده‌ی کاملا ماژولار بودن، تهیه شده‌است و از طریق آن، قابلیت به روز رسانی منظم و توزیع آسان از طریق نیوگت، میسر خواهد شد. به علاوه در آن، بسیاری از الگوهای برنامه نویسی شیء‌گرا مانند تزریق وابستگی‌ها، به صورت توکار و از ابتدا پشتیبانی می‌شوند.
ASP.NET Core 1.0 از WebForms ، VB ، WebPages و SignalR پشتیبانی نمی‌کند. البته در این بین عدم پشتیبانی از «وب فرم‌ها» قطعی است؛ اما افزودن سه مورد دیگر یاد شده، جزو لیست کارهای پس از ارائه‌ی نگارش 1 این فریم ورک قرار دارند و به زودی ارائه خواهند شد.


اکنون وضعیت  ASP.NET MVC 5 و ASP.NET Web API 2 چگونه است؟

ASP.NET Core 1.0 مدل برنامه نویسی ASP.NET MVC و Web API را به صورت یکپارچه ارائه می‌دهد و دیگر خبری از ارائه‌ی مجزای این‌ها نخواهد بود و دقیقا بر مبنای مفاهیم برنامه نویسی این دو بنا شده‌است. به صورت خلاصه MVC + Web API + Web Pages = Core MVC 1.0
پیشتر فضای نام System.Web.MVC مخصوص ASP.NET MVC بود و فضای نام مجزای دیگری به نام System.Web.Http مخصوص ASP.NET Web API. اما اکنون تنها یک فضای نام مشترک و یکپارچه به نام Microsoft.AspNet.Mvc هر دوی این‌ها را پوشش می‌دهد.

در این نگارش جدید وابستگی از system.web مبتنی بر IIS حذف شده‌است و با استفاده از هاست جدید چندسکویی به نام Kesterl، به سرعتی 5 برابر سرعت NodeJS دست یافته‌اند.


آخرین تاریخ به روز رسانی ASP.NET MVC 5.x دوشنبه، 20 بهمن 1393 است (با ارائه نگارش 5.2.3 که آخرین نگارش رسمی و پایدار آن است) و آخرین تاریخ به روز رسانی ASP.NET Web API 2.x نیز همان روز است.
هرچند مایکروسافت عادت به اعلام رسمی پایان پشتیبانی از بسیاری از محصولات خود را ندارد اما تمام فناوری‌های «قدیمی» خودش را بر روی CodePlex نگهداری می‌کند و تمام فناوری‌های «جدید» را به GitHub منتقل کرده‌است. بنابراین اگر در مورد فناوری خاصی به Codeplex رسیدید، یعنی «دیگر ادامه‌ی رسمی نخواهد یافت» و حداکثر در حد رفع یک سری باگ‌ها و مشکلات گزارش شده باقی می‌مانند.
مثال 1: هم اکنون نگارش دوم ASP.NET Identity را بر روی Codeplex می‌توانید مشاهده کنید. نگارش سوم آن به GitHub منتقل شد‌ه‌است که این نگارش صرفا با ASP.NET Core 1.0 سازگار است. در مورد ASP.NET MVC و Web API نیز چنین حالتی رخ داده‌است. نگارش‌های 5 و 2 آن‌ها بر روی Codeplex موجود هستند و نگارش ششم که به ASP.NET Core 1.0 تغییر نام یافت و ترکیبی است از MVC و Web API، در GitHub توسعه می‌یابد.
مثال 2: WCF به علت پیچیدگی بیش از حد و مدرن نبودن طراحی آن، رقابت را به ASP.NET Web API 2.x واگذار کرد و مدل برنامه نویسی ASP.NET Web API 2.x نیز هم اکنون جزئی از ASP.NET Core 1.0 است. بنابراین اگر قصد ایجاد پروژه‌ی جدیدی را بر این مبنا دارید، بهتر است با APS.NET Core 1.0 کار را شروع کنید.


اما هنوز تعداد زیادی از کتابخانه‌های Full framework به NET Core. انتقال پیدا نکرده‌اند

برای نمونه هنوز EF Core 1.0 که پیشتر نام EF 7.x به آن داده شده بود، به مرحله‌ی نهایی تکمیل قابلیت‌های آن نرسیده‌است. اما باید دانست که ASP.NET Core 1.0 صرفا بر فراز NET Core. قابل اجرا نیست؛ بلکه قابلیت اجرای بر فراز NET 4.6. و یا همان دات نت «بزرگ و کامل» را نیز دارد. بنابراین به سادگی قابلیت اجرای EF 6.x و یا NHibernate را نیز دارا است. تنها مزیتی را که در اینجا از دست خواهید، قابلیت چندسکویی بودن ASP.NET Core 1.0 است؛ زیرا EF 6.x با چنین دیدی طراحی نشده‌است.



همانطور که ملاحظه می‌کنید، ASP.NET Core 1.0 قابلیت اجرای بر روی هر دوی NET Core 1.0. و NET 4.6. را دارا است. اما یکی، چندسکویی است و دیگری صرفا مختص به ویندوز.


فناورهای منسوخ شده‌ی در NET Core.

یکسری از فناوری‌ها و کتابخانه‌ها احتمالا هیچگاه قابلیت انتقال به NET Core. را نخواهند یافت و یا حداقل باید تا چندنگارش بعدی آن صبر کنند. فناوری‌های خاتمه یافته‌ی با NET Core. به شرح زیر هستند:
- Reflection: همانطور که عنوان شد، NET Core. بر فراز CoreCLR و همچنین NET Native runtime. اجرا می‌شود و تولید برنامه‌های native و static linking آن‌ها مانند برنامه‌های ++C، نیاز به دانستن اجزایی دارد که به صورت پویا فراخوانی نمی‌شوند و بلافاصله و در زمان کامپایل، توسط کامپایلر قابل تشخیص هستند. همین محدودیت سبب شده‌است که استفاده‌ی از Reflection در NET Core. به حداقل ممکن آن برسد. برای مثال در System.Object متد GetType آن تنها نام نوع را باز می‌گرداند و نه اطلاعات بیشتری را مانند  GetMembers سابق.
- App Domains: هرچند CoreCLR از App Domains پشتیبانی می‌کند اما NET Native runtime. خیر. به همین جهت برای ایزوله سازی برنامه‌ها توصیه شده‌است که از containerهایی مانند docker استفاده شود.
- Remoting: پیش از WCF جهت برقراری ارتباط بین برنامه‌ها مطرح شده بود و هم اکنون در دات نت کامل هم آنچنان استفاده‌ای از آن نمی‌شود.
- binary serialization: البته کتابخانه‌هایی مانند JSON.NET و امثال آن، نگارش NET Core. هم دارند؛ اما چون binary serialization نیاز به اطلاعات reflection قابل توجهی دارد دیگر پشتیبانی نخواهد شد.


فناور‌هایی که به زودی به NET Core. منتقل می‌شوند

یکسری از فناوری‌ها مانند XAML هنوز معادل NET Core. ندارند و لیست زیر قرار است از طرف مایکروسافت سورس باز شده و همچنین به NET Core. منتقل شود:
System.Data
System.DirectoryServices
System.Drawing
System.Transactions
System.Xml.Xsl and System.Xml.Schema
System.Net.Mail
System.IO.Ports
System.Workflow
System.Xaml


مراحل نصب ASP.NET Core 1.0

پیش از نصب نگارش 1.0 RTM باید به این نکته دقت داشت که نصاب آن، نگارش‌های آزمایشی قبلی را حذف و یا بازنویسی نمی‌کند و همین مساله ممکن است سبب بروز تداخل‌هایی و یا حتی از کار افتادن VS.NET شما شود. بنابراین اگر نگارش‌های RC یا بتا را پیشتر نصب کرده‌اید، به Add remove programs ویندوز مراجعه کرده و سه مورد ذیل را حتما حذف کنید (خیلی مهم):
- Preview Tooling (all versions)
- NET Core Runtime SDK (all versions).
- NET Core Runtime (all Versions).
پس از حذف بسته‌های قدیمی، برای نصب نگارش 1.0 RTM، ابتدا نیاز است Visual Studio 2015 Update 3 را نصب کنید و پس از آن با استفاده از NET Core for Visual Studio Official MSI Installer. کار نصب اجزای مورد نیاز آن انجام خواهد شد.


بررسی شماره نگارش 1.0 RTM

پس از نصب اجزای عنوان شده، خط فرمان را گشوده و دستور ذیل را صادر کنید:
 C:\Users\Vahid>dotnet --version
1.0.0-preview2-003121
همانطور که مشاهده می‌کنید، نگارش ذکر شده هنوز در مرحله‌ی preview است و صرفا مرتبط است به tooling و یا ابزارهای مرتبط با آن.
اگر یک پروژه‌ی خالی ASP.NET Core Web Application را نیز شروع کنید (با طی مراحل زیر جهت ایجاد یک پروژه‌ی جدید):
 .NET Core -> ASP.NET Core Web Application (.NET Core) -> Select `Empty` Template


در اینجا فایل جدیدی را به نام global.json مشاهده می‌کنید که محتوایات آن شامل دقیقا همین شماره نگارش است؛ به همراه معرفی پوشه‌های اصلی پروژه:
{
  "projects": [ "src", "test" ],
  "sdk": {
    "version": "1.0.0-preview2-003121"
  }
}
مطالب
بررسی مشکلات AngularJS 1.x
از اولین مقاله‌ای که در مورد AngularJS در این سایت منتشر کردم، بیش از دو سال می‌گذرد. در آن زمان فقط از این فریمورک تعریف و تمجید کردم؛ اما بد نیست بعد از چند تجربه‌ی کاری دلایل تنفری را که نسبت به آن پیدا کرده ام، نیز بیان کنم.
اگر عبارت why I hate angularjs را در گوگل جستجو کنید، می‌بینید که فقط من این عقیده را پیدا نکرده‌ام و افراد دیگری نیز هستند که مثل من فکر می‌کنند و حتی از لحاظ فنی AngularJS را به چالش کشیده‌اند. برای مثال سایت I hate angular بیشتر مقالاتی را که ضد AngularJS هستند، گردآوری کرده است و برای بررسی مشکلات Angular می‌تواند شروع خوبی باشد.
البته قصد ندارم که از نظر فنی Angular را نقد کنم؛ فقط قصد به اشتراک گذاری یک سری از مشکلات توسعه‌ی Single Page Application‌ها را با استفاده از فریمورک Angular، دارم و این را در نظر داشته باشید که بعضی از این مشکلات در هنگام توسعه SPA‌ها با فریمورک‌هایی از این دست، گریبان‌گیر شما می‌شوند و الزاما ربطی به AngularJS ندارند.

سازگار نبودن افزونه‌های jQuery با Angular

برنامه‌های واقعی فقط از تعدادی ng-repeat تشکیل نشده‌اند که ما از دیدن آن‌ها ذوق زده شویم. خواسته یا ناخواسته مجبوریم در برنامه‌های وب خودمان از افزونه‌های محبوب جی‌کوئری نیز استفاده کنیم. خوب، خیلی هم خوب! چندین راه حل پیش روی ماست:

روش اول - نادیده گرفتن angular
انگار نه انگار که از angular استفاده می‌کنیم و افزونه مورد نظر را بدون در نظر گرفتن وجود angular، کاملا عادی فراخوانی کنیم.
نتیجه: ممکن است بعضی  وقت‌ها جواب بدهد، ولی اکثر مواقع، نتیجه عجیب غریب است و خطا‌ها قابل فهم نیستند و توانایی اشکال زدایی آن‌ها را نخواهید داشت. دلیلش هم مشخص است؛ چون Angular فازی به نام کامپایل و اصطلاحا context مربوط به خودش را دارد و فراخوانی افزونه مورد نظر، خارج از context انگولار رخ می‌دهد و انگولار از وجود این افزونه بی خبر است. حال ممکن است به طور اتفاقی، فراخوانی افزونه قبل، مابین و یا حتی بعد از فاز کامپایل انگولار رخ دهد. باز هم فرض کنید که بر حسب اتفاق همه چیز خوب پیش رفت، اما اکنون سایر قابلیت‌های خوب انگولار مثل ng- model و model binding آن در دسترس نیستند و در آخر به این نتیجه می‌رسید که پس چرا دارم از انگولار استفاده می‌کنم.

روش دوم - استفاده از directive‌های محصور کننده
راه اصولی برای استفاده از افزونه‌های جی‌کوئری در AngularJS، استفاده از directiveهای تهیه شده برای آن افزونه است. اگر خوش شانس باشید، معمولا برای افرونه‌های معروف، directive انگولاری آن نیز تهیه شده است. اما این همه‌ی داستان نیست؛ فرض کنید که از کتابخانه jQuery file upload، برای آپلود فایل می‌خواهید استفاده کنید. خوشبختانه directive  انگولاری نیز برای آن تهیه شده است و مستندات استفاده از آن هم، تنها مثالی هست که برای آن فراهم شده است. اما فرض کنید که می‌خواهید مانند مثال استفاده از آن در jQuery، یک file input که کاربر تنها  بتواند یک فایل را از طریق کشیدن و رها کردن آپلود کند، با استفاده از Directive انگولاری آن پیاده سازی کنید. اما کار با این directive، به آسانی مثال جی‌کوئری آن نیست. یک‌کم که جلوتر بروید می‌بینید که این directive گنگ طراحی شده است.  البته بیشتر directive هایی که اصطلاحا wrapper برای افزونه‌های جی‌کوئری هستند این مشکل را دارند و کار با آن‌ها چندان لذت بخش نیست و باید ساعت‌ها با آنها کلنجار رفت تا به نتیجه‌ی دلخواه رسید و همه‌ی این‌ها را در نظر بگیرید که اگر با api‌های jQuery آن کار می‌کردید، دیگر این مشکلات را نداشتید. قبلا نیز یک نمونه‌ی دیگر از مشکلات استفاده از این گونه directive‌های محصور کننده را تحت مقاله ای با عنوان استفاده از افزونه isotope در انگولار به اشتراک گذاشتم.

روش سوم - استفاده از directive هایی که به صورت native با انگولار نوشته شده‌اند
اما چرا به هنگام استفاده از directive‌های محصور کننده افرونه‌های جی‌کوئری، با مشکلات زیادی روبرو می‌شویم؟ دلیلش این است که انگولار می‌گوید بهتر است این افزونه‌ها با استفاده از خود angular بازنویسی شوند. برای مثال برای آپلود فایل می‌توان از کتابخانه‌ی با کیفیت ng-file-upload که هیچ وابستگی به jQuery ندارد استفاده کرد. اما آیا واقعا برای تمامی افزونه‌های جی‌کوئری معادلی برای AngularJs آن با همان کیفیت تهیه شده است؟ جواب مطمئنا خیر است. برای مثال در حالی که برای datagrid افزونه‌های بی شماری برای جی‌کوئری تهیه شده است، اما برای angular تنها یکی دو تا directive با کیفیت تهیه شده‌است که نه تنها قابلیت رقابت با معادل‌های jQuery شان را ندارند، آنچنان نیز stable نیستند و در مستندات خودشان هشدار می‌دهند که فلان ویژگی در حال تست هست و هنوز پایدار نیست.

روش چهارم – نوشتن directive توسط خودتان
به عنوان آخرین راه حل باید خودتان دست به کار شده و برای افزونه مورد نظرتان directive بنویسید. اما نوشتن directive برای افزونه‌های پیچیده‌ی جی‌کوئری به سادگی مثال‌های آموزشی AngularJS همانند چگونگی نوشتن directive برای jQueryUI Datepicker  نیست. اگر کدهای directive‌های نوشته شده برای افزونه‌های پیچیده را بررسی کنید، کدهایی را می‌بینید که برای شما منطقی نیست. برای مثال ممکن است با تعداد زیادی setTimeOut مواجه شوید که احتمالا با نحوه‌ی کامپایل HTML توسط انگولار مرتبط است. در کل باید بدانید که نوشتن directive برای تعداد زیادی از افزونه‌ها کار راحتی نیست و احتمالش هست که قید این را کار نیز بزنید.

پس اگر قصد توسعه SPA با هر فریمورکی مثل angular را داشته باشید، این را در نظر داشته باشید که دیر یا زود هنگام استفاده از افزونه‌های جی‌کوئری به مشکل برخواهید خورد. 

 

بیشتر امکانات تو کار ASP.NET MVC را از دست خواهید داد

به هنگام توسعه‌ی برنامه با استفاده از فریم ورک‌های SPA، امکانات توکار ASP.NET MVC مثل اعتبارسنجی یکپارچه و strongly typed view‌ها را از دست خواهید داد. شاید یک سری پروژه در Github پیدا کنید که سعی کرده‌اند این‌ها را با یکدیگر سازگار کنند. اما به محض استفاده متوجه می‌شوید که اگر همه‌ی کارها را خودتان با Angular انجام بدهید راحت‌تر هستید تا استفاده از کتابخانه‌های آزمایشی و ناقص.

البته باز هم نمی‌گویم که این‌ها تقصیر AngularJS است. ذات توسعه‌ی SPA‌ها، این گونه است و در توسعه‌ی SPA با هر فریمورکی به این مشکلات برخواهید خورد.

حال که یکسری مشکلات عمومی را بررسی کردیم، بدنیست نگاهی اختصاصی به خود AngularJS بیندازیم.

ضعف طراحی 

اگر به تعدای از لینک‌های سایت ihateangular مراجعه کنید می‌بینید که هر کسی نظری دارد: یکی می‌گوید به هیچ وجه Directive ننویسید، یکی دیگر می‌گوید کنترلر ننویسید و تمامی کارها را در directive‌های سفارشی نوشته شده توسط خودتان انجام بدهید، کلا همه جا علیه performance این فریمورک صحبت می‌کنند و همگی به پیچیده بودن آن اذعان دارند.

 اما نمی‌شود با چند مقاله‌ی موجود در اینترنت، یک فریمورک با این محبوبیت را زیر سوال برد. اما واقعا فکر می‌کنید که چرا نسخه‌ی 2 انگولار یک بازنویسی کامل است؟ دلیلش واضح است؛ این فریمورک از پایه اشکال دار بوده است و باید از اساس اصلاح شود. پس می‌توان نتیجه گرفت که اشکالات وارد شده به این فریمورک صحیح هستند. 

AngularJs 2 یک بازنویسی کامل است
 
قبلا این موضوع در این نظرسنجی مطرح شده است. بازنویسی کامل یعنی این که خیلی چیزها به کل تغییر کرده‌اند و کدهای قبلی شما با نسخه‌ی جدید سازگار نیستند. بیشتر مطالبی که فراگرفته بودید دیگر کاربردی ندارد و دوباره مطالب جدیدی را باید یاد بگیرید. این را هم در نظر بگیرید که توسعه دهندگانی که در حال نوشتن directive هستند، احتمالا با آمدن نسخه 2 انگولار، مجبورند directive خود را بازنویسی کنند. آیا خودتان بودید، دیگر دل به کار می‌دادید؟!

نتیجه گیری

AngularJS فریمورک خیلی خوبی برای نوشتن برنامه‌های تست پذیر است و کسی منکر قابلیت‌های آن نیست. ولی این را نیز در نظر بگیرید که برای تست پذیر بودن، خیلی چیز‌ها از جمله سادگی کار را از دست می‌دهید. معمولا می‌گویند که AngularJS کارهای مشکل را ساده می‌کند و کارهای ساده را مشکل.

پیشنهاد من این است که اگر هنوز AngularJS را فرا نگرفته‌اید، حداقل یادگیری آن را تا انتشار نسخه‌ی 2 آن به تعویق بیندازید. اگر AngularJS را بلد هستید، دیگر آن را در پروژه‌ای استفاده نکنید؛ چون دیگر کدهای شما در نسخه‌ی 2 کار نخواهد کرد و احتیاج به انجام تغییرات گسترده‌ای در کدهای نوشته شده قبلی پیدا می‌کنید.

مطالب
Base64 و کاربرد جالب آن
Base64 یک مبنای عددی است که یکی از کاربرد‌های آن در نرم افزار‌ها انتقال اطلاعات فایل باینری است. به عنوان مثال با تبدیل محتوای باینری یک تصویر به مبنای 64 میتونید اون تصویر رو در دل فایل هایی نظیر HTML و CSS و SVG قرار بدید؛ یا به اصطلاح اون تصویر رو Embeded (توکار) کنید.

نکته: در Base64 برای هر 6 بیت یک کاراکتر معادل در مبنای 64 در نظر گرفته میشه، به همین دلیل در هنگام تبدیل برای جلوگیری از Lost (گم) شدن داده‌ها عملیات مورد نظر رو بر روی سه بایت داده انجام میدیم. که با این کار برای هر 3 بایت (24 بیت) 4 کاراکتر معادل خواهیم داشت؛ به این ترتیب حجم نهایی فایل تبدیل شده در واحد بایت، برابر است با:

(حجم نهایی) = (3 / حجم کل فایل) + (حجم کل فایل)


و حالا نحوه تبدیل فایل تصویر به Base64:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Image2Base64Converter
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnOpen_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Multiselect = false;
            ofd.Filter = "Pictures |*.bmp;*.jpg;*.jpeg;*.png";

            if (ofd.ShowDialog(this) == DialogResult.OK)
            {
                txtImagePath.Text = ofd.FileName;
            }
        }

        private void btnConvert_Click(object sender, EventArgs e)
        {
            if (!File.Exists(txtImagePath.Text))
            {
                MessageBox.Show("File not found!");
                return;
            }

            btnCopy.Enabled = false;
            btnConvert.Enabled = false;
            txtOutput.Enabled = false;

            BackgroundWorker bworker = new BackgroundWorker();
            bworker.DoWork += (o, a) =>
            {
                string header = "data:image/{0};base64,";
                header = string.Format(header, txtImagePath.Text.GetExtension());

                StringBuilder data = new StringBuilder();

                byte[] buffer;
                BinaryReader head = new BinaryReader(
                    new FileStream(txtImagePath.Text, FileMode.Open));

                buffer = head.ReadBytes(6561);
                while (buffer.Length > 0)
                {
                    data.Append(Convert.ToBase64String(buffer));
                    buffer = head.ReadBytes(6561);
                }

                head.Close();
                head.Dispose();

                this.Invoke(new Action(() =>
                {
                    txtOutput.ResetText();
                    txtOutput.AppendText(header);
                    txtOutput.AppendText(data.ToString());

                    btnCopy.Enabled = true;
                    btnConvert.Enabled = true;
                    txtOutput.Enabled = true;
                }));
            };

            bworker.RunWorkerAsync();
        }

        private void btnCopy_Click(object sender, EventArgs e)
        {
            Clipboard.SetText(txtOutput.Text);
        }
    }

    public static class ExtensionMethods
    {
        public static string GetExtension(this string str)
        {
            string ext = string.Empty;
            for (int i = str.Length - 1; i >= 0; i--)
            {
                if (str[i] == '.')
                {
                    break;
                }

                ext = str[i] + ext;
            }

            return ext;
        }
    }
}
توضیح کد:
در خط 44 یک BackgroundWorker تعریف شده است تا عملیات تبدیل در یک ترد جداگانه انجام شود، که در عملیات‌های سنگین ترد اصلی برنامه آزاد باشد.
در خطوط 47 تا 64 کدهای مربوط به تبدیل قرار گرفته است:
در خط 47 و 48 ابتدا یک سرآیند برای معرفی داده‌های تبدیل شده ایجاد میکنیم؛ ",data:image/{0};base64" که در ان نوع فایل و پسوند آن را مشخص کرده و سپس الگوریتم به کار گرفته شده برای تبدیل آن را نیز ذکر میکنیم: ":data" + نوع فایل (image) + "/" + پسوند فایل + ";" + الگوریتم تبدیل + ",".
در انتهای کار این سرآیند تولید شده در ابتدای داده‌های تبدیل شده فایل، قرار خواهد گرفت.
در خط 50 یک StringBuilder برای نگهداری اطلاعات تبدیل شده ایجاد کرده ایم.
در خط 52 یک بافر برای خواندن اطلاعات باینری فایل ایجاد کرده ایم.
در خط 53 فایل مورد نظر را برای خواندن باز کرده ایم.
و در خطوط 56 تا 61 فایل مورد نظر را خوانده و پس از تبدیل در متغیر data ذخیره کرده ایم.
در نظر داشته باشید که برای عملکرد صحیح لازم است که عملیات تبدیل بر روی 3 بایت داده انجام شود؛ پس در هر بار  خواندن داده‌های فایل، باید مقدار داده ای که خوانده میشود ضریبی از 3 باشد.
در خطوط 63 و 64 نیز منابع اشغال شده سیستم را آزاد کرده ایم.
در انتها داده‌های مورد استفاده برای Embeded کردن تصویر برابر است با:
()header + data.ToString

embeded-images.htm : فایل نمونه برای نحوه استفاده از تصویر توکار.
Image2Base64-Converter.zip : سورس کامل برنامه ارائه شده.
نظرات مطالب
شروع به کار با AngularJS 2.0 و TypeScript - قسمت دوازدهم - توزیع برنامه
یک نکته‌ی تکمیلی

به مستندات رسمی AngularJS 2.0، فصل جدیدی به نام «Introduction to Webpack» اضافه شده‌است. در اینجا می‌توان Webpack را جایگزین Gulp کرد و نکته‌ی جالب آن، امکان نوشتن یک چنین کامپوننت‌هایی هستند:
import { Component } from '@angular/core';
import '../../public/css/styles.css';

@Component({
      selector: 'my-app',
      template: require('./app.component.html'),
      styles: [require('./app.component.css')]
})
export class AppComponent { }
در اینجا معرفی template و css جداگانه‌ی تعریف شده‌ی در فایل‌های مجزای خودشان، توسط متد require مربوط به webpack انجام شده‌اند. مزیت آن این است که زمانیکه webpack کار bundling برنامه را انجام می‌دهد، تک فایل js حاصل، حاوی تمام فایل‌های html و css برنامه هم خواهد بود و دیگر نیازی به توزیع جداگانه‌ی آن‌ها نیست. به عبارتی شما در حین تهیه‌ی برنامه، inline کار نمی‌کنید، اما webpack آن‌ها را حین توزیع نهایی، به صورت خودکار تبدیل به قالب‌ها و شیوه‌نامه‌های inline می‌کند.
نظرات مطالب
C# 7 - Pattern matching and switch expressions
C# 7.1 - Pattern-Matching with Generics

C# 7.1 پشتیبانی بهتری از pattern-matching را جهت کار با Generics ارائه داده‌است.
public class Car {}
public class SportsCar : Car
{
   public string Color { get; set; }
}
در اینجا یک کلاس پایه خودرو و سپس یک کلاس مشتق شده‌ی خودرو‌های ورزشی را داریم. اکنون در جائی از برنامه می‌خواهیم متد راندن این خودروها را تعریف کنیم:
public static void Run<T>(T car) where T : Car
{
   if (car is SportsCar sportsCar)
   {
   }

   switch (car)
   {
      case SportsCar sCar:
      break;
   }
}
در اینجا نوع خودرو به صورت جنریک تعریف شده‌است و سپس با استفاده از قابلیت‌های pattern-matching سعی در انطباق با آن‌ها را داریم. کامپایل این قطعه کد در C# 7.0 با خطای کامپایلر ذیل متوقف می‌شود:
 An expression of type "T" cannot be handled by a pattern of type "SportsCar"

اگر این قطعه کد را بخواهیم با C# 7.0 کامپایل کنیم نیاز است ابتدا شیء دریافتی به object تبدیل شود و سپس کار pattern-matching با موفقیت صورت خواهد گرفت:
public static void Run<T>(T car) where T : Car
{
   if ((object)car is SportsCar sportsCar)
   {
   }

   switch ((object)car)
   {
      case SportsCar sCar:
      break;
   }
}
این محدودیت در C# 7.1 برطرف شده‌است و دیگر نیازی به این cast اضافه نیست و می‌توان (object) را از قطعه کد فوق حذف کرد.
مسیرراه‌ها
ASP.NET MVC
              مطالب
              Virtual Scrolling در Angular 7
              یکی از امکانات Angular 7، ویژگی Virtual Scrolling می‌باشد. در صورتیکه شما قصد داشته باشید یک لیست بزرگ از المنت‌ها را  بارگذاری کنید، این‌کار می‌تواند بر روی کارآیی برنامه‌ی شما تاثیر بگذارد . تگ زیر
              <cdk-virtual-scroll-viewport></cdk-virtual-scroll-viewport>
              می تواند برای بارگذاری تنها بخش‌های قابل مشاهده‌ی از یک لیست، بر روی صفحه نمایش استفاده شود و همچنین تنها آیتم‌هایی Render خواهند شد که می‌تواند آن‌ها را در صفحه نمایش جا دهد. اگر لیست بارگذاری شده را اسکرول کنیم، در این حالت المنت‌ها در DOM  به صورت پویا  load و unload می‌شوند. 
              قبل از پیاده سازی ، لازم است Angular CLI  را به آخرین نسخه بروز رسانی کنیم. برای بروز رسانی Angular CLI  دستور زیر را اجرا می‌کنیم:
              npm install -g @angular/cli
              بعد از نصب با استفاده از ng version  نسخه‌ی Angular CLI  را بررسی می‌کنیم که باید بزرگتر از 7 باشد:

              حالا نوبت به ایجاد یک پروژه‌ی جدید می‌باشد. با استفاده از دستور زیر یک پروژه جدید ایجاد می‌شود:
              ng new angular7-virtualScrolling
              بعد از تایید دستور بالا،  دو سؤال از شما پرسیده می‌شود؟
              1- آیا قصد دارید Angular routing اضافه شود یا نه؟ ( در نسخه‌های قبلی با استفاده از routing--  این کار را انجام می‌دادیم)


              2-انتخاب فرمت stylesheet که قصد استفاده‌ی از آن‌را دارید ( با کلید‌های جهتی بالا و پایین روی صحفه کلید می‌توانید یکی از گزینه‌ها را انتخاب کنید )


              برای استفاده از Virtual Scrolling نیاز است پکیج زیر را نصب کنیم : 
              npm install @angular/cdk@latest
              بعد از نصب، دستور ng serve را اجرا می‌کنیم تا بررسی کنیم که برنامه به درستی اجرا می‌شود یا نه. سپس فایل app.module.ts را باز می‌کنیم و ScrollingModule را در بخش imports اضافه می‌کنیم. اکنون نیاز است تا یک آرایه را برای نمایش آیتم‌های لیست، تولید کنیم. قطعه کد زیر در فایل app.component.ts  قرار دارد که یک آرایه عددی را ایجاد می‌کند و تعدادی آیتم را به آن اضافه می‌کند:
                title = 'Angular 7 – Virtual Scrolling feature';
                scrollItems: number[] = [];
                constructor() {
                  for (let index = 0; index < 10000; index++) {
                    this.scrollItems.push(index);
                  }
                }

              در فایل app.component.html  قطعه کد زیر را قرار می‌دهیم:
                  <div>
                    <h4>
                      {{this.title}}
                    </h4>
                    <cdk-virtual-scroll-viewport itemSize="100">
                      <div *cdkVirtualFor="let n of scrollItems">Item {{n}}</div>
                    </cdk-virtual-scroll-viewport>
                  </div>

              داخل تگ  cdk-virtual-scroll-viewport، یک div را ایجاد و سپس یک دایرکتیو را به نام cdkVirtualFor* به آن اضافه می‌کنیم. این دایرکتیو، ngFor* را درون cdk-virtual-scroll-viewport، جایگزین می‌کند که شما با استفاده از آن می‌توانید یک حلقه بر روی آرایه  scrollItems  جهت پیمایش ایجاد کنید.
              تمام ! اکنون پروژه را اجرا کنید.
              در اولین بار اجرا :    


              بعد از اسکرول کردن لیست : 


              همانطور که مشاهده می‌کنیم المنت‌های قبلی unload شدند و المنت‌های جدید load شدند
              DEMO 


              مطالب
              کمی شوخی با IE6

              اخیرا عده‌ای از همکاران عنوان می‌کنند که "لطفا" از IE6 استفاده نکنید، یا یک پیغام "لطیف" را به کاربران IE6 نمایش می‌دهند و امثال آن. نظر شما در مورد استفاده از روش‌های زیر چیست؟ :-)

              مثال زیر را در نظر بگیرید:

              <html>
              <head>
              <title>crash-1</title>
              <style type="text/css">
              * {position: relative;}
              </style>
              </head>
              <body>

              <table><input></table>

              </body>

              </html>

              IE6 کاربر، پس از باز کردن این صفحه، بلافاصله محو خواهد شد. به صورت خلاصه همین یک سطر زیر برای کرش IE6 کافی است:

              <style>*{position:relative}</style><table><input></table>

              مثال 2:
              <html>
              <head>
              <title>crash-2</title>
              <script type="text/javascript">for (x in document.write) { document.write(x);}</script>
              </head>
              <body>
              Test-2
              </body>

              </html>

              این یک سطر اسکریپت نیز سبب کرش IE6 خواهد شد.

              مثال 3:
              این مورد کمی خطرناک است و سبب هنگ کل سیستم عامل خواهد شد و همچنین مصرف شدید حافظه تا حد ممکن.
              <html>
              <head>
              <title>crash-3</title>
              <style type="text/css">
              :link:hover {
              color: #f00;
              }
              :link .images {
              width: 300px;
              display: none;
              }
              :link:hover .images {
              position: absolute;
              top: 10px;
              left: 230px;
              display: block;
              }
              </style>
              </head>

              <body>

              <a href="#">Line 1
              <div class="images">
              Line 2: HOVERING OVER THIS LINE MAY CRASH THE BROWSER! <br>Line 3: What is happening
              here?</div>
              </a>

              </body>

              </html>

              مثال 4:
              این مورد نیز سبب هنگ سیستم عامل می‌شود:

              <!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" xml:lang="en-US" lang="en-US">
              <head>
              <style type="text/css">
              a {
              padding:2px;
              white-space:nowrap;
              position:relative;
              }
              </style>
              </head>
              <body>

              <div>
              <a href="#">Option 1</a>
              <a href="#">Option 2</a>
              </div>

              </body>
              </html>

              و اما روش‌های محترمانه!
              اشتراک‌ها
              دریافت کتاب Clean Architecture نوشته Robert C. Martin

              دانش و مهارت زیادی لازم نیست تا یک برنامه نوشت. بچه‌های دبیرستانی نیز این کار را در دبیرستان انجام می‌دهند. مردان و زنان جوان در دانشگاه با سر هم کردن چند خط کد PHP یا Ruby کسب و کار‌های میلیارد دلاری را شروع کرده اند. برنامه نویسان تازه کار زیادی در دفاتر کاری مکعبی شکلشان در سرتاسر دنیا در بین اسناد حجیم نیازمندی‌های موجود در سیستم‌های issue tracking خود در حال تقلا هستند تا سیستم هایشان را با صرف فعل خواستن توانستن است به کار بیندازند. کدهایی که تولید می‌کنند ممکن است زیبا نباشند ولی کار می‌کنند. کار می‌کند به این دلیل که چیزی بتواند یک بار کار کند، خیلی سخت هم نیست. این که چیزی واقعا به درستی کار کند موضوعی کاملا متفاوت است. پیاده سازی صحیح نرم افزار سخت است چرا که دانش و مهارت هایی نیاز دارد که هنوز بیشتر برنامه نویسان جوان به آن دست نیافته اند. 

              دریافت کتاب Clean Architecture نوشته Robert C. Martin