۱۳۸۷/۱۲/۱۰

اضافه كردن قابليت از سرگيري مجدد (resume) به HttpWebRequest


مطابق RFC مربوطه، اگر هدر درخواست ارسالي به سرور را كمي تغيير دهيم مي‌توان بجاي شروع از اولين بايت، از بايت مورد نظر شروع به دريافت فايل نمود. (البته اين به شرطي است كه سرور آن‌را پشتيباني كند)

يعني نياز داريم كه به هدر ارسالي سطر زير را اضافه كنيم:
Range: bytes=n-
كه n در اينجا حجم فايل ناقص دريافتي موجود بر حسب بايت است.
براي بدست آوردن اندازه‌ي فايل ناقص موجود مي‌توان از دستور زير استفاده كرد:
using System.IO;
long brokenLen = new FileInfo(fileNamePath).Length;

سپس اگر شيء webRequest ما به صورت زير تعريف شده باشد:

HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);

فقط كافي است سطر زير را جهت افزودن قابليت از سرگيري مجدد دريافت فايل به اين شيء افزود:

//دانلود از ادامه
webRequest.AddRange((int)brokenLen); //resume

نكته:
اگر علاقمند باشيد كه ريز فعاليت‌هاي انجام شده توسط فضاي نام System.Net را ملاحظه كنيد، به فايل config خود (مثلا فايل app.config برنامه)، چند سطر زير را اضافه كنيد:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.Net">
<listeners>
<add name="MyTraceFile"/>
</listeners>
</source>
</sources>

<sharedListeners>
<add
name="MyTraceFile"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="System.Net.trace.log"
/>
</sharedListeners>

<switches>
<add name="System.Net" value="Verbose" />
</switches>

</system.diagnostics>
</configuration>
به اين صورت كليه هدرهاي ارسالي به سرور و ريز فعاليت‌هاي انجام شده در پشت صحنه‌ي كلاس‌هاي موجود در فايلي به نام System.Net.trace.log براي شما ثبت خواهد شد.


ملاحظات:
بديهي است پياده سازي قابليت resume نياز به موارد زير خواهد داشت:
الف) در نظر گرفتن مسيري پيش فرض براي ذخيره سازي فايل‌ها
ب) پيدا كردن اندازه‌ي فايل موجود بر روي يك سرور و مقايسه‌ي آن با حجم فايل موجود بر روي هارد
امكان پيدا كردن اندازه‌ي يك فايل هم بدون دريافت كامل آن ميسر است. خاصيت ContentLength مربوط به شيء HttpWebResponse بيانگر اندازه‌ي يك فايل بر روي سرور است و صد البته پيش از استفاده از اين عدد، مقدار StatusCode شيء نامبرده را بررسي كنيد. اگر مساوي OK بود، يعني اين عدد معتبر است.

۱۳۸۷/۱۲/۰۹

مشكل چشمك زدن (Flicker) در كنترل ListView


با هر بار اضافه كردن يك سطر به ListView ، تمام ناحيه پس زمينه كنترل به روز شده و مشكل چشمك زدن (Flicker) آزار دهنده‌اي را پديد مي‌آورد. راه حل‌هاي زيادي براي رفع اين مشكل وجود دارد. براي مثال استفاده از متدهاي BeginUpdate و EndUpdate قبل و پس از افزودن تعداد زيادي ركورد به يك ListView . اما اگر اين كنترل توسط چند ترد در حال به روز رساني باشد و هربار هم تعداد آيتم‌هاي اضافه شده آنچنان زياد نباشد، اين روش اثري نداشته و باز هم مشكل flickering وجود خواهد داشت.
رفع اين مشكل راه حل بسيار ساده‌اي دارد كه به شرح زير است:

يك user control جديد ايجاد كنيد، آن‌را از ListView به ارث برده و سپس سطر زير را به constructor آن اضافه كنيد:

this.DoubleBuffered = true;

اكنون از اين ListView سفارشي بجايlistView استاندارد استفاده كنيد، مشكل برطرف مي‌شود!

public partial class CustomListView : ListView
{
public CustomListView()
{
this.DoubleBuffered = true;
}
}
شبيه به همين مورد را جهت كنترل ListBox نيز مي‌توان پياده سازي كرد

۱۳۸۷/۱۲/۰۸

لينك‌هاي هفته‌ي دوم اسفند


وبلاگ‌ها ، سايت‌ها و مقالات ايراني (داخل و خارج از ايران)

امنيت

Visual Studio

ASP. Net

طراحي و توسعه وب

PHP

اس‌كيوال سرور

سي شارپ

VB

CPP

عمومي دات نت

مسايل اجتماعي و انساني برنامه نويسي

متفرقه

۱۳۸۷/۱۲/۰۷

آيا از وضعيت رويه‌هاي ذخيره شده‌ي ديتابيس‌هاي اس كيوال سرور خود خبر داريد؟


به لطف امكانات سيستمي اس كيوال سرورهاي 2005 به بعد و DMV هاي آن‌ها، آمارگيري از ريز اتفاقات رخ داده در يك اس كيوال سرور اين روزها بسيار ساده شده است و نيازي به ابزارهاي جانبي براي انجام اين نوع عمليات نيست (يا كمتر هست). در ادامه مروري خواهيم داشت بر يك سري كوئري كه اطلاعات جالبي را در مورد وضعيت رويه‌هاي ذخيره شده‌ي ديتابيس‌هاي شما ارائه مي‌دهند. لازم به ذكر است كه اكثر اين آمارها با هر بار ري استارت سرور، صفر خواهند شد.

آيا مي‌دانيد در يك ديتابيس خاص كداميك از رويه‌هاي ذخيره شده‌ي شما بيش از سايرين مورد استفاده بود و آماري از اين دست؟

use dbName;
SELECT TOP(100) qt.text AS 'SP Name',
qs.execution_count AS 'Execution Count',
qs.execution_count / DATEDIFF(Second, qs.creation_time, GETDATE()) AS
'Calls/Second',
qs.total_worker_time / qs.execution_count AS 'AvgWorkerTime',
qs.total_worker_time AS 'TotalWorkerTime',
qs.total_elapsed_time / qs.execution_count AS 'AvgElapsedTime',
qs.max_logical_reads,
qs.max_logical_writes,
qs.total_physical_reads,
DATEDIFF(Minute, qs.creation_time, GETDATE()) AS 'Age in Cache'
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
WHERE qt.dbid = DB_ID() -- Filter by current database
ORDER BY
qs.execution_count DESC

البته مرتب سازي پيش فرض اين كوئري بر اساس تعداد بار اجرا است (رويه‌هاي ذخيره شده‌ي محبوب!)، مي‌شود آن‌را بر اساس total_worker_time (فشار بر روي CPU سيستم)، total_logical_reads (فشار بر روي حافظه)، total_physical_reads (فشار I/O كوئري‌ها)، total_logical_writes نيز مرتب كرد و نتايج جالب توجهي را بدست آورد.


آيا مي‌دانيد كداميك از رويه‌هاي ذخيره شده‌ي شما بيش از سايرين كامپايل مجدد شده است؟

select top 50
sql_text.text,
sql_handle,
plan_generation_num,
execution_count,
dbid,
objectid
from
sys.dm_exec_query_stats a
cross apply sys.dm_exec_sql_text(sql_handle) as sql_text
where
plan_generation_num >1
order by plan_generation_num desc

آيا مي‌دانيد آخرين باري كه رويه‌هاي ذخيره شده‌ي شما ويرايش شده‌اند چه زماني بوده است؟

SELECT NAME,
create_date,
modify_date
FROM sys.objects
WHERE TYPE = 'P'
ORDER BY
Modify_Date DESC,
NAME

۱۳۸۷/۱۲/۰۶

Postable


ارسال سورس كد برنامه‌ها در بلاگر داستان خودش را دارد كه پيشتر در مورد آن بحث شد.
اما اين‌كار (تبديل كاراكترهاي غيرمجاز به نمونه‌هاي مجاز يا به اصطلاح escape آن‌ها) پس از يك مدت تبديل به دردسر خواهد شد. به همين جهت برنامه‌ي كوچك زير را براي ساده‌تر كردن اين وضع تهيه كرده‌ام، كه از آدرس زير قابل دريافت است:



دريافت برنامه (براي اجرا نياز به دات نت فريم ورك 2 دارد)

اين برنامه‌ي كمكي، انجام چند كار زير را در بلاگر براي شما ساده‌تر خواهد كرد:
الف) escape خودكار كاراكترهاي غيرمجاز xml هنگام ارسال سورس كدهاي خود و همچنين قرار دادن آن‌ها داخل تگ‌هاي div و pre مناسب.

روش برنامه نويسي آن:

public static string EscapeXml(string s)
{
var xml = s;
if (!string.IsNullOrEmpty(xml))
{
// replace literal values with entities
xml = xml.Replace("&", "&amp;");
xml = xml.Replace("<", "&lt;");
xml = xml.Replace(">", "&gt;");
xml = xml.Replace("\"", "&quot;");
xml = xml.Replace("'", "&apos;");
}
return xml;
}
ب) حذف خطوط بين تگ‌هاي html . اين مورد هنگام ارسال يك table استاندارد html در بلاگر لازم است. براي مثال در بلاگر ارسال كد زير
<table>
<tr>
<td>data
</td>
</tr>
سبب ايجاد فواصل عجيبي در حين نمايش رديف‌هاي جدول در سايت خواهد شد، زيرا بلاگر به ازاي هر خط جديد يك br را به صورت خودكار نمايش خواهد داد. براي رفع اين مشكل از دكمه remove html new lines استفاده كنيد. به اين صورت اطلاعات فوق به صورت خودكار به شكل زير تبديل مي‌شوند:

<table> <tr> <td>data</td> </tr>

روش برنامه نويسي آن :

private static readonly Regex REGEX_BETWEEN_TAGS = new Regex(@">\s+<", RegexOptions.Compiled);
private static readonly Regex REGEX_LINE_BREAKS = new Regex(@"\n\s+", RegexOptions.Compiled);
public static string RemoveSpaces(string html)
{
html = REGEX_BETWEEN_TAGS.Replace(html, "> <");
return REGEX_LINE_BREAKS.Replace(html, string.Empty);

}

ج) حذف كاراكتر 0xA0 . البته اين مورد ارتباطي به بلاگر پيدا نمي‌كند ولي اگر با CPP كار كرده باشيد، حتما به مورد كپي سورس از اينترنت به داخل اديتور و عدم كامپايل آن، برخورده‌ايد. در سورس كدهاي CPP مجاز به استفاده از كاراكتر No-Break Space نيستيد (0xA0) و بايد حذف شود. حال فرض كنيد با بيش از 200 سطر سر و كار داريد. بنابراين نياز به يك تميز كننده سريع وجود خواهد داشت. (اين مورد در اديتور برنامه management studio اس كيوال سرور هم صادق است)

txtMod.Text = txtOrig.Text.Replace((char)160, ' ');
ساده است ولي انجام دستي آن مشكل خواهد بود.

۱۳۸۷/۱۲/۰۵

زيباتر كد بنويسيم


داشتن آگاهي در مورد ساختارهاي داده‌‌ها، الگوريتم‌ها و يا عملگرهاي بيتي بسيار عالي است و يا تسلط بر نحوه‌ي كاركرد ابزارهايي مانند SharePoint و امثال آن اين روزها ضروري است. اما بايد در نظر داشت، كدي كه امروز تهيه مي‌شود شايد فردا يا ماه ديگر يا چند سال بعد نياز به تغيير داشته باشد، بنابراين دانش زيبا نوشتن يك قطعه كد كه خواندن آن‌را ساده‌تر مي‌كند و در آينده افرادي كه از آن نگهداري خواهند كرد زياد "زجر" نخواهند كشيد، نيز ضروري مي‌باشد. (اگر كامنت‌هاي سايت را خوانده باشيد يكي از دوستان پيغام گذاشته بود، اگر به من بگويند يك ميليون بگيريد و برنامه فعلي را توسعه دهيد يا رفع اشكال كنيد، حاضرم 10 هزارتومان بگيرم و آن‌را از صفر بنويسم! متاسفانه اين يك واقعيت تلخ است كه ناشي از عدم خوانا بودن كدهاي نوشته شده مي‌باشد.)
در ادامه يك سري از اصول زيبا نويسي كدها را بررسي خواهيم كرد.


1- سعي كنيد ميزان تو در تو بودن كدهاي خود را محدود كنيد.
لطفا به مثال زير دقت نمائيد:

void SetA()
{
if(a == b)
{
foreach(C c in cs)
{
if(c == d)
{
a = c;
}
}
}
}

توصيه شده است فقط يك سطح تو در تو بودن را در يك تابع لحاظ كنيد. تابع فوق 4 سطح تو رفتگي را نمايش مي‌دهد (براي رسيدن به a=c بايد چهار بار از tab استفاده كنيد). براي كاهش اين تعداد سطح مي‌توان به صورت زير عمل كرد:

void SetA()
{
if(a != b)
return;

foreach(C c in cs)
a = GetValueOfA(c);
}

TypeOfA GetValueOfA(C c)
{
if(c == d)
return c;

return a;
}

خواناتر نشد؟!

افزونه‌هاي CodeRush و refactor pro مجموعه‌ي DevExpress از لحاظ مباحث refactoring در ويژوال استوديو حرف اول را مي‌زنند. فقط كافي است براي مثال قطعه كد if داخلي را انتخاب كنيد، بلافاصله سه نقطه زير آن ظاهر شده و با كليك بر روي آن امكان استخراج يك تابع از آن‌را براي شما به سرعت فراهم خواهد كرد.



مثالي ديگر:

if (foo) {
if (bar) {
// do something
}
}

به صورت زير هم قابل نوشتن است (جهت كاهش ميزان nesting):

if (foo && bar) {
// do something
}

افزونه‌ي Resharper امكان merge خودكار اين نوع if ها را به همراه دارد.



و يا يك مثال ديگر:
ميزان تو در تو بودن اين تابع جاوا اسكريپتي را ملاحظه نمائيد:

function findShape(flags, point, attribute, list) {
if(!findShapePoints(flags, point, attribute)) {
if(!doFindShapePoints(flags, point, attribute)) {
if(!findInShape(flags, point, attribute)) {
if(!findFromGuide(flags,point) {
if(list.count() > 0 && flags == 1) {
doSomething();
}
}
}
}
}
}

آن‌را به صورت زير هم مي‌توان نوشت با همان كارآيي اما بسيار خواناتر:

function findShape(flags, point, attribute, list) {
if(findShapePoints(flags, point, attribute)) {
return;
}

if(doFindShapePoints(flags, point, attribute)) {
return;
}

if(findInShape(flags, point, attribute)) {
return;
}

if(findFromGuide(flags,point) {
return;
}

if (!(list.count() > 0 && flags == 1)) {
return;
}

doSomething();
}

2- نام‌هاي با معنايي را براي متغيرها وتوابع خود انتخاب كنيد.
با وجود پيشرفت‌هاي زيادي كه در طراحي و پياده سازي IDE ها صورت گرفته و با بودن ابزارهاي تكميل سازي خودكار متن تايپ شده در آن‌ها، اين روزها استفاده از نام‌هاي بلند براي توابع يا متغيرها مشكل ساز نيست و وقت زيادي را تلف نخواهد كرد. براي مثال به نظر شما اگر پس از يك سال به كدهاي زير نگاه كنيد كداميك خود توضيح دهنده‌تر خواهند بود (بدون مراجعه به مستندات موجود)؟

void UpdateBankAccountTransactionListWithYesterdaysTransactions()
//or?
void UpdateTransactions()

3- تنها زماني از كامنت‌ها استفاده كنيد كه لازم هستند.
اگر مورد 2 را رعايت كرده باشيد، كمتر به نوشتن كامنت نياز خواهد بود. از توضيح موارد بديهي خودداري كنيد، زيرا آن‌ها بيشتر سبب اتلاف وقت خواهند شد تا كمك به افراد ديگر يا حتي خود شما. همچنين هيچگاه قطعه كدي را كه به آن نياز نداريد به صورت كامنت شده به مخزن كد در يك سيستم كنترل نگارش ارسال نكنيد.

//function thisReallyHandyFunction() {
// someMagic();
// someMoreMagic();
// magicNumber = evenMoreMagic();
// return magicNumber;
//}

زمانيكه از ورژن كنترل استفاده مي‌كنيد نيازي به كامنت كردن قسمتي از كد كه شايد در آينده قرار است مجددا به آن بازگشت نمود، نيست. اين نوع سطرها بايد از كد شما حذف شوند. تمام سيستم‌هاي ورژن كنترل امكان revert و بازگشت به قبل را دارند و اساسا اين يكي از دلايلي است كه از آن‌ها استفاده مي‌شود!
به صورت خلاصه جهت نگهداري سوابق كدهاي قديمي بايد از سورس كنترل استفاده كرد و نه به صورت كامنت قرار دادن آن‌ها.

از كامنت‌هاي نوع زير پرهيز كنيد كه بيشتر سبب رژه رفتن روي اعصاب خواننده مي‌شود تا كمك به او! (خواننده را بي‌سواد فرض نكنيد)

// Get the student's id
thisId = student.getId();

كامنت زير بي معني است!

// TODO: This is too bad. FIX IT!

اگر شخص ديگري به آن مراجعه كند نمي‌داند كه منظور چيست و دقيقا مشكل كجاست. شبيه به افرادي كه به فوروم‌ها مراجعه مي‌كنند و مي‌گويند برنامه كار نمي كند و همين! طرف مقابل علم غيب ندارد كه مشكل شما را حدس بزند! به توضيحات بيشتري نياز است.


4- عدم استفاده از عبارات شرطي بي‌مورد هنگام بازگشت دادن يك مقدار bool:
مثال زير را درنظر بگيريد:

if (foo>bar) {
return true;
} else {
return false;
}

آن‌را به صورت زير هم مي‌توان نوشت:

return foo>bar;

5- استفاده از متغيرهاي بي مورد:
براي مثال:

Something something = new Something(foo);
return something;

كه مي‌شود آ‌ن را به صورت زير هم نوشت:

return new Something(foo);

البته يكي از خاصيت‌هاي استفاده از افزونه‌ي Resharper ويژوال استوديو، گوشزد كردن و اصلاح خودكار موارد 4 و 5 است.



6- در نگارش‌هاي جديد دات نت فريم ورك استفاده از ArrayList منسوخ شده است. بجاي آن بهتر است از ليست‌هاي جنريك استفاده شود. كدي كه در آن از ArrayList استفاده مي‌شود طعم دات نت فريم ورك 1 را مي‌دهد!

7- لطفا بين خطوط فاصله ايجاد كنيد. ايجاد فواصل مجاني است!

دو تابع جاوا اسكريپتي زير را (كه در حقيقت يك تابع هستند) در نظر بگيريد:

function getSomeAngle() {
// Some code here then
radAngle1 = Math.atan(slope(center, point1));
radAngle2 = Math.atan(slope(center, point2));
firstAngle = getStartAngle(radAngle1, point1, center);
secondAngle = getStartAngle(radAngle2, point2, center);
radAngle1 = degreesToRadians(firstAngle);
radAngle2 = degreesToRadians(secondAngle);
baseRadius = distance(point, center);
radius = baseRadius + (lines * y);
p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);
pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
// Now some more code
}

function getSomeAngle() {
// Some code here then
radAngle1 = Math.atan(slope(center, point1));
radAngle2 = Math.atan(slope(center, point2));

firstAngle = getStartAngle(radAngle1, point1, center);
secondAngle = getStartAngle(radAngle2, point2, center);

radAngle1 = degreesToRadians(firstAngle);
radAngle2 = degreesToRadians(secondAngle);

baseRadius = distance(point, center);
radius = baseRadius + (lines * y);

p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);

pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
// Now some more code

}

كداميك خواناتر است؟
استفاده از فاصله بين خطوط در تابع دوم باعث بالا رفتن خوانايي آن شده است و اين طور به نظر مي‌رسد كه سطرهايي با عملكرد مشابه در يك گروه كنار هم قرار گرفته‌اند.

8- توابع خود را كوتاه كنيد.
يك تابع نبايد بيشتر از 50 سطر باشد (البته در اين مورد بين علما اختلاف هست!). اگر بيشتر شد بدون شك نياز به refactoring داشته و بايد به چند قسمت تقسيم شود تا خوانايي كد افزايش يابد.
به صورت خلاصه يك تابع فقط بايد يك كار را انجام دهد و بايد بتوان عملكرد آن‌را در طي يك جمله توضيح داد.

9- از اعداد جادويي در كدهاي خود استفاده نكنيد!
كد زير هيچ معنايي ندارد!

if(mode == 3){ ... }
else if(mode == 4) { ... }

بجاي اين اعداد بي مفهوم بايد از enum استفاده كرد:

if(mode == MyEnum.ShowAllUsers) { ... }
else if(mode == MyEnum.ShowOnlyActiveUsers) { ... }

10- توابع شما نبايد تعداد پارامتر زيادي داشته باشند
اگر نياز به تعداد زيادي پارامتر ورودي وجود داشت (بيش از 6 مورد) از struct و يا كلاس جهت معرفي آن‌ها استفاده كنيد.

۱۳۸۷/۱۲/۰۴

آشنايي با Oslo - قسمت سوم


اگر علاقمند باشيد كه دو قسمت قبل را به صورت آموزش ويديويي ملاحظه كنيد، لطفا ويديوهاي رايگان زير را دريافت نمائيد. اين ويديوها قسمت اجرا كردن اسكريپت حاصل روي يك ديتابيس را هم در آخر نمايش داده (علاوه بر مدلسازي و نمايش T-SQL حاصل) و شما را با Quadrant نيز آشنا خواهند كرد.


مآخذ:
biztalkgurus.com و bloggersguides.net

۱۳۸۷/۱۲/۰۳

آشنايي با Oslo - قسمت دوم


قبل شروع اين قسمت بد نيست با يك سري از وبلاگ‌هاي اعضاي تيم Oslo آشنا شويم:


در ادامه‌ي مثال قسمت قبل، اكنون مي‌خواهيم entity جديدي به نام Project را به مدل اضافه كنيم:

//mschema to define a Project type
type Project
{
ProjectID : Integer64 = AutoNumber();
ProjectName : Text#25;
ConectionStringSource : Text;
ConectionStringDestination : Text;
DateCompared: DateTime;
Comment: Text?;
ProjectOwner: ApplicationUser;
} where identity ProjectID;

مطابق تعاريف فوق، فيلد ProjectOwner ارجاعي را به نوع ApplicationUser كه پيشتر ايجاد كرديم دارد. اكنون براي مشاهده‌ي تغييرات حاصل شده نياز به ايجاد يك جدول از روي اين نوع جديد است كه foreign key آن به صورت زير تعريف مي‌شود:

//this will define a SQL foreign key relationship
ProjectCollection : Project* where item.ProjectOwner in ApplicationUserCollection;

پس از افزودن اين سطر، Intellipad بلافاصله اسكريپت T-SQL آن‌را براي ما ايجاد مي‌كند كه به شرح زير است:

set xact_abort on;
go

begin transaction;
go

set ansi_nulls on;
go

create schema [Test1];
go

create table [Test1].[ApplicationUserCollection]
(
[UserID] bigint not null identity,
[FirstName] nvarchar(max) null,
[LastName] nvarchar(25) not null,
[Password] nvarchar(10) not null,
constraint [PK_ApplicationUserCollection] primary key clustered ([UserID])
);
go

create table [Test1].[ProjectCollection]
(
[ProjectID] bigint not null identity,
[Comment] nvarchar(max) null,
[ConectionStringDestination] nvarchar(max) not null,
[ConectionStringSource] nvarchar(max) not null,
[DateCompared] datetime2 not null,
[ProjectName] nvarchar(25) not null,
[ProjectOwner] bigint not null,
constraint [PK_ProjectCollection] primary key clustered ([ProjectID]),
constraint [FK_ProjectCollection_ProjectOwner_Test1_ApplicationUserCollection] foreign key ([ProjectOwner]) references [Test1].[ApplicationUserCollection] ([UserID])
);
go

insert into [Test1].[ApplicationUserCollection] ([FirstName], [LastName], [Password])
values (N'user1', N'name1', N'1@34')
;

insert into [Test1].[ApplicationUserCollection] ([FirstName], [LastName], [Password])
values (N'user2', N'name2', N'123@4')
;

insert into [Test1].[ApplicationUserCollection] ([FirstName], [LastName], [Password])
values (N'user3', N'name3', N'56#2')
;

insert into [Test1].[ApplicationUserCollection] ([FirstName], [LastName], [Password])
values (N'user4', N'name4', N'789@5')
;
go

commit transaction;

Go

همانطور كه ملاحظه‌ مي‌كنيد، هنگام كار كردن با يك مدل، نگهداري و توسعه‌ي آن واقعا ساده‌تر است از ايجاد اين دستورات T-SQL .

نكته:
جهت آشنايي با انواع داده‌هاي مجاز در زبان M مي‌توان به مستندات رسمي آن مراجعه نمود:
The "Oslo" Modeling Language Specification

اكنون قصد داريم همانند مثال قسمت قبل، تعدادي ركورد آزمايشي را براي اين جدول تعريف كنيم:

ProjectCollection
{
Project1{
ProjectName = "My Project 1",
ConectionStringSource = "Data Source=.;Initial Catalog=MyDB1;Integrated Security=True;",
ConectionStringDestination = "Data Source=.;Initial Catalog=MyDB2;Integrated Security=True;",
Comment="Project Comment",
DateCompared=2009-01-01T00:00:00,
ProjectOwner=ApplicationUserCollection.User1 //direct ref to User1 (FK)
},
Project2{
ProjectName = "My Project 2",
ConectionStringSource = "Data Source=.;Initial Catalog=MyDB1;Integrated Security=True;",
ConectionStringDestination = "Data Source=.;Initial Catalog=MyDB2;Integrated Security=True;",
Comment="Project Comment",
DateCompared=2009-01-01T00:00:00,
ProjectOwner=ApplicationUserCollection.User2 //direct ref to User2 (FK)
}

}

چون بين ProjectOwner و ApplicationUserCollection رابطه ايجاد كرده‌ايم، هنگام استفاده از آن‌ها، برنامه Intellipad جهت سهولت كار، IntelliSense مربوطه را نيز نمايش خواهد داد :


ادامه دارد ...

۱۳۸۷/۱۲/۰۲

آشنايي با Oslo - قسمت اول


Oslo پلتفرم جديد مدل‌سازي مايكروسافت است كه در سال‌هاي آتي مورد استفاده قرار خواهد گرفت و همچنين اين روزها در مجامع توسعه و طراحي برنامه‌ها به شدت مورد بحث و توجه است. به همين جهت در طي مقالاتي با اين پلتفرم جديد بيشتر آشنا خواهيم شد.

دريافت Oslo

Oslo از سه قسمت عمده تشكيل شده است:
  • الف) زبان مدل سازي M
  • ب) ابزار مدل سازي Quadrant
  • ج) استفاده از SQL Server به عنوان مخزن

زبان مدل سازي M از سه قسمت به نام‌هاي MGraph ، MGrammer و MSchema تشكيل مي‌شود.
MGrammer : گرامر مورد استفاده در SDL را تعريف مي‌كند. Syntax Directed Translation
MSchema : طرح مدل را تعريف خواهد كرد.
MGraph : اگر MSchema بيانگر انواع باشد، MGraph بيانگر وهله‌ها خواهد بود.

يك مثال:
برنامه‌ي Intellipad را اجرا كنيد (فرض بر اين است كه SDK فوق را نصب كرده‌ايد)



در اينجا حالت را بر روي M Mode قرار دهيد (مطابق تصوير) و همچنين از منوي ظاهر شده‌ي M Mode ، گزينه‌ي Generic T-SQL preview را هم انتخاب كنيد.

اولين ماژول ما به صورت زير است:

module Test1
{
type ApplicationUser
{
UserID : Integer64=AutoNumber();
FirstName :Text#15;
LastName : Text#25;
Password : Text#10;
} where identity UserID;
}

ابتدا نام ماژول مشخص مي‌شود. شبيه به معرفي يك فضاي نام در برگيرنده‌ي اشياي مربوطه. سپس type ، بيانگر همان MSchema خواهد بود.
در اين مثال شناسه‌ي كاربري از نوع Integer64 خود افزايش يابنده تعريف شده است (نوع identity در اس كيوال سرور).
فيلدهاي نام ، نام خانوادگي و كلمه‌ي عبور از نوع متني با اندازه‌هاي مشخص 15 ، 25 و 10 كاراكتر تعريف شده‌اند. اگر اندازه مشخص نبود نوع را تنها Text تعريف كنيد.
نكته:
1-اگر پس از Text علامت ? قرار گيرد، به معناي فيلدي از نوع nullable خواهد بود و برعكس. زيبايي Intellipad هم در اينجا است كه بلافاصله پس از تايپ شما، عبارت T-SQL معادل را توليد مي‌كند.
2-در اينجا UserID‌ به صورت identity معرفي شده است. در زبان ام ، identity همانند primary key‌ در عبارات T-SQL عمل مي‌كند و نبايد اشتباه گرفته شود.

تا اينجا فقط يك type تعريف شده است. براي تبديل آن به يك جدول بايد آن‌را توسعه داد.

ApplicationUserCollection : ApplicationUser*;

اين سطر را به پس از تعريف type اضافه نمائيد. علامت ستاره در اينجا به معناي صفر يا بيشتر است و جهت بسط نوع تعريف شده به يك مجموعه به كار مي‌رود. اكنون با اضافه شدن اين سطر، Intellipad بلافاصله عبارات T-SQL معادل را توليد خواهد كرد كه در تصوير مشخص است. به اين صورت MGraph ما كه بيانگر وهله‌هايي از نوع ApplicationUser هستند توليد گرديد.

اكنون قصد داريم گروهي از كاربرها را به صورت نمونه ايجاد كنيم:

ApplicationUserCollection
{
//using a named instance
User1 {
FirstName="user1",
LastName="name1",
Password="1@34"
},
User2 {
FirstName="user2",
LastName="name2",
Password="123@4"
},
User3 {
FirstName="user3",
LastName="name3",
Password="56#2"
},
User4 {
FirstName="user4",
LastName="name4",
Password="789@5"
}
}

سطرهاي فوق را پس از تعريف ApplicationUserCollection در Intellipad اضافه كنيد. بلافاصله Intellipad عبارات T-SQL معادل را براي ما توليد خواهد كرد.



ادامه دارد ...

۱۳۸۷/۱۲/۰۱

دريافت خلاصه‌ي وبلاگ تا اول اسفند 87


اگر علاقمند باشيد كه مطالب سايت جاري را (تا اول اسفند 87) به صورت آفلاين مطالعه كنيد،‌ لطفا فايل زير را دريافت نمائيد.
دريافت خلاصه‌ي وبلاگ


لينك‌هاي هفته‌ي اول اسفند


وبلاگ‌ها ، سايت‌ها و مقالات ايراني (داخل و خارج از ايران)

Visual Studio

ASP. Net

طراحي و توسعه وب

اس‌كيوال سرور

عمومي دات نت

ويندوز

متفرقه

۱۳۸۷/۱۱/۳۰

آيا برنامه نويس‌هاي دات نت بايد نگران دنياي 64 بيتي باشند؟


جواب ساده و كوتاه: خير!
كدمديريت شده‌ي شما در هر دو پلتفرم 32 بيتي - x86 و x64 بدون نياز به هيچگونه تغييري و بدون نگراني اجرا خواهد شد.
گزيده‌اي از MSDN :
اگر كد شما 100 درصد مديريت شده است (managed code ايي كه به صورت خالص از دات نت فريم ورك استفاده مي‌كند و هيچگونه وابستگي خارجي ديگري به كتابخانه‌هاي ديگر ندارد)، تنها با كپي شدن در يك محيط x64 داراي CLR ايي 64 بيتي (دات نت فريم ورك 64 بيتي)، بدون هيچگونه مشكلي اجرا خواهد شد.

سؤال: چرا و چگونه؟!
كامپايلرهاي دات نتي (تفاوتي نمي‌كند كه چه زباني مورد استفاده باشد)، كد شما را به IL‌ ترجمه مي‌كنند و IL اساسا دركي از پروسسور ندارد. JIT است كه در آخرين لحظه در اين مورد تصميم گيري مي‌كند.

اين نگراني از كجا حاصل شده است؟
نگارش R2 ويندوز 2008 سرور، فقط 64 بيتي خواهد بود و ويندوز سرور 2008 فعلي، آخرين سروري از مايكروسافت است كه هر دو نسخه‌ي 32 بيتي و 64 بيتي را دارد. بنابراين دير يا زود تمام برنامه نويس‌هاي ويندوزي "مجبور" خواهند شد دنياي 64 بيتي را تجربه كنند. (البته اگر تاكنون آن‌را تجربه نكرده‌اند)
و البته هنوز يك سري از محيط‌هاي توسعه، كامپايلر مخصوص 64 بيتي ندارند (مانند دلفي كه قرار است در طول سال جاري اولين تجربه‌ي 64 بيتي خود را ارائه دهد)

نكته:
در صفحه‌ي build ويژوال استوديو، شما مي‌توانيد نوع پلتفرم مورد نظر را نيز تعيين كنيد:



پيش فرض آن بر روي Any CPU‌ است و در اين حالت كد كامپايل شده‌ي شما بدون مشكل بر روي پلتفرم‌هايي كه مشاهده مي‌كنيد اجرا خواهد شد و تنها پيشنياز اجراي آن، نصب نسخه‌ي دات نت فريم ورك مخصوص آن پلتفرم است، بدون اينكه نياز باشد برنامه نويس نگران جزئيات خاصي در مورد خصوصيات ويژه‌ي آن پلتفرم‌ ويژه باشد.


سؤال: اگر كد ما خالص نبود چطور؟ (منظور اينكه 100 درصد دات نتي نبود)

حالت الف) اگر از كامپوننت‌هاي خارجي استفاده مي‌كنيد (حتي اگر 100 درصد دات نتي هم باشند) حتما اطمينان حاصل كنيد كه براي پلتفرم خاصي كامپايل نشده‌اند (همان Any CPU‌‌ مورد استفاده بوده)، زيرا كد شما كه براي تمام CPU ها كامپايل شده، در محيط 64 بيتي، تنها توانايي بارگذاري اسمبلي‌هاي 64 بيتي را خواهد داشت (64 بيتي رفتار مي‌كند) و با مواجه شدن با اسمبلي‌هايي كه براي يك پروسسور خاص ديگر كامپايل شده‌اند، با خطاي BadImageFormatException خاتمه مي‌يابد.

حالت ب) استفاده از API ويندوز يا DLL هاي غير دات نتي
بايد با هماهنگي با توليد كننده‌ي مربوطه حتما از نگارش 64 بيتي استفاده شود و همچنين برنامه‌ي شما بايد توانايي استفاده از اشاره‌گرهاي 64 بيتي را داشته باشد. اندازه‌ي نوع داده‌اي IntPtr در يك محيط 32 بيتي 4 است و در يك محيط 64 بيتي 8 خواهد بود (IntPtr.Size). اگر در حين اجراي ترجمه‌ي API يك كتابخانه به اشتباه بجاي استفاده از IntPtr از int‌ استفاده شده باشد، ممكن است كد شما در يك محيط 32 بيتي سال‌ها بدون مشكل اجرا شود، اما در اولين اجراي خود در يك محيط 64 بيتي، كرش خواهد كرد. (بدليل overflow حاصل)
IntPtr به اندازه‌ي كافي هوشمند است تا سايز خودش را مطابق پلتفرم تنظيم كند و مشكل ساز نشود.

مثال:

[DllImport("kernel32.dll")]
public static extern void GetSystemInfo([MarshalAs(UnmanagedType.Struct)] ref SYSTEM_INFO lpSystemInfo);

[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_INFO
{
internal _PROCESSOR_INFO_UNION uProcessorInfo;
public uint dwPageSize;
public IntPtr lpMinimumApplicationAddress;
public int lpMaximumApplicationAddress;
public IntPtr dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public ushort dwProcessorLevel;
public ushort dwProcessorRevision;
}

[StructLayout(LayoutKind.Explicit)]
public struct _PROCESSOR_INFO_UNION
{
[FieldOffset(0)]
internal uint dwOemId;
[FieldOffset(0)]
internal ushort wProcessorArchitecture;
[FieldOffset(2)]
internal ushort wReserved;
}

در اين مثال كه از API‌ ويندوز استفاده مي‌شود، به اشتباه نوع lpMaximumApplicationAddress‌ به صورت int تعريف شده است (بجاي IntPtr). اين كد بدون مشكل در يك برنامه‌ي 32 بيتي كار مي‌كند اما همين برنامه در يك محيط 64 بيتي يا كرش خواهد كرد يا مقدار lpMaximumApplicationAddress منفي گزارش مي‌شود.

۱۳۸۷/۱۱/۲۹

بررسي وجود نام كاربر با استفاده از jQuery Ajax در ASP.Net


شايد بعضي از سايت‌ها را ديده باشيد كه در حين ثبت نام، پس از وارد كردن يك نام كاربري و سپس مشغول شدن به پر كردن فيلد كلمه‌ي عبور، در قسمت نام كاربري شروع به جستجو در مورد آزاد بودن نام كاربري درخواستي مي‌كنند يا نمونه‌اي ديگر، فرم پرداخت الكترونيكي بانك سامان. پس از اينكه شماره قبض را وارد كرديد، بلافاصله بدون ريفرش صفحه به شما پيغام مي‌دهد كه اين شماره معتبر است يا خير. امروز قصد داريم اين قابليت را با استفاده از كتابخانه‌ي Ajax مجموعه jQuery در ASP.Net پياده سازي كنيم (بدون استفاده از ASP.Net Ajax مايكروسافت).
ابتدا سورس كامل را ملاحظه نمائيد:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AjaxTest.aspx.cs" Inherits="testWebForms87.AjaxTest" %>
<!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>jQuery Ajax Text</title>

<script src="jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#<%= TextBox1.ClientID %>").blur(function(event) {
$.ajax({
type: "POST",
url: "AjaxTest.aspx/IsUserAvailable",
data: "{'username': '" + $('#<%= TextBox1.ClientID %>').val() + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
$('#valid').html("<img src='ajaxImages/waiting.gif' alt='لطفا كمي تامل كنيد'>");
var delay = function() {
AjaxSucceeded(msg);
};

setTimeout(delay, 2000); //remove this
},
error: AjaxFailed
});
});
});
function AjaxSucceeded(result) {
if (result.d == true)
$('#msg').html("<img src='ajaxImages/available.gif' alt='نام كاربري درخواستي موجود است'>");
else
$('#msg').html("<img src='ajaxImages/taken.gif' alt='متاسفانه نام كاربري مورد نظر پيشتر دريافت شده‌است'>");
}
function AjaxFailed(result) {
alert(result.status + ' ' + result.statusText);
}
</script>

</head>
<body>
<form id="form1" runat="server">
<div>
user name:
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<span id="msg"></span>
<br />
pass:
<asp:TextBox ID="TextBox2" TextMode="Password" runat="server"></asp:TextBox>
</div>
<!-- preload -->
<div style="display: none">
<img src="ajaxImages/available.gif" alt="available" />
<img src="ajaxImages/taken.gif" alt="taken" />
<img src="ajaxImages/waiting.gif" alt="waiting" />
</div>
</form>
</body>
</html>


using System;
using System.Web.Services;

namespace testWebForms87
{
public partial class AjaxTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}

[WebMethod]
public static bool IsUserAvailable(string username)
{
// اين مورد را با خواندن اطلاعات از ديتابيس مي‌شود تعويض كرد
return username != "test";
}
}
}

توضيحات:
همانطور كه ملاحظه مي‌كنيد صفحه‌ي ASP.Net ما بسيار ساده است و از دو تكست باكس استاندارد تشكيل مي‌شود، به همراه تصاوير مربوط به Ajax كه يك سري تصاوير ساده چرخان معروف منتظر بمانيد ، يافت شد يا موجود نيست مي‌باشند. اين تصاوير در يك div مخفي (display: none) در صفحه قرار گرفته‌اند و در هنگام بارگذاري صفحه، اين‌ها نيز بارگذاري شده و حاضر و آماده خواهند بود. بنابراين هنگام استفاده از آن‌ها، كاربر تاخيري را مشاهده نخواهد كرد. همچنين يك span با id مساوي msg‌ را هم پس از تكست باكس اضافه كرده‌ايم تا تصاوير مربوط به رخدادهاي Ajax را با استفاده از توانايي‌هاي jQuery به آن اضافه كنيم.

اسكريپت Ajax ما با دراختيار گرفتن روال رخداد گردان blur شيء textBox1 شروع مي‌شود. همانطور كه در مقالات پيشين سايت نيز ذكر شد، روش صحيح دريافت ID يك كنترل ASP.Net در كدهاي سمت كلاينت جاوا اسكريپتي، بر اساس خاصيت ClientID آن است كه در اولين سطر كدهاي ما مشخص است (زيرا در ASP.Net نام و ID يك كنترل در هنگام رندر شدن به همراه ID كنترل‌هاي دربرگيرنده آن نيز خواهد بود، بنابراين بهتر است اين مورد را دايناميك كرد).

كار بررسي موجود بودن نام كاربري (يا مثلا يك شماره قبض و امثال آن) توسط WebMethod ايي به نام IsUserAvailable در code behind صفحه انجام مي‌شود كه پياده سازي آن‌را ملاحظه مي‌كنيد. بديهي است در اين مثال ساده، تنها نام كاربري از پيش رزرو شده، كلمه‌ي test است و در يك كد واقعي اين مورد با مقايسه‌ي نام كاربري با اطلاعات موجود در ديتابيس بايد صورت گيرد (و حملات تزريق اس كيوال را هم فراموش نكنيد. براي رهايي از آن‌ها "حتما" بايد از پارامترهاي ADO.Net استفاده كرد و گرنه كد شما مستعد به اين نوع حملات خواهد بود).

سؤال: چرا از web method استفاده شد و همچنين چرا اين متد static است؟
زمانيكه يك متد با كلمه كليدي static‌ مشخص مي‌شود حالت state less پيدا مي‌كند يعني مستقل از وهله‌ي كلاس عمل مي‌كند. در اين حالت نيازي به ارسال ViewState نبوده (بنابراين در كوئري مورد نظر ما بسيار بهينه و سبك عمل مي‌كنند) و همچنين نيازي به ايجاد يك وهله‌اي از كلاس صفحه‌ي ما نيز نخواهد بود. براي توضيحات بيشتر به اين مقاله مراجعه نمائيد. (به صورت خلاصه، دليل اصلي، كارآيي بالا و بهينه بودن اين روش در اين مساله ويژه است و در ASP.Net Ajax مايكروسافت به صورت گسترده‌اي در پشت صحنه مورد استفاده قرار مي‌گيرد)
استفاده از ويژگي WebMethod عملكرد صفحه‌ي ما را شبيه به يك وب سرويس خواهد كرد و امكان دسترسي به آن در متدهاي استاندارد POST به صورت ارسال ديتا به آدرس WebService.asmx/WebMethodName‌ خواهد بود. يك مثال ساده و عملي

بررسي تابع Ajax بكار رفته:
اين تابع هنگام فراخواني رخداد blur تكست‌باكس ما (مطابق كد فوق) فراخواني مي‌شود. ساختار ساده‌اي دارد كه به شرح زير است:
type: "POST"
نحوه‌ي ارسال داده را به متد وب سرويس ما مشخص مي‌كند.

url: "AjaxTest.aspx/IsUserAvailable"
اطلاعات پست شده، به صفحه‌ي AjaxTest.aspx و وب متد IsUserAvailable ارسال خواهد شد

data: "{'username': '" + $('#<%= TextBox1.ClientID %>').val() + "'}",
داده‌اي كه به آرگومان username ما ارسال مي‌شود، همان مقدار تايپ شده در TextBox1 است (كه باز هم دريافت ID آن به صورت دايناميك صورت گرفته تا مشكل زا نشود)

contentType: "application/json; charset=utf-8",
dataType: "json",
در اين دو سطر از نوع داده‌ي json استفاده شده است كه فرمت بسيار سبك و بهينه‌اي براي تبادل اطلاعات در وب به‌شمار مي‌آيد و توسط كتابخانه‌هاي جاوا اسكريپتي به سادگي پردازش شده و تبديل به اشياء مورد نظر خواهند شد. براي مثال اگر خروجي يك وب سرويس در حالت xml به صورت زير باشد:

<xx yy="nn"></xx>
معادل json آن به شرح زير است:
{ "xx": {"yy":"nn"} }
success: function(msg)
Success ، پس از موفقيت آميز بودن عمليات ajax در jQuery فراخواني مي‌شود
error: AjaxFailed
و اگر در اين بين خطايي رخ داده باشد، قسمت error فراخواني مي‌شود.

در اين مثال براي نمايش بهتر عمليات، يك وقفه‌ي 2 ثانيه‌اي توسط setTimeout ايجاد شده و بديهي است در يك مثال واقعي بايد آن‌را حذف نمود.

نكته: با استفاده از افزونه‌ي فايرباگ فايرفاكس، مي‌توان جزئيات اين عمليات را بهتر مشاهده نمود:





۱۳۸۷/۱۱/۲۸

كمي شوخي با 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>

و اما روش‌هاي محترمانه!

۱۳۸۷/۱۱/۲۷

توصيه‌هايي در مورد overloading متدها


مطلب زير چكيده‌اي است از كتاب Framework Design Guidelines در مورد سربارگذاري توابع

الف) از يك نوع خروجي استفاده كنيد

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

public User[] GetGroupMembers(int groupId)
public List<User> GetGroupMembers(string groupName)

هر دوي اين متدها گروهي از كاربران را بازگشت مي‌دهند. خروجي متد اول از نوع آرايه است و خروجي متد دوم از نوع يك ليست جنريك مي‌باشد.
مشكل اينجا است كه هنگام فراخواني هر كدام، نحوه‌ي استفاده متفاوت خواهد بود. بنابراين بايد از اين نوع سربارگذاري پرهيز كرد.

ب) نام‌هاي آرگومان‌هاي توابع سربارگذاري شده شما بايد يكسان باشند

در مثال زير، از اولين آرگومان جهت دريافت شناسه‌ي يك گروه استفاده مي‌شود:

public List<User> GetGroupMembers(int groupId)
public List<User> GetGroupMembers(int id, int pageIndex, int pageSize)

اما همانطور كه ملاحظه مي‌كنيد در يكي از groupId استفاده شده و در ديگري از نام id . اين روش مزموم است! از آن پرهيز كنيد! (هر دو يا بايد groupId باشند و يا id . اين هماهنگي و يكسان بودن بايد در توابع سربارگذاري شده‌ي شما حفظ شود)

ج) ترتيب آرگومان‌ها را در توابع سربارگذاري شده حفظ و رعايت نمائيد

لطفا به مثال زير دقت كنيد:

public List<User> GetGroupMembers(int groupId)
public List<User> GetGroupMembers(int pageIndex, int pageSize, int groupId)

در اينجا شناسه‌ي گروه يكبار به عنوان آرگومان اول معرفي شده و بار ديگر به عنوان آرگومان سوم. اين كار نيز مزموم است، زيرا برنامه نويس‌ها از روي عادت به اولين آرگومان توابع سربارگذاري شده‌ي شما، همان شناسه‌ي گروه را ارسال خواهند كرد و اين مورد سبب بروز باگ‌هايي خواهد شد كه رديابي آن مشكل است. بنابراين اگر شناسه‌ي گروه به عنوان اولين آرگومان معرفي شده، در تمامي overload هاي اين تابع نيز اولين آرگومان بايد همان شناسه‌ي گروه باشد.

د) از call forwarding استفاده كنيد

جهت توضيح بهتر call forwarding به مثال زير دقت نمائيد:
public List<User> GetGroupMembers(int groupId)
{
return GetGroupMembers(groupId, 0, 10);
}

public List<User> GetGroupMembers(int groupId, int pageIndex, int pageSize)
{
return GetGroupMembers(groupId, pageIndex, pageSize, SortOrder.Ascending);
}

public List<User> GetGroupMembers(int groupId, int pageIndex, int pageSize, SortOrder sortOrder)
{
var query = new GroupQuery();
query.GroupID = groupId;
query.PageIndex = pageIndex;
query.PageSize = pageSize;
query.SortOrder = sortOrder;

return GetGroupMembers(query);
}

public List<User> GetGroupMembers(GroupQuery groupQuery)
{
// Actual implementation to get group members goes here
}

معناي call forwarding اين است كه هنگام پياده سازي توابعي از اين دست، كوچكترين تابع سربارگذاري شونده بايد تابع بزرگتر بعدي خود را صدا بزند و همين‌طور الي آخر كه در مثال فوق به خوبي آشكار است. در اين مثال چهارمين تابع سربارگذاري شده، بيشترين حوضه‌ي تمركز را در خود دارد و توابع ديگر مي‌توانند از آن بهره جويند بدون اينكه پياده سازي خاصي را ارائه دهند.

ه) زياده‌ روي نكنيد!

آخرين موردي كه توصيه شده اين است كه در تهيه توابع سربارگذاري شده زياده روي نكنيد. در اين نوع موارد بايد قانون 80/20 را در نظر گرفت. 2 تا 3 تابع سربارگذاري شده ارائه دهيد كه 80 درصد كار را انجام مي‌دهند و سپس يك تابع سربارگذاري شده‌ي ديگر ارائه دهيد كه 20 درصد باقيمانده را پوشش دهد.


پ.ن.
در سي شارپ 4 ، با معرفي optional parameters ، شايد كمتر به سربارگذاري نياز باشد.

۱۳۸۷/۱۱/۲۶

مونيتور كردن ميزان فضاي خالي باقيمانده در سرور توسط اس كيوال سرور


با توجه به در حال اجرا بودن 24 ساعته‌ي سرويس SQL server agent، استفاده‌هاي ارزنده‌اي از آن مي‌توان كرد. براي مثال هر از گاهي بررسي كند كه آيا هارد سرور پر شده يا نه؟ و اگر بله (كمبود ميزان فضاي خالي به حد خطرناكي رسيده)، يك ايميل خودكار به مسؤول مربوطه ارسال كند.
عمده‌ي مطالبي كه در اين مقاله بررسي خواهند شد همانند مطلب مونيتور كردن ميزان مصرف CPU توسط اس كيوال سرور است و از تكرار آن‌ها در اين‌جا صرفنظر خواهد شد (راه اندازي ديتابيس ميل و همچنين تعريف يك job جديد كه در مورد آن‌ها صحبت شد، همانند قبل است). تنها مطلب جديدي كه به آن اشاره خواهد شد، اسكريپت بررسي ميزان فضاي خالي و سپس ارسال ايميل است كه در يك job جديد همانند مقاله‌ي قبل بايد به سرور اضافه شود. اين اسكريپت به شرح زير است:

DECLARE @DriveBenchmark INT
DECLARE @MachineName NVARCHAR(1000)
DECLARE @DiskFreeSpace INT
DECLARE @DriveLetter CHAR(1)
DECLARE @AlertMessage NVARCHAR(MAX)
DECLARE @MailSubject NVARCHAR(MAX)
DECLARE @NewLine CHAR(2)

SET @NewLine = CHAR(13) + CHAR(10)

SET @DriveBenchmark = 2048 -- 2GB
SET @MailSubject = 'Free space is low on ' + @@SERVERNAME
SET @AlertMessage = ''

IF EXISTS (
SELECT *
FROM tempdb..sysobjects
WHERE id = OBJECT_ID(N'[tempdb]..[#disk_free_space]')
)
DROP TABLE #disk_free_space

CREATE TABLE #disk_free_space
(
DriveLetter CHAR(1) NOT NULL,
FreeMB INTEGER NOT NULL
)

/* Populate #disk_free_space with data */
INSERT INTO #disk_free_space
EXEC MASTER..xp_fixeddrives


DECLARE DriveSpace CURSOR FAST_FORWARD
FOR
SELECT DriveLetter,
FreeMB
FROM #disk_free_space

OPEN DriveSpace
FETCH NEXT FROM DriveSpace INTO @DriveLetter, @DiskFreeSpace

WHILE (@@FETCH_STATUS = 0)
BEGIN
IF @DiskFreeSpace < @DriveBenchmark
BEGIN
SET @AlertMessage = @AlertMessage + 'Drive ' + @DriveLetter + ' on ' + @@SERVERNAME
+ ' has only ' + CAST(@DiskFreeSpace AS VARCHAR) + ' MB left.' + @NewLine
END

FETCH NEXT FROM DriveSpace INTO @DriveLetter, @DiskFreeSpace
END
CLOSE DriveSpace
DEALLOCATE DriveSpace

DROP TABLE #disk_free_space

IF @AlertMessage <> ''
BEGIN
EXECUTE msdb.dbo.sp_send_dbmail
@recipients = 'nasiri@site.net', -- Change This
@copy_recipients = 'Administrator@site.net', -- Change This
@Subject = @MailSubject,
@Body = @AlertMessage
,@importance = 'High'
END

بررسي اسكريپت فوق:

همه چيز از رويه‌ي سيستمي xp_fixeddrives شروع مي‌شود. حاصل اجراي اين رويه، دريافت ميزان فضاي خالي هر درايو موجود در سرور خواهد بود. همانطور كه در اسكريپت نيز مشخص است، براي ذخيره سازي خروجي اين رويه، يك جدول موقتي (disk_free_space) ايجاد شده و خروجي آن به درون اين جدول اضافه خواهد شد. سپس يك cursor ايجاد شده و تك تك ركوردهاي حاصل با مقدار متغير DriveBenchmark كه در اينجا 2 گيگابايت در نظر گرفته شده است، مقايسه مي‌گردند. سپس هر كدام از ركوردها كه كمتر از 2 گيگابايت بود، متغير AlertMessage ما را مقدار دهي خواهد كرد. در پايان اگر اين متغير مقدار دهي شده بود، يعني مشكل حاصل شده و نتيجه‌ي بررسي به صورت يك ايميل ارسال مي‌گردد. بديهي است كه در صورت نياز مقدار متغير DriveBenchmark و آرگومان‌هاي recipients و copy_recipients كد فوق بايد اصلاح شوند.

براي استفاده از آن يك job جديد تعريف كنيد كه مثلا هر سه ساعت يكبار اجرا شده و اين اسكريپت را فراخواني نمايد.


۱۳۸۷/۱۱/۲۵

يكي از مزاياي استفاده از SVN در يك پروژه تك نفره


حتما لازم نيست كه در يك تيم برنامه نويسي مشغول به كار باشيد تا به يك سورس كنترل نياز پيدا كنيد. در ادامه يكي از مزاياي استفاده از SVN را با هم مرور خواهيم كرد.

چند روز قبل هنگام كار با VS.Net ، ناگهان IDE‌ كرش كرد. (از لطايف استفاده از يك دو جين افزونه و ضعف در برنامه نويسي يكي از اين‌ها كه مي‌تواند سبب ناپايدار شدن IDE شود)
پس از كرش با صفحه‌ي زير مواجه شدم!


بله! فرم برنامه كه با هزار زحمت درست شده بود، پس از كرش نابود شده بود!
در اين نوع مواقع چه بايد كرد؟ مراجعه به آخرين مجموعه‌ي بك آپ زيپ شده كه احتمالا وجود خارجي ندارد؟ ناسزا گفتن به زمين و زمان، يا ... ؟!

چون هميشه از SVN به عنوان سورس كنترل استفاده مي‌كنم، به سادگي چند كليك مشكل برطرف شد.
براي اين‌كار مي‌توان به صورت زير عمل كرد:
الف) كليك راست بر روي فايل frmMain.Designer.cs (اين فايل تعاريف رابط كاربر فرم تخريب شده را در خود دارد)
ب) سپس انتخاب گزينه‌ي Showlog از منوي افزونه‌ي Visual SVN (شكل زير)



اكنون صفحه‌ي گزارش تاريخچه‌ي ريز عمليات صورت گرفته بر روي اين فايل ظاهر مي‌شود:



در ادامه مي‌توان بر روي يكي از سطرهاي ظاهر شده در گزارش كليك راست كرد و گزينه‌ي compare with working copy را انتخاب نمود (شكل زير):



سپس ابزار diff ظاهر شده و مي‌توان به سادگي تفاوت فايل تخريب شده فعلي و فايل سالم چند نگارش قبل را مشاهده نمود:



همانطور كه در تصوير مشخص است، فايل مورد استفاده (working copy) در دو نقطه اساسي كه مربوط به اضافه كردن منوها است تخريب شده. سمت چپ نگارش قديمي است و سمت راست نگارش فعلي تخريب شده.
اكنون براي اصلاح كد تخريب شده فقط كافي است روي قسمت رنگي سمت راست كليك راست كرده و گزينه copy to right‌ را انتخاب كنيم. به اين صورت در اسرع وقت و به سادگي هر چه تمام‌تر يك فايل تخريب شده به روز اول يا حداقل به يك نگارش قبل بازگشت پيدا كرده و مشكل حل مي‌شود. (البته در اين مورد تخريب فرم، پس از انجام اصلاح فوق، يكبار بايد IDE را كاملا بست و مجددا آنرا گشود تا نتيجه ظاهر شود)



اگر به اين مبحث علاقمند شديد، به كتابچه‌ي فارسي راهنماي كار با SVN مراجعه نمائيد. (در مورد نحوه‌ي راه اندازي SVN ، افزونه‌هاي IDE هاي مختلف و موارد ديگري كه در اين مطلب كوتاه در مورد آن‌ها بحث نشد، به تفصيل توضيح داده شده است)


۱۳۸۷/۱۱/۲۴

لينك‌هاي هفته‌ي آخر بهمن


وبلاگ‌ها ، سايت‌ها و مقالات ايراني (داخل و خارج از ايران)

امنيت

Visual Studio

ASP. Net

طراحي و توسعه وب

اس‌كيوال سرور

سي شارپ

عمومي دات نت

مسايل اجتماعي و انساني برنامه نويسي

كتاب‌هاي رايگان جديد

متفرقه

۱۳۸۷/۱۱/۲۳

فايل‌هاي chm و مشكل فارسي - قسمت دوم


بر اساس جستجوهايي كه انجام داده‌ام، CHM پشتيباني كاملي را از يونيكد انجام نمي‌دهد (مشكل جستجو و همچنين ايندكس كردن).
اما با ترفندي مي‌توان اين مساله را حل كرد و آن هم تبديل encoding فايل‌ها به عربي است (windows-1256). در اين حالت هم جستجو كار مي‌كند و هم عنوان صفحات هنگام جستجو در ليست موارد ياد شده درست نمايش داده مي‌شود و صفحه add to favorites نيز مشكلي در نمايش عنوان‌هاي صفحه‌ها نخواهد داشت. روش كار به شرح زير است:

الف) encoding تمام فايل‌هاي html خود را به صورت زير تغيير دهيد (از utf-8 به windows-1256):

<meta content="text/html; charset=Windows-1256" http-equiv="Content-Type">

ب) محتواي تمام فايل‌هاي html خود را يكبار با فرمت ويندوز 1256 ذخيره كنيد. براي اين منظور در دات نت به سادگي زير مي‌توان عمل كرد:
using System.IO;
using System.Text;

public static void SaveAs1256(string fileName)
{
string content = File.ReadAllText(fileName);
File.WriteAllText(fileName, content, Encoding.GetEncoding("windows-1256"));
}

شايد بعضي از ويرايشگرهاي متني هم اين مورد را پشتيباني كنند.(مانند ويرايشگر ويژوال استوديو)

ج) اصلاح فايل hhp پروژه خود
فايل hhp مربوط به html help work shop را باز كنيد. (همان فايل پروژه ساخت راهنما)
اگر مثال قبل را دنبال كرده باشيد، محتواي فايل آن چيزي شبيه به خطوط زير خواهد بود:

[OPTIONS]
Compatibility=1.1 or later
Compiled file=test.chm
Contents file=Table of Contents.hhc
Default Window=win1
Default topic=page1.html
Display compile progress=No
Full-text search=Yes
Index file=Index.hhk
Language=0x429 Farsi
Title=راهنماي يك

[WINDOWS]
win1=,"Table of Contents.hhc","Index.hhk","page1.html","page1.html",,,,,0x3420,,0x304e,,,,,,2,,0


[FILES]
page1.html
page2.html

[INFOTYPES]

نياز است تا آن‌را به صورت زير ويرايش كرد تا فرمت 1256 به آن اعمال شود:
به قسمت options چند سطر زير را اضافه كنيد: (زبان فارسي و فونت تاهوماي عربي)

Default Font=Tahoma,8,178
Language=0x429 Farsi

اكنون پس از كامپايل مجدد مجموعه، مشكلي در مورد جستجو يا به هم ريختگي عنوان‌ها ديگر وجود نخواهد داشت.

محض نمونه، كل وبلاگ جاري را به يك فايل chm تبديل كرده‌ام كه ‌آن‌را از آدرس زير مي‌توانيد دريافت نمائيد:
دريافت فايل

براي آزمايش، يك عبارت فارسي را در آن جستجو نمائيد.


پ.ن.
اين راه حلي است كه به نظر من رسيده و جواب داده. اگر شما با encoding هاي ديگر هم جواب گرفته‌ايد (مشكل جستجوي فارسي حل شده) لطفا پيغام بگذاريد. با تشكر.

۱۳۸۷/۱۱/۲۲

فايل‌هاي chm و مشكل فارسي - قسمت اول


همانطور كه مطلع هستيد از ويندوز ويستا به بعد، فرمت قديمي فايل‌هاي راهنماي ويندوز (فايل‌هاي hlp) منسوخ شده تلقي مي‌شود و فرمت پيشنهادي، chm است. نرم افزارهاي زيادي براي تهيه فايل‌هاي compiled html help يا همان chm هاي معروف وجود دارند كه معروفترين آن‌ها برنامه‌ي Help & Manual است.
اما تمام اين برنامه‌ها در حقيقت پوسته‌اي هستند براي برنامه‌ي رايگان html help work shop مايكروسافت و در نهايت از كامپايلر آن استفاده مي‌كنند. بنابراين چرا از برنامه‌ي رايگان اصلي استفاده نشود؟

اگر تا به حال با html help work shop كار نكرده‌ايد، در ادامه مروري سريع بر آن خواهيم داشت:

الف) درست كردن فايل‌هاي صفحات راهنما
برنامه‌ي Help & Manual ايي كه معرفي شد و تمام نمونه‌هاي مشابه آن، تنها كار مهمي را كه انجام مي‌دهند اين است كه شما را از يك html editor بي‌نياز مي‌كنند. بنابراين زمانيكه مي‌خواهيم از برنامه‌ي اصلي html help work shop استفاده كنيم نياز به يك html editor خارجي براي تهيه فايل‌هاي راهنما خواهيم داشت. مثلا مرحوم front page يا نگارش جديد آن به نام Microsoft expression web يا Dreamweaver يا Aptana يا حتي notepad !
در اينجا تنها مشخص كردن نوع encoding نمايش صفحه براي صحيح نمايش داده شدن متون فارسي كافي است. اما اين تمام ماجرا نيست.

ب) كامپايل كردن فايل‌هاي راهنماي ايجاد شده
براي اين منظور بجاي آپلود بيش از 30 تصوير جهت توضيحات قدم به قدم نحوه‌ي انجام اين‌كار، يك فايل ويديويي درست كرده‌ام كه آن‌‌را از آدرس زير مي‌توانيد دريافت كنيد.
دريافت فايل

همانطور كه در اين فايل آموزشي مقدماتي هم تاكيد شده، به صورت پيش فرض جستجوي فارسي كار نمي‌كند. همچنين اگر يك متن انگليسي را جستجو كنيد، صفحات ياد شده با عنواني به هم ريخته نمايش داده مي‌شوند. در صفحه افزودن به علاقمندي‌ها نيز يك چنين مشكلي با عنوان‌ها وجود دارد.

در قسمت دوم، نحوه‌ي رفع اين دو مشكل (مشكل جستجوي عبارات فارسي و مشكل عنوان‌هاي به هم ريخته) را بررسي خواهيم كرد.

ادامه دارد ...

۱۳۸۷/۱۱/۲۱

سريع‌تر كردن عمليات دريافت‌ اطلاعات از وب، توسط يك برنامه ASP.Net


فرض كنيد يك برنامه ASP.Net نوشته‌ايد كه كار آن نمايش يك سري فيد از سايت‌هاي مختلف است يا دريافت وضعيت آب و هوا از يك وب سرويس و نمايش آن در سايت مي‌باشد و امثال آن (استفاده از WebRequest ، WebClient ، XmlDom/Reader و ...).
اگر همين عمليات را يكبار با ASP.Net 1.1 و بار ديگر با ASP.Net 2.0 به بالا انجام دهيد، متوجه تفاوت سرعت دريافت قابل تاملي خواهيد شد (ASP.Net 2.0 به بعد حدودا تا 10 ثانيه كندتر عمل مي‌كند). علت چيست؟
در دات نت 1.1 ، تنظيمات پروكسي پيش فرض در كتابخانه‌هاي مربوطه وجود نداشت و به نال تنظيم شده بود. در دات نت 2 به بعد اين مورد به پروكسي پيش فرض سيستم، تنظيم شده است. پروكسي پيش فرض سيستم همان تنظيماتي است كه در internet explorer صورت مي‌گيرد.
كاربر پيش فرض ASP.Net (مثلا NETWORK SERVICE) دسترسي خواندن اين اطلاعات را از رجيستري ويندوز ندارد. علت اين وقفه هم همين مورد است! (حتي اگر برنامه ويندوزي شما هم دسترسي خواندن اطلاعات كليدهاي HKLM رجيستري ويندوز را نداشته باشد، باز هم اين مساله رخ خواهد داد)
دات نت فريم ورك سعي مي‌كند تا اين تنظيمات را از رجيستري يا مكان‌هاي ميسر ديگر بخواند و در آخر پس از شكست كليه حالات مختلف، كلاينت را به صورت مستقيم متصل خواهد كرد.
خوشبختانه اين عملكرد پيش فرض قابل تغيير است. تنها كافي است چند سطر زير را به فايل config برنامه خود اضافه كنيد:

<system.net>
<defaultProxy>
<proxy bypassonlocal="true" usesystemdefault="false" />
</defaultProxy>
</system.net>

با اين‌كار تشخيص خودكار پروكسي سيستم غيرفعال شده و وقفه‌ي معرفي شده ديگر وجود نخواهد داشت.
راه ديگر انجام آن، نسبت دادن نال به خاصيت Proxy شيء HttpWebRequest است كه همين اثر را خواهد داشت.

۱۳۸۷/۱۱/۲۰

رفع تداخل jQuery با كتابخانه‌هاي مشابه


قبل از شروع، يك خبر!
VsDoc for jQuery 1.3.1 (جهت فعال سازي intellisense آخرين نگارش جي كوئري در VS.Net)


اگر سعي كنيد jQuery را به همراه ساير كتابخانه‌هاي جاوا اسكريپتي ديگر به صورت همزمان استفاده كنيد (مثلا mootools يا ASP.Net Ajax و امثال آن)، احتمالا قسمتي و يا تمامي كدهاي جاوا اسكريپتي شما كار نخواهند كرد. براي مثال update panel شما در ASP.Net Ajax از كار مي‌افتد، يا كدهاي mootools شما ديگر كار نمي‌كنند. علت اينجا است كه تمامي اين كتابخانه‌ها از نشانه $ به عنوان متغيري عمومي كه بيانگر نام مستعار كتابخانه مربوطه است استفاده مي‌كنند و در نهايت تمام اين‌ها با هم تداخل خواهند كرد.

خوشبختانه jQuery امكان رفع اين تداخل را پيش بيني كرده است كه به صورت زير مي‌باشد:

<script type="text/javascript" language="javascript" src="jquery.min.js"></script>
<script type="text/javascript">
jQuery.noConflict();
jQuery(document).ready(function($) {
//tip-1
$("select > option").each(function() {
var obj = $(this);
obj.attr("title", obj.attr("value"));
});
//tip-1
});
</script>

كد مثال فوق، به تمامي آيتم‌هاي drop down list‌ هاي شما در يك صفحه، بر اساس value هر آيتم موجود در آن‌ها، يك tooltip اضافه مي‌كند. (با IE7 به بعد و فايرفاكس سازگار است)
در اينجا ابتدا jQuery.noConflict فراخواني شده و سپس document ready متداول هم بايد اندكي مطابق كد فوق تغيير كند. مابقي كدهاي شما از اين پس نيازي به تغيير نخواهند داشت. (روش‌هاي ديگري هم براي تغيير نام $ وجود دارند كه در مستندات مربوطه قابل مشاهده است)

۱۳۸۷/۱۱/۱۹

ويديوهاي رايگان طراحي رابط كاربر (UI) براي برنامه نويس‌ها از مايكروسافت

1- اصول طراحي: آموزش توازن با استفاده از Expression Design (دريافت ويديو، فايل‌هاي پروژه)

2- اصول طراحي: آموزش ريتم با استفاده از Expression Design(دريافت ويديو، فايل‌هاي پروژه)

3- اصول طراحي: آموزش تاكيد و برجسته سازي با استفاده از Expression Design(دريافت ويديو، فايل‌هاي پروژه)

4- اصول طراحي: آموزش تقارن با استفاده از Expression Design(دريافت ويديو، فايل‌هاي پروژه)

5- اصول طراحي: آموزش يكپارچگي با استفاده از Expression Design (دريافت ويديو، فايل‌هاي پروژه)

6- اصول طراحي: آموزش نقاط، خطوط و فرم با استفاده از Expression Design(دريافت ويديو، فايل‌هاي پروژه)

7- نحوه انتخاب رنگ در طراحي رابط كاربر (دريافت ويديو، فايل‌هاي پروژه)

8- نحوه بكارگيري رنگ‌ها با استفاده از Expression Design(دريافت ويديو، فايل‌هاي پروژه)

9- نحوه طراحي الگوهاي شطرنجي با استفاده از Expression Design (دريافت ويديو، فايل‌هاي پروژه)

10- نحوه طراحي آيكون‌ها با استفاده از Expression Design(دريافت ويديو، فايل‌هاي پروژه)

11- ايجاد يك آيكون نمونه با استفاده از Expression Design (دريافت ويديو، فايل‌هاي پروژه)

12- طراحي دكمه‌هاي شفاف با استفاده از Expression Design(دريافت ويديو، فايل‌هاي پروژه)

13- اعمال افكت به تصاوير با استفاده ازExpression Design (دريافت ويديو، فايل‌هاي پروژه)

۱۳۸۷/۱۱/۱۸

تاريخچه‌ي نگارش‌هاي مختلف دات نت فريم ورك


حدود 8 سال از ارائه اولين نگارش دات نت فريم ورك مي‌گذرد و در ادامه مرور سريعي خواهيم داشت بر عناوين كتابخانه‌هاي اضافه شده به اين مجموعه:



دات نت فريم ورك 1.0
اولين ارائه عمومي آزمايشي آن در PDC 2000 صورت گرفت و در اوايل 2002 به عموم عرضه شد (2/13/2002).
عبارت كد مديريت شده را به دنيا معرفي كرد (managed code) و شامل اجزاي زير بود:
• GC, JIT
• C#
• Coherent Framework
• XSP….ASP+…ASP.NET!
• WinForms

دات نت فريم ورك 1.1
در اوايل 2003 به همراه ويندوز سرور 2003 و VS 2003 ارائه شد.
• Mobile ASP.NET controls
• Built-in support for ODBC and Oracle databases.
• IPv6 support.

دات نت فريم ورك 2
در اواخر 2005 ارائه شد (11/07/2005) و شامل تازه‌هاي زير بود:
• ASP.NET for the Masses
○ Application Building Blocks
§ Parts, Authentication, Role Management, etc
○ Visual Web Developer
• Client Development
• ClickOnce!

دات نت فريم ورك 3
در اواخر 2006 ارائه شد (11/06/2006) و موارد زير را به اين فريم ورك افزود:

• Windows CardSpace - Digital identity interface.
• Windows Presentation Foundation : WPF
○ Vector Graphics, Media and UI
○ Enters the age of UX
• Windows Communication Foundation : WCF
○ Unified messaging model
• Windows Workflow Foundation : WF
○ Coordinating work with durable applications

دات نت فريم ورك 3.5
در پايان 2007 ارائه شد (11/19/2007) و تازه‌هاي زير را به همراه داشت:
• Linq
• Expression Trees and Lamda Methods
• Extension Methods
• Paging Support for ADO.NET
• Managed Wrappers for WMI and AD
• Enhancements to WCF and WF
• System.CodeDom namespace
• ASP.NET AJAX
• WCF/WF
○ REST Services
○ Workflow Services
• Client
○ Sync
○ Client app services

در همين زمان نيز دات نت فريم ورك سورس باز شد.

سرويس پك يك دات نت فريم ورك 3.5
در اواسط 2008 ارائه شد (8/11/2008) و به همراه تغييرات زير بود:
• ASP.NET Dynamic Data
• ADO.NET
○ Entity Framework
○ Data Services (Astoria)
• WCF
○ AtomPub ServiceDocuments
• Client
○ Client Profile
○ Performance
§ Working set and startup time
• Silverlight 2
○ RTM end of 2008
○ Brings power of .NET to the web client
○ Media and RIA .NET platform


دات نت فريم ورك 4.0
نگارش بتاي آن در دسترس است و احتمالا نگارش نهايي آن در سال آينده‌ي ميلادي به همراه VS2010 ارائه مي‌شود. اين مجموعه تازه‌هاي زير را به همراه خواهد داشت:

• Base Class Library Improvements
○ Managed Extensibility Framework
○ More Core Data Structures
○ I/O Improvements
• Parallel Computing
○ Task Parallel Library
○ Parallel Linq (PLINQ)
○ Coordination Data Structures (CDS)
• Client
○ WPF
§ Client Profile
§ Business Focused Controls
§ Win7 Advances (Multi-touch, etc)
○ ADO.NET
§ Entity Framework v2
□ Code-First Development
□ TDD Support
□ Foreign-Key Support
○ ASP.NET
§ ASP.NET Dynamic Data Improvements
§ ASP.NET MVC
§ ASP.NET Dynamic Data for MVC
§ Extensible Caching Framework
○ WF & WCF
§ Fully Declarative Services
§ Workflow Enhancements
□ New flowchart modeling
□ Workflow Rules Integration
□ … much more…
§ WCF Enhancements
□ Durable Duplex
□ WS-Discovery & UDP Channel
□ In-Process Channel
§ RIA (Silverlight)
□ Simplified N-tier development
□ Business-focused framework

۱۳۸۷/۱۱/۱۷

لينك‌هاي هفته‌ي سوم بهمن


وبلاگ‌ها ، سايت‌ها و مقالات ايراني (داخل و خارج از ايران)

Visual Studio

ASP. Net


طراحي و توسعه وب

PHP

اس‌كيوال سرور

سي شارپ

عمومي دات نت

ويندوز

مسايل اجتماعي و انساني برنامه نويسي

متفرقه

۱۳۸۷/۱۱/۱۶

افزونه جملات قصار jQuery


چندي قبل مطلبي را در مورد پردازش فايل‌هاي xml با استفاده از قابليت Ajax جي كوئري نوشتم. در سايت پي‌سافت، تعدادي فايل XML از شعرا و جملات قصار و امثال آن موجود است (با تقدير و تشكر از زحمات اين عزيزان) كه امروز قصد داريم از فايل XML جملات قصار آن يك افزونه jQuery درست كنيم تا آن‌ها را به صورت اتفاقي (random) در صفحه نمايش دهد:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>XML</title>
<script src='jquery-1.3.min.js' type='text/javascript'></script>
<script type="text/javascript">
var ourXml = '';
function parseXml(xml){
ourXml = xml; //for our timer
var i;
var rnd = Math.floor(Math.random() * 130) + 1; //we have 130 entries
for (i = 1; i < 5; i++) //M1 to M4
{
$(xml).find("Ghesaar" + rnd + " > M" + i).each(function(){
$("#output").append($(this).text() +' ');
});
}
}

//ajax loader
$(document).ready(function(){
$.ajax({
type: "GET",
url: "Ghesaar.xml",
dataType: "xml",
success: parseXml
});
});

//timer
window.setInterval(function(){
$("#output").empty().hide();
parseXml(ourXml);
$("#output").fadeIn("slow");
}, 10000);
</script>
</head>
<body>
<span id="output" dir="rtl" style=" "/>
</body>

</html>

توضيحات:
همه چيز از قسمت Ajax كد فوق شروع مي‌شود. فايل Ghesaar.xml بارگذاري شده و به تابع parseXml ارسال مي‌شود. در اين تابع يك كپي از xml دريافت شده را نگهداري مي‌كنيم تا در تايمري كه بعدا جهت نمايش اتفاقي پيام‌ها درست خواهيم كرد، مجبور نشويم مجددا محتويات فايل xml را بارگذاري كنيم.
در تابع parseXml قصد داريم فايل xml ايي با فرمت زير را پردازش كنيم:

  <Ghesaar10>
<M1>نااميدى، آخرين نتيجه گيرى </M1>
<M2>بى خردان است</M2>
<M3>
</M3>
<M4>« ضرب المثل انگليسى »</M4>
</Ghesaar10>

براي مثال در اينجا بايد به دنبال Ghesaar10>M1 براي يافتن متن تگ M1 گشت و الي آخر. كلا چهار تگ داريم كه در يك حلقه آن‌ها را استخراج خواهيم كرد. سپس يك عدد اتفاقي بين 1 تا 130 هم توليد كرده و بجاي عدد پس از Ghesaar قرار مي‌دهيم. يعني هر بار به صورت اتفاقي يك مجموعه از جملات قصار، دريافت و پردازش خواهند شد. نهايتا اين جملات استخراج شده را به يك span با id مساوي output‌ اضافه مي‌كنيم.
تا اينجا فقط يكي از جملات قصار در هنگام بارگذاري صفحه نمايش داده خواهند شد. براي تكرار نمايش، از يك تايمر مي‌توان كمك گرفت كه كد آن‌را در بالا ملاحظه مي‌كنيد.
همين!

براي تبديل آن به يك پلاگين/افزونه جي‌كوئري ، مي‌توان به صورت زير عمل كرد:

$.fn.ghesaar = function(options){
var defaults = {
interval: 1
};
var options = $.extend(defaults, options);

return this.each(function(){
var obj = $(this);
var ourXml = '';
function parseXml(xml){
ourXml = xml; //for our timer
var i;
var rnd = Math.floor(Math.random() * 130) + 1; //we have 130 entries
for (i = 1; i < 5; i++) //M1 to M4
{
$(xml).find("Ghesaar" + rnd + " > M" + i).each(function(){
obj.append($(this).text() + ' ');
});
}
}

//ajax loader
$.ajax({
type: "GET",
url: "Ghesaar.xml",
dataType: "xml",
success: parseXml
});

//timer
window.setInterval(function(){
obj.empty().hide();
parseXml(ourXml);
obj.fadeIn("slow");
}, options.interval * 1000);

});


};

فرمت اين فايل ساده و استاندارد است. نام فايل jquery.ghesaar.js خواهد بود.
سپس قسمت استاندارد توسعه options اضافه مي‌شود تا بتوان به تابع افزونه خود مقدار interval را پاس كرد تا از اين حالت خشك و جمود خارج شود.
كل وقايع افزونه درون تابع زير رخ مي‌دهد:

return this.each(function(){
...

});

اينجا همان كدهايي را كه پيشتر توسعه داديم بدون هيچ تغييري قرار مي‌دهيم.
سپس در ابتداي كار شيء this كه اشاره‌گري است به شيء انتخاب شده توسط جي‌كوئري را دريافت كرده و هرجايي را كه قبلا $("#output") داشتيم، تبديل به obj مي‌كنيم. (يعني اين مورد هم به انتخاب كاربر خواهد شد)
جهت دريافت مقدار تنظيمي interval هم مي‌توان از options.interval استفاده كرد.
به اين صورت كد ما تبديل به يك افزونه جي‌كوئري مي‌شود.

اينبار نحوه‌ي استفاده از افزونه‌ي توليدي به صورت زير است: (عدد interval بر اساس ثانيه است)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>XML</title>
<script src='jquery-1.3.min.js' type='text/javascript'></script>
<script src='jquery.ghesaar.js' type='text/javascript'></script>
<script type="text/javascript">
$(document).ready(function(){
$("#output").ghesaar({interval:5});
});

</script>
</head>
<body>
<span id="output" dir="rtl" style=" "/>
</body>

</html>

بهتر شد، نه؟!

به صورت ساده:
براي استفاده از آن، سه فايل jquery-1.3.min.js (يا نگارش جديدتر آن)، jquery.ghesaar.js و Ghesaar.xml را بايد آپلود كنيد. چند سطري را كه در قسمت head صفحه فوق مشاهده مي‌نمائيد بايد اضافه شوند. سپس يك span يا div را جهت نمايش اين جملات قصار به هر جايي از ساختار صفحه خود كه علاقمند بوديد اضافه كنيد (id آن مهم است و در قسمت نمايش جملات قصار مورد جستجو قرار مي‌گيرد).

فايل‌هاي اين پروژه را از اينجا دريافت كنيد.