مطالب
فعالسازی امکانات Refactoring افزونه‌ی Roslynator در VSCode
یکی از قابلیت‌های افزونه‌ی C# for Visual Studio Code پس از نگارش 1.10.0 آن، امکان بارگذاری افزونه‌های مخصوص Roslyn است که قابلیت‌های Refactoring را به همراه دارند؛ مانند افزونه‌ی معروف و جامع Roslynator. البته هنوز افزونه‌های Analyzers مبتنی بر Roslyn، با VSCode سازگاری ندارند که قرار است در نگارش‌های آتی افزوده شوند. در این مطلب، نحوه‌ی فعالسازی افزونه‌های Roslyn refactoring ثالث را بررسی خواهیم کرد.


فعالسازی قدم به قدم Roslyn refactoring افزونه‌ی Roslynator

الف) فایل VSIX آن‌را از اینجا دریافت کنید و سپس پسوند آن‌را به zip تغییر دهید.
ب) این فایل zip را در پوشه‌ای مشخص باز کنید.
ج) پس از باز کردن این فایل zip، دو فایل Roslynator.VisualStudio.Core.dll و Roslynator.VisualStudio.dll آن‌را حذف کنید. این فایل‌ها مخصوص نگارش کامل ویژوال استودیو هستند و در صورت وجود، با سیستم بارگذاری افزونه‌های OmniSharp تداخل می‌کنند.
د) در آخر مسیر زیر را گشوده:
%USERPROFILE%/.omnisharp
و سپس فایل جدید omnisharp.json را با محتوای ذیل، در آن مسیر ایجاد کنید:
{
  "RoslynExtensionsOptions": {
    "LocationPaths": [
      "C:\\lib\\roslynator"
    ]
  }
}
که در اینجا مسیر ذکر شده، به پوشه‌ای اشاره می‌کند که فایل zip افزونه را در آنجا گشوده‌اید (به ذکر \\ هم دقت داشته باشید؛ تا فایل json نهایی، به درستی تشکیل شود).

اکنون اگر VSCode را اجرا کنید، شاهد افزوده شدن امکانات Refactoring مخصوص افزونه‌ی Roslynator به لیست Refactoring پیش‌فرض OmniSharp خواهید بود:



خودکار سازی دریافت، نصب و فعالسازی Roslyn refactoring افزونه‌ی Roslynator

مراحل فوق را می‌توان تبدیل به یک اسکریپت پاورشل کرد که با هر بار اجرای آن، به صورت خودکار کار دریافت و نصب این افزونه صورت گیرد:
Write-Host "Download, unzip and enable Roslynator for Visual Studio Code"

$name = "josefpihrt.Roslynator2017"
$url = "https://marketplace.visualstudio.com/items?itemName=$name"
$currentDir = $PSScriptRoot
$file = "$currentDir\Roslynator.zip"

$pattern = "<script class=`"vss-extension`" defer=`"defer`" type=`"application\/json`">(.*?)<\/script>"
$regex = [regex]"(?m)$pattern"
Write-Host "Grab the home page of the $name."
$dom = (New-Object Net.WebClient).DownloadString($url); 
if($dom -and $dom -match $pattern) 
{
    $matches = $regex.Match($dom)
    $jsonText = $matches[0].Groups[1]

    $json = ConvertFrom-Json $jsonText

    $version = $Json.versions[0].version # Parse the json in the page for the latest version number
    $parts = $name.Split(".")
    $publisher = $parts[0]
    $package = $parts[1]

    # Assemble the url for the vsix package
    $packageUrl = "https://marketplace.visualstudio.com/_apis/public/gallery/publishers/$publisher/vsextensions/$package/$version/vspackage"
    Write-Host "Download the vsix package: $packageUrl"
    (New-Object Net.WebClient).DownloadFile($packageUrl, $file)

    Write-Host "Using $currentDir as the current dir."
    Write-Host "Unzip $file."
    $shellApp = new-object -com shell.application 
    $zipFile = $shellApp.namespace($file) 
    $destination = $shellApp.namespace($currentDir) 
    $destination.Copyhere($zipFile.items(), 0x14)# overwrite and be silent

    Write-Host "Delete VS specific files. Otherwise they will interfere with the MEF services inside OmniSharp."
    Remove-Item "$currentDir\Roslynator.VisualStudio.Core.dll","$currentDir\Roslynator.VisualStudio.dll", "$currentDir\Roslynator.VisualStudio.pkgdef"

    $omnisharpJsonFilePath = "$env:USERPROFILE\.omnisharp\omnisharp.json";
    Write-Host "Create $omnisharpJsonFilePath file."
    $omnisharpJson = @" 
{{
  "RoslynExtensionsOptions": {{
    "LocationPaths": [
      "{0}"
    ]
  }}
}}
"@ -f $currentDir -Replace "\\","\\"
    $omnisharpJson | Out-File "$omnisharpJsonFilePath" -Confirm

    Write-Host "Done!"
}
else
{
    Write-Host "Failed to find the packageUrl!"
}
کدهای فوق را با نام فرضی update.ps1 ذخیره کنید (و یا از اینجا دریافت کنید: update.zip ). سپس می‌توانید آن‌را با اجرای دستور update.ps1\.، اجرا کرده و به صورت خودکار شاهد این مراحل باشید:
PS D:\Prog\1396\RoslynatorVSCode> .\update.ps1
Download, unzip and enable Roslynator for Visual Studio Code
Grab the home page of the josefpihrt.Roslynator2017.
Download the vsix package: https://marketplace.visualstudio.com/_apis/public/gallery/publishers/josefpihrt/vsextensions/Roslynator2017/1.7.0/vspackage
Using D:\Prog\1396\RoslynatorVSCode as the current dir.
Unzip D:\Prog\1396\RoslynatorVSCode\Roslynator.zip.
Delete VS specific files. Otherwise they will interfere with the MEF services inside OmniSharp.
Create C:\Users\Vahid\.omnisharp\omnisharp.json file.

Confirm
Are you sure you want to perform this action?
Performing the operation "Output to File" on target "C:\Users\Vahid\.omnisharp\omnisharp.json".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"):
Done!
ابتدا صفحه‌ی اصلی این افزونه دریافت می‌شود. سپس از داخل آن، پارامترهای مخصوص دانلود افزونه استخراج و آدرس دریافت نهایی آن تشکیل می‌شود.
در ادامه این افزونه دریافت شده و در پوشه‌ی جاری باز خواهد شد. سپس فایل omnisharp.json نیز به صورت خودکار تشکیل و مقدار دهی می‌شود.
اکنون اگر VSCode را اجرا کنید، همه چیز آماده بوده و امکانات این افزونه در دسترس خواهند بود.
نظرات مطالب
صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid
- قصد پشتیبانی از wrapperهای آن‌را ندارم. لطفا خارج از موضوع سؤال نپرسید. اگر کسی دوست داشت در این زمینه مطلب منتشر کند، خوب. ولی من چنین قصدی ندارم.
- عرض کردم اگر از wrapperها استفاده کنید، به علت عدم درک زیر ساخت اصلی Kendo UI، قادر به دیباگ کار نخواهید بود.
- اگر متن را مطالعه کنید در قسمت «پیشنیاز تامین داده مخصوص Kendo UI Grid » دقیقا شکل نهایی خروجی JSON مورد نیاز ارائه شده‌است. این خروجی در سه فیلد data، total و aggregate قرار می‌گیرد. شما الان فقط قسمت data آن‌را بازگشت داده‌اید؛ بجای اصل و کل آن. نام این سه فیلد هم مهم نیست؛ اما هر چیزی که تعیین می‌شوند، باید در قسمت data source در خاصیت schema آن مانند مثالی که در مطلب جاری آمده (در قسمت «تامین داده و نمایش گرید »)، دقیقا مشخص شوند، تا Kendo UI بداند که اطلاعات مختلف را باید از چه فیلدهایی از JSON خروجی دریافت کند.
مطالب
بررسی کارآیی کوئری‌ها در SQL Server - قسمت اول - جمع آوری اطلاعات آماری کوئری‌های زنده
بسیاری از شرکت‌ها دارای نقشی مانند «مدیران بانک اطلاعاتی» نیستند؛ اما تعدادی «توسعه دهنده‌ی بانک‌های اطلاعاتی» را به همراه دارند که گاهی از اوقات از آن‌ها خواسته می‌شود تا کارآیی پایین کوئری‌های صورت گرفته را بررسی و رفع کنند و ... آن‌ها دقیقا نمی‌دانند که باید از کجا شروع کنند! فقط می‌دانند که یک کوئری، مدت زمان زیادی را برای اجرا به خود اختصاص می‌دهد؛ اما نمی‌دانند که چگونه باید به کوئری پلن آن دسترسی یافت و چگونه باید آن‌را تفسیر کرد. در این حالت حداکثر کاری را که ممکن است انجام دهند، افزودن یک ایندکس جدید است که ممکن است کار کند و یا خیر و حتی اگر کار کند، دقیقا نمی‌دانند که چگونه! هدف از این سری، بررسی مقدماتی روش‌های بهبود کارآیی کوئری‌ها در SQL Server، از دید یک «توسعه دهنده‌ی بانک‌های اطلاعاتی» است.


پیشنیازهای این سری

در این سری از بانک اطلاعاتی استاندارد مثال به همراه SQL Server 2016، به نام WideWorldImporters استفاده می‌کنیم. برای دریافت آن، به قسمت releases مثال‌های مایکروسافت مراجعه کرده و فایل WideWorldImporters-Full.bak را دریافت کنید. پس از دریافت این فایل، برای restore سریع آن، می‌توانید دستور زیر را اجرا کنید که در آن باید مسیر فایل bak دریافتی و همچنین مسیر ایجاد فایل‌های mdf/ldf/ndf را مطابق مسیرهای سیستم خودتان اصلاح نمائید (فقط مسیر پوشه‌ها را نیاز است تغییر دهید):
use master;

RESTORE DATABASE WideWorldImporters 
FROM disk='D:\path\WideWorldImporters-Full.bak'
WITH MOVE 'WWI_Primary' TO 'D:\SQL_Data\WideWorldImporters.mdf',
MOVE 'WWI_Log' TO 'D:\SQL_Data\WideWorldImporters_log.ldf',
MOVE 'WWI_UserData' TO 'D:\SQL_Data\WideWorldImporters_UserData.ndf',
MOVE 'WWI_InMemory_Data_1' TO 'D:\SQL_Data\WideWorldImporters_InMemory_Data_1'
همچنین صرفنظر از نگارش SQL Server ای که در حال استفاده‌ی از آن هستید (البته به حداقل SQL Server 2016 نیاز خواهید داشت)، بهتر است آخرین نگارش برنامه‌ی management studio را نیز به صورت مستقل دریافت و نصب کنید که در این زمان نگارش 18.1 است.


یافتن اطلاعاتی در مورد کوئری‌ها

SQL Server زمانیکه یک کوئری را اجرا می‌کند، اطلاعاتی را نیز به همراه آن تولید خواهد کرد که سبب ایجاد یک Query Plan می‌شود و در آن، اطلاعاتی مانند جداول مورد استفاده، نوع جوین‌ها، ایندکس‌های استفاده شده و غیره وجود دارند. علاوه بر آن، Query Statistics نیز قابل دسترسی هستند که در آن مدت زمان اجرای یک کوئری، میزان I/O صورت گرفته و میزان مصرف CPU کوئری، ذکر می‌شوند. برای دسترسی یافتن به این اطلاعات، می‌توان به اشیاء مختلف SQL Server مراجعه کرد؛ مانند dynamic management objects یا به اختصار DMO's، همچنین extended events، traces، query stores و یا حتی management studio. مهم‌ترین تفاوت این‌ها نیز در نحوه‌ی دسترسی به اطلاعات آن‌ها است که می‌تواند زنده (live) و یا ذخیره شده در جائی باشند. در اینجا تنها منبعی که امکان مشاهده‌ی این اطلاعات را به صورت زنده میسر می‌کند، management studio است. البته live در اینجا به معنای امکان مشاهده‌ی تمام اطلاعات مرتبط با یک کوئری، مانند آمار و کوئری پلن آن در داخل محیط management studio، پس از اجرای یک کوئری است. در این قسمت بیشتر به روش استخراج اطلاعات آماری کوئری‌های زنده می‌پردازیم و در قسمت‌های بعدی، سایر گزینه‌های نامبرده شده را نیز بررسی خواهیم کرد.


مشاهده‌ی زنده‌ی داده‌های مرتبط با اجرای یک کوئری در management studio

پس از restore بانک اطلاعاتی مثال WideWorldImporters که عنوان شد، در برنامه‌ی Microsoft SQL Server Management Studio، کوئری زیر را اجرا می‌کنیم:
USE [WideWorldImporters];
GO

SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [c].[CountryName] = 'United States';
GO
با اجرای آن، اگر به ذیل ردیف‌های بازگشت داده شده‌ی در Management Studio دقت کنیم، مشخص کرده‌است که این کوئری، 53 ردیف را بازگشت داده و همچنین کمتر از 1 ثانیه مدت زمان اجرای آن، طول کشیده‌است:


اینجا است که نیاز به اطلاعات بیشتری در مورد نحوه‌ی اجرای این کوئری داریم. برای استخراج این اطلاعات، اینبار گزینه‌های تولید و جمع آوری اطلاعات آماری IO و TIME را روشن می‌کنیم و سپس همان کوئری قبلی را اجرا خواهیم کرد:
USE [WideWorldImporters];
GO

SET STATISTICS IO ON;
GO
SET STATISTICS TIME ON;
GO

SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [c].[CountryName] = 'United States';
GO
ظاهر اجرای این کوئری با کوئری قبلی، تفاوت خاصی ندارد. اما اگر در همینجا به برگه‌ی messages، که در کنار برگه‌ی results و نمایش ردیف‌ها قرار دارد، مراجعه کنیم، یک چنین خروجی قابل مشاهده است:
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 504 ms.

(53 rows affected)
Table 'Countries'. Scan count 0, logical reads 118, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'StateProvinces'. Scan count 1, logical reads 43, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 10 ms.
در اینجا اطلاعات آماری مدت زمان کامپایل و همچنین مدت زمان اجرای کوئری، ارائه شده‌اند. به علاوه در میانه‌ی این آمار، اطلاعات IO کوئری مانند logical reads درج شده‌اند.


استخراج اطلاعات Actual Execution Plan یک کوئری

کوئری را زیر با فرض IO ON و TIME ON حاصل از اجرای کوئری قبل، اجرا می‌کنیم:
USE [WideWorldImporters];
GO

SET STATISTICS XML ON;
GO

SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [c].[CountryName] = 'United States';
GO

SET STATISTICS XML OFF;
GO
با فعالسازی اطلاعات آماری XML (و خاموش کردن آن در انتهای کار)، اینبار در برگه‌ی messages، اطلاعات بیشتری ارائه شده‌اند:
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 7 ms.

(53 rows affected)
Table 'Countries'. Scan count 0, logical reads 118, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'StateProvinces'. Scan count 1, logical reads 43, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 15 ms,  elapsed time = 179 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
اگر دقت کنید اینبار زمان اجرا اندکی بیشتر شده‌است؛ چون درخواست تهیه‌ی query plan را داده‌ایم. این plan را در ذیل قسمت نتایج کوئری می‌توان مشاهده کرد:


اگر بر روی این XML کلیک کنیم، برگه‌ی جدید نمایش گرافیکی این plan ظاهر می‌شود:


با کلیک راست بر روی این برگه، می‌توان اطلاعات آن‌را جهت بررسی‌های بعدی و یا به اشتراک گذاری آن ذخیره کرد.
در این plan اگر اشاره‌گر ماوس را بر روی هر کدام از عناصر آن حرکت دهیم، اطلاعاتی مانند actual number of rows نیز مشاهده می‌شود، در کنار اطلاعات تخمینی؛ به همین جهت به آن Actual Execution Plan هم گفته می‌شود.


این یک روش دسترسی به Execution Plan است. روش دوم آن با استفاده از امکانات رابط کاربری خود Management Studio است؛ با فشردن دکمه‌های Ctrl+M و یا انتخاب گزینه‌ی Include actual execution plan از منوی Query آن. پس از آن کوئری زیر را اجرا کنید:
SET STATISTICS IO ON;
GO
SET STATISTICS TIME ON;
GO

SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [c].[CountryName] = 'United States';
GO
اینبار در برگه‌ی نتایج کوئری، برگه‌ی سوم Execution Plan قابل مشاهده‌است:




استخراج اطلاعات Estimated Execution Plan یک کوئری

تا اینجا نحوه‌ی استخراج اطلاعات Actual Execution Plan را بررسی کردیم که به همراه اطلاعات دقیق حاصل از اجرای کوئری نیز بود؛ مانند actual number of rows. نوع دیگری از Execution Planها را نیز می‌توان از SQL Server درخواست کرد که به آن‌ها Estimated Execution Plan گفته می‌شود و حاصل اجرای کوئری نیستند؛ بلکه تخمینی هستند از روش اجرای این کوئری توسط SQL Server. برای فعالسازی محاسبه‌ی آن، ابتدا کوئری زیر را در management studio انتخاب کنید:
USE [WideWorldImporters];
GO

SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [c].[CountryName] = 'United States';
GO
سپس از منوی Query، گزینه‌ی Display estimated execution plan را انتخاب نمائید و یا دکمه‌های Ctrl+L را فشار دهید. در این حالت برگه‌های حاصل، حاوی قسمت results نیستند؛ چون کوئری اجرا نشده‌است. اما هنوز برگه‌ی Execution Plan قابل مشاهده است:


همانطور که مشاهده می‌کنید، اینبار نتیجه‌ی حاصل، به همراه اطلاعاتی مانند actual number of rows نیست و صرفا تخمینی است از روش اجرای این کوئری، توسط SQL Server.


جمع آوری اطلاعات آماری کلاینت‌ها

در منوی Query، گزینه‌ای تحت عنوان Include client statistics نیز وجود دارد. با انتخاب آن، اگر کوئری زیر را اجرا کنیم:
USE [WideWorldImporters];
GO

SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [c].[CountryName] = 'United States';
GO
اینبار برگه‌ی جدید client statistics ظاهر می‌شود:


در اینجا مشخص می‌شود که آیا عملیات insert/update/delete انجام شده‌است. چه تعداد ردیف تحت تاثیر اجرای این کوئری قرار گرفته‌اند. چه تعداد تراکنش انجام شده‌است. همچنین اطلاعات آماری شبکه و زمان نیز در اینجا ارائه شده‌اند.
در همین حالت، کوئری جدید زیر را با تغییر قسمت where کوئری قبلی، اجرا کنید:
SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [s].[StateProvinceName] LIKE 'O%';
GO
نتیجه‌ی آن، ظاهر شدن ستون جدید trial 2 است که می‌تواند جهت مقایسه‌ی کوئری‌های مختلف با هم، بسیار مفید باشد:


در اینجا حداکثر 10 کوئری را می‌توان با هم مقایسه کرد و بیشتر از آن سبب حذف موارد قدیمی از لیست می‌شود.


عدم نمایش ردیف‌های بازگشت داده شده‌ی توسط کوئری در حین جمع آوری اطلاعات آماری

هربار اجرای یک کوئری در management studio، به همراه بازگشت و نمایش ردیف‌های مرتبط با آن کوئری نیز می‌باشد. اگر می‌خواهید در حین بررسی کارآیی کوئری‌ها از نمایش این ردیف‌ها صرف نظر کنید (تا بار این برنامه کاهش یابد)، می‌توانید از منوی Query، گزینه‌ی Query Options را انتخاب کرده و در قسمت Results، گزینه‌ی Grid آن، گزینه‌ی discard results after execution را انتخاب کنید تا دیگر برگه‌ی results نمایش داده نشود و وقت و منابع را تلف نکند. بدیهی است پس از پایان کار بررسی آماری، نیاز به عدم انتخاب این گزینه خواهد بود.
مسیرراه‌ها
AngularJS
مطالب
کش کردن اطلاعات غیر پویا در ASP.Net - قسمت دوم

قسمت قبل به IIS7‌ اختصاص داشت که شاید برای خیلی‌ها کاربرد نداشته باشد خصوصا اینکه برنامه نویس‌ها ترجیح می‌دهند به روش‌هایی روی بیاورند که کمتر نیاز به دخالت مدیر سرور داشته باشد؛ یا زمانیکه سایت شما بر روی یک هاست اینترنتی قرار گرفته است عملا شاید دسترسی خاصی به تنظیمات IIS نداشته باشید (مگر اینکه یک هاست اختصاصی را تهیه کنید).
برای IIS6 و ماقبل از آن و حتی بعد از آن!، حداقل دو روش برای کش کردن اطلاعات استاتیک وجود دارد:

الف) استفاده از web resources معرفی شده در ASP.Net 2.0 به بعد
در مورد نحوه‌ی تعریف و بکارگیری web resources می‌توان به مقاله "تبدیل پلاگین‌های jQuery‌ به کنترل‌های ASP.Net" رجوع کرد.


همانطور که در شکل فوق نیز ملاحظه می‌کنید، هدر مربوط به مدت زمان منقضی شدن کش سمت کلاینت یک web resource توسط موتور ASP.Net به صورت خودکار به سال 2010 تنظیم شده است و این مقدار خالی نیست.

ب) افزودن این هدر به صورت دستی

برای این منظور باید در نحوه‌ی ارائه فایل‌های استاتیک دخالت کنیم و این‌کار را با استفاده از یک generic handler می‌توان انجام داد.


کد این generic handler می‌تواند به صورت زیر باشد:

using System;
using System.IO;
using System.Web;
using System.Web.Services;
using System.Reflection;

namespace test1
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class cache : IHttpHandler
{

private static void cacheIt(TimeSpan duration)
{
HttpCachePolicy cache = HttpContext.Current.Response.Cache;

FieldInfo maxAgeField = cache.GetType().GetField("_maxAge", BindingFlags.Instance | BindingFlags.NonPublic);
maxAgeField.SetValue(cache, duration);

cache.SetCacheability(HttpCacheability.Public);
cache.SetExpires(DateTime.Now.Add(duration));
cache.SetMaxAge(duration);
cache.AppendCacheExtension("must-revalidate, proxy-revalidate");
}

public void ProcessRequest(HttpContext context)
{
string file = context.Request.QueryString["file"];
if (string.IsNullOrEmpty(file))
{
return;
}

string contetType = context.Request.QueryString["contetType"];
if (string.IsNullOrEmpty(contetType))
{
return;
}

context.Response.Write(File.ReadAllText(context.Server.MapPath(file)));

//Set the content type
context.Response.ContentType = contetType;

// Cache the resource for 30 Days
cacheIt(TimeSpan.FromDays(30));
}

public bool IsReusable
{
get
{
return false;
}
}
}
}
توضیحات:
این generic handler دو کوئری استرینگ را دریافت می‌کند؛ file جهت دریافت نام فایل و contetType جهت مشخص سازی نوع محتوایی که باید سرو شود؛ مثلا جاوا اسکریپت یا استایل شیت و امثال آن. سپس زمانیکه محتوا را Response.Write می‌کند، هدر مربوط به کش شدن آن‌را نیز به 30 روز تنظیم می‌نماید.
تابع مربوط به کش کردن اطلاعات از مقاله ASP.NET Ajax Under-the-hood Secrets استخراج شد.

روش استفاده در مورد فایل‌های CSS
بجای تعریف یک فایل CSS در صفحه، به صورت استاندارد، اکنون تعریف متداول را به صورت زیر اصلاح کنید:

<link type="text/css" href="cache.ashx?v=1&file=site.css&contetType=text/css" rel="Stylesheet" />
هر زمانیکه که فایل site.css درخواست می‌شود، باید از فیلتر ما عبور کند و سپس ارائه گردد. در این حین، هدر مربوط به مدت زمان کش شدن سمت کلاینت به آن اضافه می‌شود. از کوئری استرینگ مربوط v هم جهت به روز رسانی‌های بعدی استفاده می‌شود تا اگر تغییری را اعمال کردیم، کلاینت حتما با توجه به آدرس جدید، محتویات جدید را یکبار دیگر دریافت کند. (مرورگر آدرس‌های مشابه را در صورتیکه هدر مربوط به کش شدن آن‌ها تنظیم شده باشد، از کش خواهد خواند و کاری به آخرین تغییرات شما در سرور ندارد)

روش استفاده در مورد فایل‌های JS
<script type="text/javascript" src="cache.ashx?v=1&file=js/jquery-1.3.2.min.js&contetType=application/x-javascript"></script>
اکنون اگر سایت را مجددا با افزونه YSlow بررسی کنیم، می‌توان این هدر جدید را مشاهده کرد:



مطالب
چک لیست شروع به ساخت یک نرم افزار بزرگ یا متوسط
 کتابها و منابع آموزشی بسیاری در جهت یادگیری برنامه سازی و مهندسی نرم­ افزار وجود دارند که اکثراً هم مطالب مفید و بسیار خوبی را ارائه می­دهند؛ با این‌حال یکی از سؤالات بزرگی که بعد از مطالعه آنها در ذهن افراد ممکن است پیش بیاید این است که با خود می­پرسند حالا چه کنم؟ از کجا شروع کنم؟ در واقع ذهن افراد پر است از اطلاعات تخصصی بسیار مفید ولی نمیدانند آنها را چگونه سرهم بندی کنند تا یک سیستم نرم­ افزاری قابل اتکا تولید کنند. توسعه گران با تجربه با گذشت زمان، مطالعه کد نرم­ افزارهای موجود، مطالعه مضاعف، شرکت در بحثهای تخصصی و ... معمولاً می­دانند که باید از کجا شروع کنند. در اینجا بنده سعی کرد‌ه‌ام مواردی را که توسعه گران باتجربه در شروع ساخت یک نرم ­افزار متوسط یا بزرگ با رویکرد توسعه برای وب در مورد آنها تصمیم می­گیرند، به صورت مختصر توضیح دهم. طبیعی هست که ممکن است این لیست کامل نباشد، نظرات دوستان میتواند آنرا کاملتر کند.

در اینجا غیر از مورد زمانبندی انجام پروژه سعی شده است به دیگر موارد غیره از قبیل شناخت نیازمندیها، نحوه بستن قرارداد، نحوه قیمت دهی و ... اشاره نشود.

 

در ابتدا در مورد موضوعات کلی و عمومی بحث می‌کنیم.

1- انتخاب فریم­ورک، فریمورک‌های فراوان و مختلفی برای کار با زمینه­‌های مختلف نرم ­افزاری در جهان وجود دارند که هرکدام مزایا و معایبی دارند. این روزها استفاده از فریم‌ورکها به قدری جای افتاده است و به اندازه­‌ای امکانات دارند که حتی ممکن است امکانات یک فریم ورک باعث شود از یک زبانی که در تخصصتان نیست استفاده کنید و آنرا یاد بگیرید.

2- زمانبندی انجام پروژه، به نظر خود بنده، سخت‌ترین و اساسی‌ترین مرحله، برای هر پروژه‌­ای، زمانبندی مناسب آن است که نیازمندی اساسی آن، شناخت سایر مواردی است که در این متن بدان‌ها اشاره می­شود. زمانبندی دقیق، قرار ملاقاتها و تحویل به‌موقع پیش نمایشهای نرم­ افزار، ارتباط مستمر با کارفرما و تحویل حتی زودتر از موعد پروژه باعث رضایت بیشتر کارفرما و حس اطمینان بیشتر خواهد شد. اگر در تحویل پروژه دیرکرد وجود داشته باشد، باعث دلسردی کارفرما و نوعی تبلیغ منفی خواهد بود. حتی زمانبندی و تحویل به موقع پروژه برای کارفرما بیشتر از کیفیت اهمیت دارد.

3- انتخاب معماری نرم­ افزار، معماری نرم ­افزار در اصل تعیین کننده نحوه قطعه بندی و توزیع تکه‌های نرم افزار، نحوه ارتباط اجزاء،، قابلیت تست پذیری، قابلیت نگهداری و قابلیت استفاده مجدد از کدهای تولید شده می­باشد. یکی از اهداف اساسی‌ای که باید در معماری نرم­‌افزار بدان توجه کرد، قابلیت استفاده مجدد از کد است. در یک معماری خوب ما قطعاتی درست خواهیم کرد که به‌راحتی می­توانیم از آن در نرم‌افزارهای دیگر نیز استفاده کنیم. البته قابلیت تست پذیری و قابلیت نگهداری نیز حداقل به همان اندازه اهمیت دارند. در این سایت موارد بسیار زیاد و کاملی جهت ساخت معماری مناسب و design patterns وجود دارد که می­توانید در اینجا یا اینجا مشاهده کنید.

 4- قابلیت اجرا بر روی پلتفرمهای مختلف، هرچند این مورد ممکن است بیشتر به نظر کارفرما بستگی داشته باشد، اما در کل اگر کارفرما بتواند سیستم را در پلتفرمهای مختلفی اجرا کند، راضی‌تر خواهد شد. اگر قصد فروش نرم‌­افزار طراحی شده را داشته باشیم، در اینصورت نیز می­توانیم کاربران پلتفرمهای مختلف را مورد هدف قرار دهیم یا سیستم را در سرورهای مختلفی میزبانی کنیم.

5- انتخاب سیستم بانک اطلاعاتی و نحوه ارتباط با آن. باید تصمیم بگیرید که از چند سیستم بانک اطلاعاتی، چگونه و به چه منظوری استفاده خواهید کرد. مواردی وجود دارند که سیستم را طوری طراحی کرد‌ه‌اند تا در زمان بهره برداری امکان انتخاب بانک‌های اطلاعاتی یا نحوه ذخیره اطلاعات برای مدیر سیستم وجود دارد. مثلا در BlogEngine.net میتوان انتخاب کرد که اطلاعات در SQL Server ذخیره شوند یا در سیستم فایل مبتنی بر XML . بحثهای بسیار زیادی در این سایت و کل فضای وب پیرامون نحوه انتخاب و استفاده از ORM ها، چگونگی معماری مناسب آن وجود دارد. بطور مثال همیشه بحث سر اینکه از الگوی Repository استفاده شود یا نشود وجود دارد! باید به خودمان پاسخ دهیم که آیا واقعاً نیاز است که سیستم را برای امکان استفاده از Orm‌های مختلف طراحی کنیم؟

6- نحوه ماژول بندی سیستم و امکان افزودن راحت ماژولهای جدید به آن. امروزه و با افزایش کاربران محصولات انفورماتیک که باعث بیشتر شدن سواد مصرف کننده در این زمینه و بالطبع افزایش نیازهای وی شده، همیشه احتمال اینکه کارفرما موارد جدیدی را بخواهد وجود خواهد داشت. باید سیستم را طوری طراحی کرد که حتی بتوان بدون توقف اجرای آن موارد جدید (پلاگینهای جدید) را بدان افزود و اجرا کرد.

7- میزان مشارکت دیگران در رفع نیازمندیهای کابران. ممکن است این گزینه در درجه اول زیاد با اهمیت جلوه ندهد، اما با تعمق در وبسایت‌ها و نرم‌­افزارهای بزرگ که هم اکنون در دنیا صاحب نامی شده‌اند می‌بینیم همه آنها تمهیداتی اندیشیده‌اند تا با وجود کپسوله کردن موارد پس زمینه، امکاناتی را در جهت مشارکت دیگران فراهم کنند. اکثر شبکه­‌های اجتماعی api هایی را مهیا کرده­ اند که افراد ثالث می­توانند از آنها استفاده کنند. اکثر سیستم‌های مدیریت محتوا و ابزارهای e-commerce تمهیداتی را برای راحتی ساخت plugin و api‌های برای راحتی برقراری ارتباط اشخاص ثالث اندیشیده‌اند. از نظر این جانب موارد 6 و 7 برای ادامه حیات و قابلیت رقابت پذیری پروژه از درجه اهمیت زیادی برخوردار است.

8- معماری Multi tenancy بلی یا خیر؟ Multi tenancy یک از بحثهای مهم رایانش ابری است. در این حالت فقط یک نمونه از نرم­ افزار در سمت سرور در حال اجراست ولی کاربر یا گروهی از کاربران دید یا تنظیمات متفاوتی از آن‌را دارند.

در ادامه به موارد فنی‌تری خواهیم پرداخت:

9- بحث انتخاب ابزار Dependency injection مناسب و مهیا سازی امکاناتی جهت هرچه راحت‌تر کردن امکان تنظیم و register کردن اشیا بدان. نحوه پیکربندی مناسب این مورد می­تواند کد نویسی را برایتان بسیار راحت کند. دات نت تیپس مطالب بسیاری را در این مورد ارائه داده است میتوانید اینجا را ببینید.

10- کشینگ. استفاده از یک سیستم کشینگ مناسب در ارتباط با بانکهای اطلاعاتی و یا سایر سیستمهای ذخیره و بازیابی اطلاعات می­تواند کمک بسیاری در پرفرمنس برنامه داشته باشد. سیستمها و روشهای مختلفی در مورد کشینگ وجود دارند. می‌توانید برای اطلاعات بیشتر اینجا را مطالعه فرمایید.

11- Logging. یک سیستم لاگر مناسب می­تواند وارنینگ‌ها و خطاهای بوجود آمده در سیستم را در یک رسانه ذخیره سازی حفظ کند و شما به عنوان توسعه دهنده می­توانید با مطالعه آن نسبت به رفع خطاهای احتمالی و بهبود در نسخه‌های آتی کمک بگیرید.

12- Audit logging یا Activity logging و Entity History. می­توانید کل یا برخی از فعالیتهای کاربر را در یک رسانه ذخیره سازی، ذخیره کنید، از قبیل زمان ورود و خروج، آی‌پی مورد استفاده، سیستم عامل، مرورگر، بازبینی از صفحه وغیره. همچنین در audit logging میتوانید زمانهای دقیق تغییرات مختلف موجود در موجودیتهای سیستم، فرد انجام دهنده تغییرات، سرویس انجام دهنده تغییرات، مدت زمان سپری شده و ... را ذخیره کرد. Entity History : ممکن است تصمیم بگیرید که کل اتفاقاتی را که برای یک موجودیت در طول زمان حیاتش در سیستم می‌افتد، ذخیره کنید.

13- Eventing ، Background Worker‌ها و Backgroudn jobs ( Scheduled tasks ). باید سیستم را طوری طراحی کرد که بتواند به تغییرات و اتفاقات افتاده در سیستم پاسخ دهد. همچنین این مورد یکی از نیازمندیهای معماری بر اساس پلاگین است. Background Worker‌ها در واقع کارهایی هستند که در پس زمینه انجام میشوند و نیازی نیست که کاربر برای اتمام آن منتظر بماند؛ مثلاً ارسال ایمیل خوش آمدگویی را میتوان با آن انجام داد. Background jobs کمی متفاوت هستند در واقع اینها فعالیتهای پس زمینه­ای هستند که ممکن است در فواصل زمانی مختلف اتفاق بیافتند، مثل پاکسازی کش در فواصل زمانی مناسب. در سیستمهای مختلف تمهیداتی برای ذخیره سازی فعالیتهایی که توسط background jobs انجام میشود اندیشیده می­شود.

14- پیکربندی صحیح نحوه ذخیره و بازیابی تنظیمات سیستم. در یک سیستم ممکن است شما تنظیمات متعددی را در اختیار کاربر و یا حتی خودتان قرار دهید. باید سیستم را طوری طراحی کنید که بتواند با راحت‌ترین و سریعترین روش ممکن به تنظیمات موجود دستیابی داشته باشد.

15- خطاهای کاربر را در نظر بگیریم، باید یادمان باشد کاربر ممکن الخطاست و ما برای رضایت مشتری و قابلیت اتکای هرچه بیشتر برنامه باید سیستم را طوری طراحی کنیم که امکان برگشت از خطا برای کاربر وجود داشته باشد. مثلاً در SoftDelete مواردی که حذف می­شوند در واقع به طور کامل از بانک اطلاعاتی حذف نمیشوند بلکه تیک حذف شده میخورند. پس امکان بازگردانی وجود خواهد داشت.

16- Mapping یا Object to object mapping. در توسعه شی‌‌ءگرا مخصوصاً در معماری‌هایی مثل MVC یا Domain driven در موارد بسیاری نیاز خواهید داشت که مقادیر اشیاء مختلفی را در اشیای دیگری کپی کنید. سیستمهای زیادی برای این کار موجود هستند. باید تلاش کرد ضمن اینکه یک سیستم مناسب انتخاب کنیم، باید تمهیدی بیاندیشیم که تنظیمات آن شامل کد نویسی هرچه کمتری باشد.

17- Authorization یا تعیین هویت. باید با مطالعه و بررسی، سیستم و ابزار مناسبی را برای هویت سنجی اعضاء، تنظیم نقشها و دسترسی‌های کاربران انتخاب کرد. باید امکان عضویت از طریق شبکه‌های اجتماعی مختلف را مورد بررسی قرار داد.

18- سرویس‌های Realtime. کاربری یکی از مطالب شما را می­‌پسندد و شما نوتیفیکشن آنرا سریع در صفحه‌­ای که باز کردید می­بینید. این یک مورد بسیار کوچکی از استفاده از سرویسهای realtime هست. ابزارهای مختلفی برای زبانها و فریم‌ورکهای مختلف وجود دارند؛ مثلاً میتوانید اینجا را مطالعه کنید.

19- هندل کردن خطاهای زمان اجرا، در سیستمهای قدیمی یکی از کابوس‌های کاربران، قطعی سیستم، هنگ کردن با کوچکترین خطا و موارد این چنینی بود. با تنظیم یک سیستم Exception handling مناسب هم میتوانیم گزارشاتی از خطاهای بوجود آمده را تهیه کنیم، هم میتوانیم کاربر را در جهت انجام صحیح کارها هدایت کنیم و هم از کرش بیجای نرم‌افزار جلوگیری کنیم.

20- استفاده از منابع ابری یا توزیع شده، امروزه برای بسیاری از کارها تمهیداتی از طرف شرکتهای بزرگ به صورت رایگان و یا غیر رایگان اندیشیده شده است که به راحتی می­توان از آنها استفاده کرد. برای نمونه میتوان از سرویسهای Email به عنوان ساده‌ترین و معمول‌ترین این سیستمها یاد کرد. اما امروزه شرکتها حتی امکاناتی جهت ذخیره سازی داده‌های blob (مجموعه ای از بایتها با حجم زیاد) را ارائه می­دهند؛ امکانات دیگری نظیر کم کردن حجم تصاویر، تبدیل انواع mime type‌ها و ...

21- امنیت، فریم‌ورکها اغلب موارد امنیتی پایه‌ای را به صورت مطلوب یا نسبتا مطلوبی رعایت می­کنند؛ ولی با این‌حال باید در مورد امنیت سیستمی که توسعه می‌دهیم مطالعه داشته باشیم و موارد امنیتی ضروری را رعایت کنیم و همیشه مواظب باشیم که آنها را رعایت کنیم.