۱۳۸۸/۱۰/۰۸

كتابچه‌ي رايگان نصب و راه اندازي Exchange Server 2010


در طي اين چند سالي كه كارم برنامه نويسي ASP.Net بوده است، هيچ نرم افزار پايه‌اي همانند Exchange server در كيفيت كارهاي من تاثير نداشته است و اساسا تمام هماهنگي‌هاي برنامه‌هاي من با كمك Exchange server و Outlook صورت مي‌گيرد. از گرفتن تائيد تا آلارم فلان درخواست تا يك سري از گزارشات زمانبندي شده و غيره. ديگر كار به جايي رسيده است كه اگر كاربران ايميلي را دريافت نكنند اطلاعات وارد شده در برنامه‌ها را معتبر نمي‌دانند و به برنامه‌ها مراجعه نمي‌كنند!
به همين منظور كتابچه‌ي راهنماي نصب و راه اندازي Exchange server 2010 را تهيه كرده‌ام كه در طي حدودا 120 صفحه، به صورت كاربردي و ساده، آنچه را كه بايد براي راه اندازي و مديريت اين برنامه در يك سازمان بدانيد، در اختيار شما قرار مي‌دهد.

مقدمه‌ي كتابچه

برنامه‌ي Exchange server ، نرم افزار ارسال و دريافت ايميل سازماني مايكروسافت است كه در رده‌ي محصولات سرور آن شركت قرار مي‌گيرد. اولين نگارش Exchange server در سال 1993 ارائه شد و به صورت محدود در اختيار حدود 500 شركت قرار گرفت. در سال 1996 اولين نگارش عمومي آن به نام Exchange server 4.0 به عموم ارائه گشت و در سال 1997 با ارائه‌ي Exchange server 5.0 آمار مشتريان اين محصول به 32 هزار كاربر رسيد. به همراه اين نگارش، اولين نسخه‌ي برنامه Outlook web access نيز ارائه گرديد. با افزايش استقبال از اين محصول،‌ در همان سال نگارش 5.5 آن نيز ارائه شد و ظرفيت بانك‌هاي اطلاعاتي آن تا 16TB در نگارش سازماني آن افزايش يافت. در سال 2000، اولين نگارش يكپارچه‌ي آن با Active directory ارائه شد. بزرگترين مشكل اين محصول در سال 2000، كوچ از نگارش‌هاي قديمي به نگارش جديد بودند كه اين مشكل در سال 2003 با ارائه Exchange server 2003 برطرف گرديد. در اواخر سال 2006 ، Exchange server 2007 ارائه گشت كه مهمترين تفاوت آن با نگارش‌هاي قبلي، ارائه‌ي آن تنها براي سكوهاي 64 بيتي بود به همراه بهبودهايي در اندازه‌ي صندوق‌هاي پستي تا 2 گيگابايت، تضمين فعاليت بي‌وقفه بهبود يافته ، شروع به كنار گذاري Public folders و تمهيداتي جهت ارسال و دريافت پيغام‌هاي صوتي. در اواخر سال 2009 نگارش 2010 اين محصول ارائه گشت كه تنها با ويندوز سرور 2008 سازگار مي‌باشد و در آن عمده‌ي مشكلات به همراه نگارش 2007 آن برطرف شده است همانند Outlook web access سازگار با تمامي مرورگرهاي امروزي، امكان مديريت تحت وب صندوق‌هاي پستي كاربران، بازنگري در گزينه‌هاي تضمين فعاليت بي‌وقفه و ساده سازي آن‌ها، افزايش تعداد بانك‌هاي اطلاعاتي قابل تعريف در يك سرور و بسياري از موارد ديگر كه در طي چندين فصل به بررسي آن‌ها خواهيم پرداخت.


دريافت فايل ، 7.7 MB

۱۳۸۸/۱۰/۰۵

Fluent Linq to Sql


نگارش بعدي يا چهارم entity framework چيزي است شبيه به Fluent NHibernate . يعني اگر مقاله‌اي را در اين زمينه مطالعه كنيد و عنوان آن حذف شود، نمي‌توان تشخيص داد كه اين مقاله مربوط به entity framework است يا Fluent NHibernate. هر چند entity framework حداقل دو نگارش ديگر لازم دارد تا NHibernate را كاملا پشت سر بگذارد.
از آن طرف محبوبيت Linq to SQL هم هنوز پابرجا است و براي مثال سايت پر ترافيكي مثل stack overflow از آن استفاده مي‌كند و بسيار هم موفق بوده و كارش را به خوبي انجام مي‌دهد.
پروژه مكملي به نام Fluent Linq to Sql با الهام گيري از Fluent NHibernate در سايت codeplex موجود است كه اين نوع نگاشت‌ها را براي Linq to Sql نيز ميسر مي‌سازد. به اين صورت ديگر نيازي به استفاده از attributes و يا فايل‌هاي xml نگاشت‌هاي Linq to Sql نخواهد بود. همچنين مدل كاري اول كد بعد ديتابيس نيز به اين صورت محقق مي‌شود.



۱۳۸۸/۱۰/۰۲

آشنايي با M.A.F - قسمت دوم


قسمت قبل بيشتر آشنايي با يك سري از اصطلاحات مرتبط با فريم ورك MAF بود و همچنين نحوه‌ي كلي استفاده از آن. در اين قسمت يك مثال ساده را با آن پياده سازي خواهيم كرد و فرض قسمت دوم بر اين است كه افزونه‌ي Visual Studio Pipeline Builder را نيز نصب كرده‌ايد.

يك نكته پيش از شروع:
- اگر افزونه‌ي Visual Studio Pipeline Builder پس از نصب به منوي Tools اضافه نشده است، يك پوشه‌ي جديد را به نام Addins در مسير Documents\Visual Studio 2008 ايجاد كرده و سپس فايل‌هاي آن‌را در اين مسير كپي كنيد.

ساختار اوليه يك پروژه MAF

- پروژ‌ه‌هايي كه از MAF استفاده مي‌كنند، نياز به ارجاعاتي به دو اسمبلي استاندارد System.AddIn.dll و System.AddIn.Contract.dll دارند (مطابق شكل زير):



- ساختار آغازين يك پروژه MAF از سه پروژه تشكيل مي‌شود كه توسط افزونه‌ي Visual Studio Pipeline Builder به 7 پروژه بسط خواهد يافت.
اين سه پروژه استاندارد آغازين شامل موارد زير هستند:



- هاست: همان برنامه‌ي اصلي كه قرار است از افزونه استفاده كند.
- قرار داد: نحو‌ه‌ي تعامل هاست و افزونه در اين پروژه تعريف مي‌شود. (يك پروژه از نوع class library)
- افزونه: كار پياده سازي قرار داد را عهده دار خواهد شد. (يك پروژه از نوع class library)

- همچنين مرسوم است جهت مديريت بهتر خروجي‌هاي حاصل شده يك پوشه Output را نيز به اين solution اضافه كنند:



اكنون با توجه به اين محل خروجي، به خواص Build سه پروژه موجود مراجعه كرده و مسير Build را اندكي اصلاح خواهيم كرد (هر سه مورد بهتر است اصلاح شوند)، براي مثال:



نكته‌ي مهم هم اينجا است كه خروجي host بايد به ريشه اين پوشه تنظيم شود و ساير پروژه‌ها هر كدام خروجي خاص خود را در پوشه‌اي داخل اين ريشه بايد ايجاد كنند.



تا اينجا قالب اصلي كار آماده شده است. قرارداد ما هم به شكل زير است (ويژگي AddInContract آن نيز نبايد فراموش شود):

using System.AddIn.Pipeline;
using System.AddIn.Contract;

namespace CalculatorConract
{
[AddInContract]
public interface ICalculatorContract : IContract
{
double Operate(string operation, double a, double b);
}
}

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

ايجاد pipeline

اگر قسمت قبل را مطالعه كرده باشيد، يك راه حل مبتني بر MAF از 7 پروژه تشكيل مي‌شود كه عمده‌ترين خاصيت آن‌ها مقاوم كردن سيستم در مقابل تغييرات نگارش قرارداد است. در اين حالت اگر قرار داد تغيير كند، نه هاست و نه افزونه‌ي قديمي، نيازي به تغيير در كدهاي خود نخواهند داشت و اين پروژه‌هاي مياني هستند كه كار وفق دادن (adapters) نهايي را برعهده مي‌گيرند.


براي ايجاد خودكار View ها و همچنين Adapters ، از افزونه‌ي Visual Studio Pipeline Builder كه پيشتر معرفي شد استفاده خواهيم كرد.



سه گزينه‌ي آن هم مشخص هستند. نام پروژه‌ي قرارداد، مسير پروژه‌ي هاست و مسير خروجي نهايي معرفي شده. پيش از استفاده از اين افزونه نياز است تا يكبار solution مورد نظر كامپايل شود. پس از كليك بر روي دكمه‌ي OK، پروژه‌هاي ذكر شده ايجاد خواهند شد:


پس از ايجاد اين پروژه‌ها، نياز به اصلاحات مختصري در مورد نام اسمبلي و فضاي نام هر كدام مي‌باشد؛ زيرا به صورت پيش فرض هر كدام به نام template نامگذاري شده‌اند:



پياده سازي افزونه

قالب كاري استفاده از اين فريم ورك آماده است. اكنون نوبت به پياده سازي يك افزونه مي‌باشد. به پروژه AddIn مراجعه كرده و ارجاعي را به اسمبلي AddInView خواهيم افزود. به اين صورت افزونه‌ي ما به صورت مستقيم با قرارداد سروكار نداشته و ارتباطات، در راستاي همان pipeline تعريف شده، جهت مقاوم شدن در برابر تغييرات صورت مي‌گيرد:
using System;
using CalculatorConract.AddInViews;
using System.AddIn;

namespace CalculatorAddIn
{
[AddIn]
public class MyCalculatorAddIn : ICalculator
{
public double Operate(string operation, double a, double b)
{
throw new NotImplementedException();
}
}
}

در اينجا افزونه‌ي ما بايد اينترفيس ICalculator مربوط به AddInView را پياده سازي نمايد كه براي مثال خواهيم داشت:

using System;
using CalculatorConract.AddInViews;
using System.AddIn;

namespace CalculatorAddIn
{
[AddIn("افزونه يك", Description = "توضيحات", Publisher = "نويسنده", Version = "نگارش يك")]
public class MyCalculatorAddIn : ICalculator
{
public double Operate(string operation, double a, double b)
{
switch (operation)
{
case "+":
return a + b;
case "-":
return a - b;
case "*":
return a * b;
default:
throw new NotSupportedException("عمليات مورد نظر توسط اين افزونه پشتيباني نمي‌شود");
}
}
}
}

همانطور كه در قسمت قبل نيز ذكر شد، اين كلاس بايد با ويژگي AddIn مزين شود كه توسط آن مي‌توان توضيحاتي در مورد نام ، نويسنده و نگارش افزونه ارائه داد.


استفاده از افزونه‌ي توليد شده

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

نكته‌ي مهم!
در هر دو ارجاع به HostView و يا AddInView بايد خاصيت Copy to local به false تنظيم شود، در غير اينصورت افزونه‌ي شما بارگذاري نخواهد شد.



پس از افزودن ارجاعي به HostView، نمونه‌اي از استفاده از افزونه‌ي توليد شده به صورت زير مي‌تواند باشد كه توضيحات مربوطه به صورت كامنت آورده شده است:

using System;
using System.AddIn.Hosting;
using CalculatorConract.HostViews;

namespace Calculator
{
class Program
{
private static ICalculator _calculator;

static void doOperation()
{
Console.WriteLine("1+2: {0}", _calculator.Operate("+", 1, 2));
}

static void Main(string[] args)
{
//مسير پوشه ريشه مربوطه به خط لوله افزونه‌ها
string path = Environment.CurrentDirectory;

//مشخص سازي مسير خواندن و كش كردن افزونه‌ها
AddInStore.Update(path);

//يافتن افزونه‌هايي سازگار با شرايط قرارداد پروژه
//در اينجا هيچ افزونه‌اي بارگذاري نمي‌شود
var addIns = AddInStore.FindAddIns(typeof(ICalculator), path);

//اگر افزونه‌اي يافت شد
if (addIns.Count > 0)
{
var addIn = addIns[0]; //استفاده از اولين افزونه
Console.WriteLine("1st addIn: {0}", addIn.Name);

//فعال سازي افزونه و همچنين مشخص سازي سطح دسترسي آن
_calculator = addIn.Activate<ICalculator>(AddInSecurityLevel.Intranet);

//يك نمونه از استفاده آن
doOperation();
}

Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}

چند نكته جالب توجه در مورد قابليت‌هاي ارائه شده:
- مديريت load و unload پويا
- امكان تعريف سطح دسترسي و ويژگي‌هاي امنيتي اجراي يك افزونه
- امكان ايزوله سازي پروسه اجراي افزونه از هاست (در ادامه توضيح داده خواهد شد)
- مقاوم بودن پروژه به نگارش‌هاي مختلف قرارداد


اجراي افزونه در يك پروسه مجزا

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

//فعال سازي افزونه و همچنين مشخص سازي سطح دسترسي آن
//همچنين جدا سازي پروسه اجرايي افزونه از هاست
_calculator = addIn.Activate<ICalculator>(
new AddInProcess(),
AddInSecurityLevel.Intranet);

در اين حالت اگر پس از فعال شدن افزونه، يك break point قرار دهيم و به task manager ويندوز مراجعه نمائيم، پروسه‌ي مجزاي افزونه قابل مشاهده است.



براي مطالعه بيشتر + ، + ، + و +

۱۳۸۸/۰۹/۳۰

آشنايي با M.A.F - قسمت اول


در طي چند مقاله قصد بررسي نحوه‌ي توليد برنامه‌هاي توسعه پذير (extensible) را با استفاده از plug-ins و يا add-ins داريم.

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


در حال حاضر حداقل دو فريم ورك عمده جهت انجام اين‌كار و توليد افزونه‌ها براي دات نت فريم ورك مهيا است:
الف) managed addin framework يا MAF
ب) managed extensibility framework يا MEF

فضاي نام جديدي به دات نت فريم ورك سه و نيم به نام System.AddIn اضافه شده است كه به آن Managed AddIn Framework يا MAF نيز اطلاق مي‌شود. از اين فريم ورك در VSTO (توليد افزونه براي مجموعه‌ي آفيس) توسط خود مايكروسافت استفاده شده است.

فريم ورك توسعه‌ي افزونه‌هاي مديريت شده در دات نت فريم ورك سه و نيم، مزاياي زير را در اختيار ما خواهد گذاشت:
- امكانات load و unload افزونه‌هاي توليد شده
- امكان تغيير افزونه‌ها در زمان اجراي برنامه اصلي بدون نياز به بستن آن
- ارائه‌ي محيطي ايزوله با ترسيم مرزي بين افزونه و برنامه اصلي
- مديريت طول عمر افزونه
- مديريت سازگاري با نگارش‌هاي قبلي و يا بعدي يك افزونه
- امكانات به اشتراك گذاري افزونه‌ها با برنامه‌هاي ديگر
- تنظيمات امنيتي و مشخص سازي سطح دسترسي افزونه‌ها
و ...

يك راه حل مبتني بر MAF مي‌تواند شامل 7 پروژه باشد (كه به روابط تعريف شده در آن pipeline هم گفته مي‌شود):

Host : همان برنامه‌ي اصلي است كه توسط يك سري افزونه، توسعه يافته است.
Host View : بيانگر انتظارات هاست از افزونه‌ها است. به عبارت ديگر افزونه‌ها بايد موارد ليست شده در اين پروژه را پياده سازي كنند.
Host Side Adapter : پل ارتباطي Host View و پروژه‌ي Contract است.
Contract: اينترفيسي است كه كار برقراري ارتباط بين Host و افزونه‌ها را برعهده دارد.
Add-In Side Adapter : پل ارتباطي بين Add-In View و Contract است.
Add-In View :‌ حاوي متدها و اشيايي است كه جهت برقراري ارتباط با هاست از آن‌ها استفاده مي‌شود.
Add-In : اسمبلي است كه توسط هاست جهت توسعه‌ي قابليت‌هاي خود بارگذاري مي‌شود (به آن Add-On ، Extension ، Plug-In و Snap-In هم گفته مي‌شود).

هدف از اين جدا سازي‌ها ارائه‌ي راه حل loosely-coupledايي است كه امكان ايزوله سازي، اعمال شرايط امنيتي ويژه و همچنين كنترل نگارش‌هاي مختلف را تسهيل مي‌بخشد و اين امر با استفاده از interface هاي معرفي شده ميسر گرديده است. اين pipeline از قسمت‌هاي ذيل تشكيل مي‌شود:



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

[AddInContract]
public interface ITranslator : IContract
{
string Translate(string input);
}

استفاده از ويژگي AddInContract و پياده سازي اينترفيس IContract جزو مراحل كاري استفاده از MAF است. MAF هنگام توليد پوياي pipeline ذكر شده به دنبال ويژگي AddInContract مي‌گردد. اين موارد در فضاي نام System.AddIn.Pipeline تعريف شده‌اند.

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

ديدگاه هاست نسبت به قرار داد:
public abstract class TranslatorHostView
{
public abstract string Translate(string input);
}
ديدگاه افزونه نسبت به قرار داد:
[AddInBase]
public abstract class TranslatorHostView
{
public abstract string Translate(string input);
}

هر دو كلاس فوق بر اساس قرار موجود بنا مي‌شوند اما وابسته به آن نيستند. به همين جهت به صورت كلاس‌هايي abstract تعريف شده‌اند. در سمت افزونه، كلاس تعريف شده ديدگاه آن با كلاس ديدگاه سمت هاست تقريبا يكسان مي‌باشد؛ اما با ويژگي AddInBase تعريف شده در فضاي نام System.AddIn.Pipeline مزين گرديده است.


وفق دهنده‌ها يا Adapters
آخرين قسمت pipeline ، وفق دهنده‌ها هستند كه كار آن‌ها اتصال قرار داد به ديدگاه‌ها است و توسط آن مديريت طول عمر افزونه و همچنين تبديل اطلاعات بين قسمت‌هاي مختلف انجام مي‌شود. شايد در نگاه اول وجود آن‌ها زائد به نظر برسد اما اين جدا سازي كدها سبب توليد افزونه‌هايي خواهد شد كه به نگارش هاست و برنامه اصلي وابسته نبوده و بر عكس (version tolerance). به دو كلاس زير دقت نمائيد:

كلاس زير با ويژگي [HostAdapter] تعريف شده در فضاي نام System.AddIn.Pipeline، مزين شده است و كار آن اتصال HostView به Contract مي‌باشد. براي اين منظور TranslatorHostView ايي را كه پيشتر معرفي كرديم بايد پياده سازي نمايد. علاوه بر اين با ايجاد وهله‌اي از كلاس ContractHandle ، كار مديريت طول عمر افزونه را نيز مي‌توان انجام داد.

[HostAdapter]
public class TranslatorHostViewToContract : TranslatorHostView
{
ITranslator _contract;
ContractHandle _lifetime;

public TranslatorHostViewToContract(ITranslator contract)
{
_contract = contract;
_lifetime = new ContractHandle(contract);
}

public override string Translate (string inp)
{
return _contract.Translate(inp);
}
}
كلاس سمت افزونه نيز بسيار شبيه قسمت قبل است و كار آن اتصال AddInView به Contract مي‌باشد كه با پياده سازي ContractBase و Itranslator صورت خواهد گرفت. همچنين اين كلاس به ويژگي AddInAdapter مزين گرديده است.

[AddInAdapter]
public class TranslatorAddInViewToContract : ContractBase, ITranslator
{
TranslatorAddInView _view;

public TranslatorAddInViewToContract(TranslatorView view)
{
_view = view;
}

public string Translate(string inp)
{
return _view.Translate(inp);
}
}

قسمت عمده‌اي از اين كدها تكراري است. جهت سهولت توليد اين كلاس‌ها و پروژه‌هاي مرتبط، تيم مربوطه برنامه‌اي را به نام pipeline builder ارائه داده است كه از آدرس زير قابل دريافت است:


اين برنامه با دريافت اسمبلي مربوط بهcontract ، كار ساخت خودكار كلاس‌هاي adapters و views را انجام خواهد داد.

ايجاد افزونه
پس از ساخت قسمت‌هاي مختلف pipeline ، اكنون مي‌توان افزونه را ايجاد نمود. هر افزونه بايد add-in view را پياده سازي كرده و با ويژگي AddIn مزين شود. براي مثال:

[AddIn("GoogleTranslator", Description="Universal translator",
Version="1.0.0.0", Publisher="YourName")]
public class GoogleAddIn : TranslatorAddInView
{
public string Translate(string input)
{
...
}
}

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

۱۳۸۸/۰۹/۲۸

مقايسه امنيت Oracle11g و SQL server 2008 از ديد آمار در سال 2009


جدول زير تعداد باگ‌هاي امنيتي Oracle11g و SQL server 2008 را تا ماه نوامبر 2009 نمايش مي‌دهد:


Product Advisories Vulnerabilities
SQL Server 2008 0 0
Oracle11g 7 239


و به صورت خلاصه مايكروسافت در 6 سال گذشته تنها 59 باگ امنيتي وصله شده مربوط به نگارش‌هاي مختلف SQL Server داشته است (از نگارش 2000 به بعد). در طي همين مدت اوراكل (نگارش‌هاي 8 تا 10) تعداد 233 وصله امنيتي را ارائه داده است.
در سال 2006 ، اس كيوال سرور 2000 با سرويس پك 4 ، به عنوان امن‌ترين بانك اطلاعاتي موجود در بازار شناخته شد (به همراه PostgreSQL). در همين زمان Oracle10g در قعر اين جدول قرار گرفت.

اعداد و آمار از سايت secunia.com استخراج شده است: + و +

۱۳۸۸/۰۹/۲۷

تزريق وابستگي (dependency injection) به زبان ساده


اين مطلب در ادامه‌ي "آشنايي با الگوي IOC يا Inversion of Control (واگذاري مسئوليت)" مي‌باشد كه هر از چندگاهي يك قسمت جديد و يا كاملتر از آن ارائه خواهد شد.

==============
به صورت خلاصه ترزيق وابستگي و يا dependency injection ، الگويي است جهت تزريق وابستگي‌هاي خارجي يك كلاس به آن، بجاي استفاده مستقيم از آن‌ها در درون كلاس.
براي مثال شخصي را در نظر بگيريد كه قصد خريد دارد. اين شخص مي‌تواند به سادگي با كمك يك خودرو خود را به اولين محل خريد مورد نظر برساند. حال تصور كنيد كه 7 نفر عضو يك گروه، با هم قصد خريد دارند. خوشبختانه چون تمام خودروها يك اينترفيس مشخصي داشته و كار كردن با آن‌ها تقريبا شبيه به يكديگر است، حتي اگر از يك ون هم جهت رسيدن به مقصد استفاده شود، امكان استفاده و راندن آن همانند ساير خودروها مي‌باشد و اين دقيقا همان مطلبي است كه هدف غايي الگوي تزريق وابستگي‌ها است. بجاي اين‌كه هميشه محدود به يك خودرو براي استفاده باشيم، بنابر شرايط، خودروي متناسبي را نيز مي‌توان مورد استفاده قرار داد.
در دنياي نرم افزار، وابستگي كلاس Driver ، كلاس Car است. اگر موارد ذكر شده را بدون استفاده از تزريق وابستگي‌ها پياده سازي كنيم به كلاس‌هاي زير خواهيم رسيد:

//Person.cs
namespace DependencyInjectionForDummies
{
class Person
{
public string Name { get; set; }
}
}

//Car.cs
using System;
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Car
{
List<Person> _passengers = new List<Person>();

public void AddPassenger(Person p)
{
_passengers.Add(p);
Console.WriteLine("{0} added!", p.Name);
}

public void Drive()
{
foreach (var passenger in _passengers)
Console.WriteLine("Driving {0} ...!", passenger.Name);
}
}
}

//Driver.cs
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Driver
{
private Car _myCar = new Car();

public void DriveToMarket(IList<Person> passengers)
{
foreach (var passenger in passengers)
_myCar.AddPassenger(passenger);

_myCar.Drive();
}
}
}

//Program.cs
using System.Collections.Generic;
using System;

namespace DependencyInjectionForDummies
{
class Program
{
static void Main(string[] args)
{
new Driver().DriveToMarket(
new List<Person>
{
new Person{ Name="Ali" },
new Person{ Name="Vahid" }
});

Console.WriteLine("Press a key ...");
Console.ReadKey();
}
}
}

توضيحات:
كلاس شخص (Person) جهت تعريف مسافرين، اضافه شده؛ سپس كلاس خودرو (Car) كه اشخاص را مي‌توان به آن اضافه كرده و سپس به مقصد رساند، تعريف گرديده است. همچنين كلاس راننده (Driver) كه بر اساس ليست مسافرين، آن‌ها را به خودروي خاص ذكر شده هدايت كرده و سپس آن‌ها را با كمك كلاس خودرو به مقصد مي‌رساند؛ نيز تعريف شده است. در پايان هم يك كلاينت ساده جهت استفاده از اين كلاس‌ها ذكر شده است.
همانطور كه ملاحظه مي‌كنيد كلاس راننده به كلاس خودرو گره خورده است و اين راننده هميشه تنها از يك نوع خودروي مشخص مي‌تواند استفاده كند و اگر روزي قرار شد از يك ون كمك گرفته شود، اين كلاس بايد بازنويسي شود.

خوب! اكنون اگر اين كلاس‌ها را بر اساس الگوي تزريق وابستگي‌ها (روش تزريق در سازنده كه در قسمت قبل بحث شد) بازنويسي كنيم به كلاس‌هاي زير خواهيم رسيد:

//ICar.cs
using System;

namespace DependencyInjectionForDummies
{
interface ICar
{
void AddPassenger(Person p);
void Drive();
}
}

//Car.cs
using System;
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Car : ICar
{
//همانند قسمت قبل
}
}

//Van.cs
using System;
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Van : ICar
{
List<Person> _passengers = new List<Person>();

public void AddPassenger(Person p)
{
_passengers.Add(p);
Console.WriteLine("{0} added!", p.Name);
}

public void Drive()
{
foreach (var passenger in _passengers)
Console.WriteLine("Driving {0} ...!", passenger.Name);
}
}
}

//Driver.cs
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Driver
{
private ICar _myCar;

public Driver(ICar myCar)
{
_myCar = myCar;
}

public void DriveToMarket(IList<Person> passengers)
{
foreach (var passenger in passengers)
_myCar.AddPassenger(passenger);

_myCar.Drive();
}
}
}

//Program.cs
using System.Collections.Generic;
using System;

namespace DependencyInjectionForDummies
{
class Program
{
static void Main(string[] args)
{
Driver driver = new Driver(new Van());
driver.DriveToMarket(
new List<Person>
{
new Person{ Name="Ali" },
new Person{ Name="Vahid" }
});

Console.WriteLine("Press a key ...");
Console.ReadKey();
}
}
}

توضيحات:
در اينجا يك اينترفيس جديد به نام ICar اضافه شده است و بر اساس آن مي‌توان خودروهاي مختلفي را با نحوه‌ي بكارگيري يكسان اما با جزئيات پياده سازي متفاوت تعريف كرد. براي مثال در ادامه، يك كلاس ون با پياده سازي اين اينترفيس تشكيل شده است. سپس كلاس راننده‌ي ما بر اساس ترزيق اين اينترفيس در سازنده‌ي آن بازنويسي شده است. اكنون اين كلاس ديگر نمي‌داند كه دقيقا چه خودرويي را بايد مورد استفاده قرار دهد و از وابستگي مستقيم به نوعي خاص از آن‌ها رها شده است؛ اما مي‌داند كه تمام خودروها، اينترفيس مشخص و يكساني دارند. به تمام آن‌ها مي‌توان مسافراني را افزود و سپس به مقصد رساند. در پايان نيز يك راننده جديد بر اساس خودروي ون تعريف شده، سپس يك سري مسافر نيز تعريف گرديده و نهايتا متد DriveToMarket فراخواني شده است.
به اين صورت به يك سري كلاس اصطلاحا loosely coupled رسيده‌ايم. ديگر راننده‌ي ما وابسته‌ي به يك خودروي خاص نيست و هر زماني كه لازم بود مي‌توان خودروي مورد استفاده‌ي او را تغيير داد بدون اينكه كلاس راننده را بازنويسي كنيم.
يكي ديگر از مزاياي تزريق وابستگي‌ها ساده سازي unit testing كلاس‌هاي برنامه توسط mocking frameworks است. به اين صورت توسط اين نوع فريم‌ورك‌ها مي‌توان رفتار يك خودرو را تقليد كرد بجاي اينكه واقعا با تمام ريز جرئيات آن‌ها بخواهيم سروكار داشته باشيم (وابستگي‌ها را به صورت مستقل مي‌توان آزمايش كرد).

۱۳۸۸/۰۹/۲۶

عدم كاهش حجم لاگ فايل SQL Server


در مورد روش‌هاي كاهش حجم لاگ فايل‌هاي SQL Server در اين مطلب بحث شد.
اما يكي از ديتابيس‌هاي قديمي shrink نمي‌شد و پيغام خطاي زير را صادر مي‌كرد:

Cannot shrink log file 2 because of minimum log space required.

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

DBCC OPENTRAN
كه نتيجه به صورت زير بود:

Replicated Transaction Information:
Oldest distributed LSN : (0:0:0)
Oldest non-distributed LSN : (5291:25:1)

وجود سطر مربوط به Oldest non-distributed LSN به اين معنا است كه هنوز يك replication نا تمام بر روي اين ديتابيس موجود است. البته چون اين ديتابيس از يك سرور ديگر به اينجا منتقل شده بود و هيچ نوع replication ايي هم در اين سرور بر روي آن تنظيم نشده بود؛ بنابراين ابتدا اين replication حذف شد:
exec sp_removedbreplication 'dbName', 'both';

سپس مجددا دستور زير جهت مشاهده‌ي وضعيت تراكنش‌هاي ناتمام صادر شد:
DBCC OPENTRAN

كه اين‌بار ديگر هيچ خروجي نداشت.
اكنون با استفاده از روش ذكر شده، لاگ فايل 70 گيگابايتي اين ديتابيس به سادگي به چند مگابايت shrink شد.

فايرفاكس 3.5.6 و غيرفعال شدن افزونه‌ها


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

راه حل ساده‌اي هم دارد:
فايرفاكس را بسته و پوشه‌ي Profiles مربوط به فايرفاكس را پيدا كنيد. براي مثال:
C:\Users\Vahid\AppData\Roaming\Mozilla\Firefox\Profiles
در اين پوشه و زير پوشه‌هاي آن چهار فايل زير را پيدا كرده و به يك پوشه ديگر منتقل كرده و يا حذف كنيد:
extensions.cache
extensions.ini
extensions.rdf
compatibility.ini

اكنون با اجراي فايرفاكس اين فايل‌ها مجددا توليد شده و مشكلات مربوطه هم برطرف مي‌شود.
پس از توليد خودكار مجدد اين فايل‌ها، مجددا افزونه‌ها ظاهر شدند و همه چيز مثل قبل شد!

۱۳۸۸/۰۹/۲۵

آشنايي با الگوي IOC يا Inversion of Control (واگذاري مسئوليت)


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

namespace IOCBeginnerGuide
{
class Kid
{
private int _age;
private string _name;

public Kid(int age, string name)
{
_age = age;
_name = name;
}

public override string ToString()
{
return "KID's Age: " + _age + ", Kid's Name: " + _name;
}
}
}

اكنون كلاس والد را با توجه به اينكه در حين ايجاد اين شيء، فرزندان او نيز بايد ايجاد شوند؛ در نظر بگيريد:
using System;

namespace IOCBeginnerGuide
{
class Parent
{
private int _age;
private string _name;
private Kid _obj;

public Parent(int personAge, string personName, int kidsAge, string kidsName)
{
_obj = new Kid(kidsAge, kidsName);
_age = personAge;
_name = personName;
}

public override string ToString()
{
Console.WriteLine(_obj);
return "ParentAge: " + _age + ", ParentName: " + _name;
}
}
}

و نهايتا مثالي از استفاده از آن توسط يك كلاينت:

using System;

namespace IOCBeginnerGuide
{
class Program
{
static void Main(string[] args)
{
Parent p = new Parent(35, "Dev", 6, "Len");
Console.WriteLine(p);

Console.ReadKey();
Console.WriteLine("Press a key...");
}
}
}

كه خروجي برنامه در اين حالت مساوي سطرهاي زير مي‌باشد:

KID's Age: 6, Kid's Name: Len
ParentAge: 35, ParentName: Dev

مثال فوق نمونه‌اي از الگوي طراحي تركيب يا composition مي‌باشد كه به آن Object Dependency يا Object Coupling نيز گفته مي‌شود. در اين حالت ايجاد شيء والد وابسته است به ايجاد شيء فرزند.

مشكلات اين روش:
1- با توجه به وابستگي شديد والد به فرزند، اگر نمونه سازي از شيء فرزند در سازنده‌ي كلاس والد با موفقيت روبرو نشود، ايجاد نمونه‌ي والد با شكست مواجه خواهد شد.
2- با از بين رفتن شيء والد، فرزندان او نيز از بين خواهند رفت.
3- هر تغييري در كلاس فرزند، نياز به تغيير در كلاس والد نيز دارد (اصطلاحا به آن Dangling Reference هم گفته مي‌شود. اين كلاس آويزان آن كلاس است!).

چگونه اين مشكلات را برطرف كنيم؟
بهتر است كار وهله سازي از كلاس Kid به يك شيء، متد يا حتي فريم ورك ديگري واگذار شود. به اين واگذاري مسئوليت، delegation و يا inversion of control - IOC نيز گفته مي‌شود.

بنابراين IOC مي‌گويد كه:
1- كلاس اصلي (يا همان Parent) نبايد به صورت مستقيم وابسته به كلاس‌هاي ديگر باشد.
2- رابطه‌ي بين كلاس‌ها بايد بر مبناي تعريف كلاس‌هاي abstract باشد (و يا استفاده از interface ها).

تزريق وابستگي يا Dependency injection
براي پياده سازي IOC از روش تزريق وابستگي يا dependency injection استفاده مي‌شود كه مي‌تواند بر اساس constructor injection ، setter injection و يا interface-based injection باشد و به صورت خلاصه پياده سازي يك شيء را از مرحله‌ي ساخت وهله‌اي از آن مجزا و ايزوله مي‌سازد.

مزاياي تزريق وابستگي‌ها:
1- گره خوردگي اشياء را حذف مي‌كند.
2- اشياء و برنامه را انعطاف پذيرتر كرده و اعمال تغييرات به آن‌ها ساده‌تر مي‌شود.

روش‌هاي متفاوت تزريق وابستگي به شرح زير هستند:

تزريق سازنده يا constructor injection :
در اين روش ارجاعي از شيء مورد استفاده، توسط سازنده‌ي كلاس استفاده كننده از آن دريافت مي‌شود. براي نمونه در مثال فوق از آنجائيكه كلاس والد به كلاس فرزندان وابسته است، يك ارجاع از شيء Kid به سازنده‌ي كلاس Parent بايد ارسال شود.
اكنون بر اين اساس تعاريف، كلاس‌هاي ما به شكل زير تغيير خواهند كرد:

//IBuisnessLogic.cs
namespace IOCBeginnerGuide
{
public interface IBuisnessLogic
{
}
}

//Kid.cs
namespace IOCBeginnerGuide
{
class Kid : IBuisnessLogic
{
private int _age;
private string _name;

public Kid(int age, string name)
{
_age = age;
_name = name;
}

public override string ToString()
{
return "KID's Age: " + _age + ", Kid's Name: " + _name;
}
}
}

//Parent.cs
using System;

namespace IOCBeginnerGuide
{
class Parent
{
private int _age;
private string _name;
private IBuisnessLogic _refKids;

public Parent(int personAge, string personName, IBuisnessLogic obj)
{
_age = personAge;
_name = personName;
_refKids = obj;
}

public override string ToString()
{
Console.WriteLine(_refKids);
return "ParentAge: " + _age + ", ParentName: " + _name;
}
}
}

//CIOC.cs
using System;

namespace IOCBeginnerGuide
{
class CIOC
{
Parent _p;

public void FactoryMethod()
{
IBuisnessLogic objKid = new Kid(12, "Ren");
_p = new Parent(42, "David", objKid);
}

public override string ToString()
{
Console.WriteLine(_p);
return "Displaying using Constructor Injection";
}
}
}

//Program.cs
using System;

namespace IOCBeginnerGuide
{
class Program
{
static void Main(string[] args)
{
CIOC obj = new CIOC();
obj.FactoryMethod();
Console.WriteLine(obj);

Console.ReadKey();
Console.WriteLine("Press a key...");
}
}
}

توضيحات:
ابتدا اينترفيس IBuisnessLogic ايجاد خواهد شد. تنها متدهاي اين اينترفيس در اختيار كلاس Parent قرار خواهند گرفت.
از آنجائيكه كلاس Kid توسط كلاس Parent استفاده خواهد شد، نياز است تا اين كلاس نيز اينترفيس IBuisnessLogic را پياده سازي كند.
اكنون سازنده‌ي كلاس Parent بجاي ارجاع مستقيم به شيء Kid ، از طريق اينترفيس IBuisnessLogic با آن ارتباط برقرار خواهد كرد.
در كلاس CIOC كار پياده سازي واگذاري مسئوليت وهله سازي از اشياء مورد نظر صورت گرفته است. اين وهله سازي در متدي به نام Factory انجام خواهد شد.
و در نهايت كلاينت ما تنها با كلاس IOC سركار دارد.

معايب اين روش:
- در اين حالت كلاس business logic، نمي‌تواند داراي سازنده‌ي پيش فرض باشد.
- هنگاميكه وهله‌اي از كلاس ايجاد شد ديگر نمي‌توان وابستگي‌ها را تغيير داد (چون از سازنده‌ي كلاس جهت ارسال مقادير مورد نظر استفاده شده است).

تزريق تنظيم كننده يا Setter injection
اين روش از خاصيت‌ها جهت تزريق وابستگي‌ها بجاي تزريق آن‌ها به سازنده‌ي كلاس استفاده مي‌كند. در اين حالت كلاس Parent مي‌تواند داراي سازنده‌ي پيش فرض نيز باشد.

مزاياي اين روش:
- از روش تزريق سازنده بسيار انعطاف پذيرتر است.
- در اين حالت بدون ايجاد وهله‌اي مي‌توان وابستگي اشياء را تغيير داد (چون سر و كار آن با سازنده‌ي كلاس نيست).
- بدون نياز به تغييري در سازنده‌ي يك كلاس مي‌توان وابستگي اشياء را تغيير داد.
- تنظيم كننده‌ها داراي نامي با معناتر و با مفهوم‌تر از سازنده‌ي يك كلاس مي‌باشند.

نحوه‌ي پياده سازي آن:
در اينجا مراحل ساخت Interface و همچنين كلاس Kid با روش قبل تفاوتي ندارند. همچنين كلاينت نهايي استفاده كننده از IOC نيز مانند روش قبل است. تنها كلاس‌هاي IOC و Parent بايد اندكي تغيير كنند:

//Parent.cs
using System;

namespace IOCBeginnerGuide
{
class Parent
{
private int _age;
private string _name;

public Parent(int personAge, string personName)
{
_age = personAge;
_name = personName;
}

public IBuisnessLogic RefKID {set; get;}

public override string ToString()
{
Console.WriteLine(RefKID);
return "ParentAge: " + _age + ", ParentName: " + _name;
}
}
}

//CIOC.cs
using System;

namespace IOCBeginnerGuide
{
class CIOC
{
Parent _p;

public void FactoryMethod()
{
IBuisnessLogic objKid = new Kid(12, "Ren");
_p = new Parent(42, "David");
_p.RefKID = objKid;
}

public override string ToString()
{
Console.WriteLine(_p);
return "Displaying using Setter Injection";
}
}
}

همانطور كه ملاحظه مي‌كنيد در اين روش يك خاصيت جديد به نام RefKID به كلاس Parent اضافه شده است كه از هر لحاظ نسبت به روش تزريق سازنده با مفهوم‌تر و خود توضيح دهنده‌تر است. سپس كلاس IOC جهت استفاده از اين خاصيت اندكي تغيير كرده است.

ماخذ

۱۳۸۸/۰۹/۲۳

چند نكته كوتاه و عمومي در مورد قبل و بعد از نصب ويندوز 7


- فايل ISO ايي كه از سايت‌هاي اين دور و اطراف قابل دريافت است، يك DVD از نوع bootable به شما ارائه نخواهد داد. بنابراين نياز است تا اين قابليت را فراهم كرد. خود مايكروسافت برنامه سورس بازي را در آدرس زير جهت تهيه يك bootable DVD يا حتي bootable flash drive از روي فايل ISO دريافت شده ارائه داده است:


- نياز است تا كليه افزونه‌ها، كلمات عبور ذخيره شده و غيره‌ي فايرفاكس را بتوان به سيستم جديد انتقال داد. ابزار رايگان و سورس باز MozBackup اين‌كار را به بهترين نحو ممكن ميسر مي‌سازد: +

- پس از نصب، نياز به صفحه كليد فارسي مرغوب مي‌باشد : + و +

- پس از نصب ويندوز 7 ، درايو ويندوز قبلي موجود شما ناپديد شده است! نحوه‌ي رفع مشكل : +

- هر چند در پيدا كردن درايورها از اينترنت مشكلي ندارد، اما بد نيست يكبار هم سيستم را با ابزار رايگاني جهت به روز بودن درايورها بررسي كرد: +

- اگر هنگام كار با Virtual PC مايكروسافت هنگام اتصال به VPN با خطاي 721 متوقف شديد، نگران نباشيد. با انتخاب گزينه‌ي run as admin اين مشكل برطرف مي‌شود.

- تنظيم DNS جديد گوگل نيز توصيه مي‌شود: +

و يك گجت تقويم فارسي هم كفايت مي‌كند : + و يا +

۱۳۸۸/۰۹/۲۰

مشكل فايل‌هاي ANSI-Windows-1256 با VS.Net در ويندوز 7


در ويندوز XP زمانيكه زبان سيستم و همچنين كشور جاري به ايران تنظيم شود، VS.Net فايل‌هاي ANSI را از نوع ANSI-Windows-1256 (يا همان ANSI-Arabic) در نظر مي‌گيرد و مشكلي هم براي ذخيره داده‌هاي يونيكد در اين نوع فايل‌هاي ANSI ويژه نخواهد بود (الزامي وجود ندارد كه اين فايل‌ها حتما به فرمت UTF8 ذخيره شوند). اما در ويندوز 7 با همان تنظيمات، VS.Net اين فايل‌ها را با encoding از نوع windows-1252 تشخيص مي‌دهد و پس از كامپايل برنامه‌اي كه قبلا مشكل نداشت، اين‌بار همه چيز به همه ريخته خواهد بود. شايد اينطور به نظر برسد كه اين فايل‌ها خراب شده‌اند، ولي خير. مشكلي وجود ندارد؛ فقط فرمت encoding خواندن آن‌ها بايد windows-1256 باشد (و نه 1252) و گرنه تخريب شده به نظر مي‌رسند.

تعداد فايل‌ها هم زياد است و نياز به يك روش سريع براي رفع اين مشكل وجود داشت.
بنابراين سه عمليات بايد صورت گيرد:
ليست كردن تمام فايل‌هاي مورد نظر (فايل‌هاي cs و aspx و امثال آن فقط)
پيدا كردن encoding جاري فايل‌ها : كداميك از آن‌ها با فرمت UTF-8 ذخيره نشده‌اند؟
تبديل به يونيكد: خواندن اين فايل‌هاي غير يونيكد يافت شده با فرمت windows-1256 و سپس ذخيره مجدد با فرمت UTF-8

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

الف) آيا فايل جاري مورد نظر با فرمت UTF-8 with signature ذخيره شده است؟
اين signature در مورد فايل‌هاي UTF-8 به سه بايت اول فايل بر مي‌گردد كه اصطلاحا byte-order mark يا BOM گفته مي‌شود و بايد مساوي EFBBBF باشد. چون فايل‌هاي ANSI اين امضا را ندارند، در يك سيستم ممكن است 1256 خوانده شوند و در يك سيستم ديگر 1252 يا نوع‌هاي ANSI ديگر بسته به تنظيمات جاري سيستم و مشكل اصلي از VS.Net نيست.

/// <summary>
/// آيا فايل مورد نظر با فرمت يونيكد داراي امضا ذخيره شده است؟
/// </summary>
/// <param name="filePath">فايل ورودي</param>
/// <returns>بله يا خير</returns>
public static bool IsUTF8(string filePath)
{
using (FileStream file = new FileStream(filePath,
FileMode.Open, FileAccess.Read, FileShare.Read))
{
if (file.CanSeek)
{
byte[] bom = new byte[4]; // Get the byte-order mark, if there is one
file.Read(bom, 0, 4);
if ((bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf)) // utf-8
{
return true;
}
else
{
return false;
}
}
else
{
//احتمالا فايل بايناري است
return false;
}
}
}

ب) خواندن يك فايل ANSI عربي با فرمت windows-1256 بدون تخريب اطلاعات آن و سپس ذخيره سازي با فرمت UTF-8

/// <summary>
/// تبديل يك فايل انسي عربي به يونيكد داراي امضاء
/// </summary>
/// <param name="path">مسير ورودي</param>
public static void FixWindows1256(string path)
{
try
{
//باز كردن فايل با فرمت انسي عربي و تبديل به يونيكد
string data = File.ReadAllText(path, Encoding.GetEncoding("windows-1256"));
//نوشتن حاصل يونيكد در جاي قبلي با فرمت مربوطه
File.WriteAllText(path, data, Encoding.UTF8);
}
catch (Exception ex)
{
//دسترسي وجود ندارد يا امثال آن
Console.WriteLine(ex.ToString());
}
}


پ.ن.
جالب اينجا است كه اين نوع فايل‌هاي ANSI عربي در وب زياد پيدا مي‌شوند. براي مثال اينجا كليك كنيد. تمام اين نوع فايل‌ها را با متد فوق مي‌توان بدون تخريب اطلاعات به فرمت UTF-8 داراي امضاء اصلاح كرد.

۱۳۸۸/۰۹/۱۸

انتقال SVN به يك سيستم جديد


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

الف) دريافت و نصب Visual SVN server
يا مي‌توان SVN خالص را از سايت آن دريافت كرد و يا جهت سهولت كار و همچنين دسترسي به يك كنسول مديريتي مي‌توان برنامه‌ي رايگان Visual SVN server را از آدرس زير دريافت و نصب كرد:

پس از نصب، ابتدا بايد يا كاربر جديدي را جهت استفاده از منابع آن تعريف كرد و يا از نحوه‌ي اعتبار سنجي يكپارچه با ويندوز هم مي‌توان استفاده كرد كه من از اين روش دوم استفاده مي‌كنم (شكل زير، كليك راست بر روي نود اصلي visual SVN server و سپس انتخاب خواص و مراجعه به برگه‌ي اعتبار سنجي آن):



ب)دريافت و نصب TortoiseSVN

نصب آن نكته‌ي خاصي ندارد. اما يك سري نكته‌ي ريز پس از نصب آن بهتر است رعايت شود كه در ادامه ذكر مي‌شود:

ج) دريافت و نصب برنامه‌ي WinMerge
برنامه‌ي Diff پيش فرض TortoiseSVN آنچنان قوي نيست. به همين جهت مي‌توان برنامه‌ي WinMerge را با آن يكپارچه كرد. براي اين منظور ابتدا آن‌را دريافت نمائيد:

اگر پس از نصب TortoiseSVN آن‌را نصب كنيد، در حين نصب پيشنهاد يكپارچه سازي با TortoiseSVN را نيز مي‌دهد. اگر ابتدا WinMerge را نصب كرده‌ايد و سپس TortoiseSVN بر روي سيستم شما نصب شده، فقط كافي است مطابق شكل زير ابتدا به قسمت Diff viewers آن مراجعه كرده و سپس با انتخاب گزينه‌ي external ، دستور خط فرمان زير را وارد نمائيد:

C:\Program Files (x86)\WinMerge\WinMergeU.exe -e -x -ub -dl %bname -dr %yname %base %mine



بديهي است مسير WinMergeU.exe مطابق مسير نصب در سيستم شما بايد تنظيم شود.

د) تنظيم مسير تحت نظر قرار گرفتن سيستم
TortoiseSVN به صورت پيش فرض كل سيستم را جهت مشاهده‌ي تغييرات تحت نظر قرار مي‌دهد كه گاهي باعث كاهش كارآيي آن خواهد شد. براي رفع اين مشكل مي‌توان مسيرهايي را كه پروژه‌هاي شما در آن قرار دارند را به آن معرفي نمود تا بار كلي سيستم كاهش يابد.



همانطور كه در شكل نيز ملاحظه مي‌كنيد، Include path مقدار دهي شده است.

ه) مشخص سازي پسوندهايي كه بهتر است از آن‌ها صرفنظر شود
به برگه‌ي general تنظيمات TortoiseSVN مراجعه كرده و در قسمت global ignore pattern آن، موارد زير را وارد نمائيد:



اين موارد شامل پروژه‌هاي دات نت، دلفي ، VC و امثال آن است و همچنين يك سري فايل بايناري كه عموما با پروژه‌هاي برنامه نويسي نيازي به ثبت نگارش آن‌ها نيست.

*.dcu *.~* dcu temp *.exe *.zip *.bkm *.ddp *.cfg *.dof *.dsk *.ini *.hlp *.gid *.bmp *.png *.gif ~* *.log bin debug release *.map *.chm *.bkf Thumbs.db *.mdb .obj *.elf *.stat *.ddp *.bpl *.map *.GID *.hlp *.opt *.dll *.raw *.BIN *.obj *.pdb *.scc Debug Release *.xml obj *.~* *.backup *.INI *.ArmLog *.KeyLog *.NanoLog *.Stats *.PreARM *.old *.drc *.*~ *.doc *.pdf *.bmp *.jpg *.MRW *.NEF *.ORF *.psd *.X3F __history *.local *.identcache *.bak Thumbs.db *.ldb *.dex *.rar DllDcu *.lck CVS cvs *.txt *.TXT *.jdbg *.HLP *.KWF *.xls *.cnt *.dsm *.dti *.tmp *.lnk *.cbk *.mes *.suo *.ncb *.user _ReSharper.* [Bb]in obj [Dd]ebug [Rr]elease *.aps *.eto


در همين برگه، اگر هنوز از VS2003 استفاده مي‌كنيد، تيك مربوط به استفاده از _svn بجاي .svn را قرار دهيد تا VS.Net با پوشه‌هاي مديريتي ذكر شده مشكل پيدا نكند.

و) نصب افزونه‌هاي SVN سازگار با VS.Net
يا مي‌توان از افزونه‌ي Visual SVN استفاده كرد (كه رايگان نيست) و يا AnkhSVN كه رايگان و سورس باز است.
ولي در كل يك مورد را بيشتر نصب نكنيد. علت هم كند شدن VS.Net است به دليل فعاليت‌هاي پشت صحنه‌ي هر كدام از اين افزونه‌ها كه زياده روي در تعداد آن‌ها گاها باعث كرش هم مي‌شود. بنابراين همان يك مورد كافي است.

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



پس از انجام اين مراحل يكبار بايد سيستم reboot شود و اكنون همه چيز مثل قبل خواهد شد!


نكته:
اگر مسير ريشه مخزن‌هاي جديد با مسير آن‌ها در سيستم قبلي متفاوت است، هنگام commit كارهاي خود با خطاي زير متوقف خواهيد شد:
Commit failed (details follow): Unable to open an ra_local session to URL
Unable to open repository 'file:///C:/Repositories/tracking/trunk'




اشكالي ندارد! براي رفع آن بايد از گزينه‌ي relocate مربوط به TortoiseSVN استفاده كرد.
بر روي پوشه كاري پروژه خود كليك راست كرده، انتخاب گزينه‌ي TortoiseSVN و سپس انتخاب گزينه‌ي Relocate آن بايد صورت گيرد. در اينجا مي‌توان مسير جديد ريشه اصلي مخزن را در سيستم جديد معرفي كرد.



۱۳۸۸/۰۹/۱۷

فقط به خاطر يك نيم فاصله!


نسخه‌ي 64 بيتي ويندوز 7 را نصب كرده‌ام و اولين مشكل، نبود صفحه كليد مطابق استاندارد 2901 براي نسخه‌هاي 64 بيتي ويندوز است. پروژه وب فارسي دانشگاه صنعتي شريف، سال‌ها قبل فقط يك نسخه‌ي 32 بيتي از آن را تهيه كرده و نسخه‌هاي 64 بيتي موجود، مطابق استاندارد 9147 هستند و من به دلايل ذيل حاضر به استفاده از آن نيستم!
  1. در استاندارد 9147 ، جاي ژ و پ مطابق صفحه كليدي كه در بازار ايران فروخته مي‌شود نيست (و بايد به همه پاسخگو باشيد كه چرا اينطوري است).
  2. ي و ك در آن اصلاح شده و ديگر عربي نيست كه چقدر هم خوب، اما من تعداد زيادي برنامه و همچنين تعداد قابل توجهي فايل word دارم كه مطابق استاندارد 2901 تهيه شده‌اند. مشكلات ي و ك فارسي و عربي را هم در اينجا ذكر كرده‌ام و به دنبال باگ‌هاي جديد در برنامه‌ها نمي‌گردم.
  3. با ي و ك فارسي اگر در گوگل جستجو كنيد تعداد پاسخ‌هاي مرتبط يافت شده بسيار بسيار كمتر از حالتي خواهد بود كه با ي و ك عربي جستجو كنيد.
  4. در يك سازمان بايد رويه‌ا‌ي واحد در اين مورد برقرار باشد. يا همه بايد از 2901 استفاده كنند و يا همه از 9147.

نسخه‌ي كامل استاندارد 9147 را از سايت آقاي اخگري مي‌توانيد دريافت نمائيد:

به همين دلايل خصوصا قسمت دوم (هر چند ممكن است با آن موافق نباشيد)، نياز به صفحه كليد مطابق استاندارد 2901 نسخه‌ي 64 بيتي داشتم.

براي تهيه صفحه كليد فارسي از برنامه Microsoft Keyboard Layout Creator استفاده مي‌شود كه نسخه‌ي 1.4 آن‌را از آدرس زير مي‌توانيد دريافت نمائيد. اين نسخه قابليت توليد فايل‌هاي dll مرتبط 64 بيتي را هم دارد:


يكي از قابليت‌هاي اين برنامه بارگذاري صفحه كليد فارسي جاري سيستم است:



صفحه كليد استاندارد 2901 پروژه وب فارسي را اگر با آن باز كرده و سپس از منوي Project‌ گزينه‌ي Build DLL and setup package را انتخاب نمائيد، با خطاي زير متوقف خواهيد شد:
ERROR: 'VK_SPACE' in Shift State 'Shift' must be made up of white space character(s), but is defined as '‌' (U+200c) instead.

كه دقيقا مربوطه به اين سطر در تعاريف صفحه كليد است (صفحه كليد را مي‌شود به صورت فايلي با پسوند klc هم save as كرد):


39 SPACE 0 0020 200c 0020 -1 // SPACE, ZERO WIDTH NON-JOINER, SPACE, <none>

مفاهيم اين ستون‌ها هم به شرح زير هستند:
0 //Column 4
1 //Column 5 : Shft
2 //Column 6 : Ctrl
3 //Column 7 : Shft Ctrl

يعني جهت نمايش نيم فاصله حاصل از تركيب shift space مطابق استاندارد تايپ ايران، بجاي 0x0020 يا همان فاصله، از 0x200C استفاده شده است (مطابق استاندارد تايپ ايران بايد نوشت "مي‌روم" و نه "مي روم". به نيم فاصله و فاصله دقت بفرمائيد).
اما اين برنامه‌ي محترم دقيقا همين مورد را غلط گرفته و فايل dll نهايي را توليد نمي‌كند (مطابق خطايي كه ذكر شد).
برنامه‌ي Microsoft Keyboard Layout Creator هم با دات نت فريم ورك نوشته شده است. اگر كمي با reflector به آناليز آن بپردازيم به كلاس Accept و متد زير خواهيم رسيد:
private bool VerifySpaceBarIntegrity(ShiftState ss, bool fMustBeDefined)
در اين متد جايي كه خطاي ذكر شده صادر مي‌شود، مربوط به چند سطر زير است:

if (!Utilities.IsSpacing(ss.Characters))
{
this.WriteErrorToLogFile("SpaceKeyNeedsWhiteSpaceCharacters", new string[] { "VK_" + Utilities.VkStringOfIvk(ss.VK), this.m_stStateLabel[ss.State], ss.Characters, Utilities.FromCharacterToUPlusForm(ss.Characters) });
flag = false; /*اينجا بايد اصلاح شود!*/
}
خوب! به نظر شما ايرادي دارد كه اين flag هميشه true باشد؟! براي همين منظور، فايل MSKLC.exe را پچ كرده‌ام كه از آدرس زير قابل دريافت است:

با استفاده از اين نسخه (ابتدا برنامه اصلي را نصب كرده و سپس فايل exe را جايگزين نمائيد)، به راحتي مي‌توان نسخه‌ي استاندارد و اصلي 2901 را بارگذاري و مجددا كامپايل كرد (بدون توقف كامپايل به خاطر فقط يك نيم فاصله‌ي غيرمعتبر از ديدگاه نويسندگان اصلي برنامه). به اين صورت فايل‌هاي 64 بيتي لازم هم توليد مي‌شوند كه حاصل نهايي را از آدرس زير مي‌توانيد دريافت نمائيد:



اين فايل‌ها دقيقا بر مبناي همان فايل‌هاي پروژه وب فارسي استاندارد 2901 هستند؛ با اين تفاوت كه نسخه‌‌هاي غير 32 بيتي هم در آن لحاظ شده‌اند.


نصب اين dll ها هم از ويندوز ويستا به بعد داستان خودش را پيدا كرده؛ ابتدا بايد take ownership شود، سپس مي‌توان فايل اصلي را به سادگي جايگزين كرد و سپس reboot .
براي اين منظور ابتدا به پوشه‌ي system32 ويندوز مراجعه كرده و فايل KBDFA.DLL را پيدا كنيد.
در ادامه به پنجره خواص آن (كليك راست و انتخاب properties) مراجعه و برگه‌ي Security آن‌را انتخاب كنيد.
در اين قسمت بر روي دكمه‌ي Advanced كليك نمائيد.
در صفحه‌ي باز شده به برگه‌ي Owner مراجعه كنيد.
در اين قسمت بر روي دكمه‌ي Edit كليك نموده و كاربر خودتان را اضافه نمائيد.
پس از طي اين مرحله (يا همان take ownership) به برگه security مراجعه كرده و به كاربر خودتان دسترسي full control بدهيد.
اكنون مجوز تغيير اين فايل را بدون هيچ مشكلي خواهيد يافت.
در پايان reboot را فراموش نكنيد.

راه دوم:
يا برنامه نصاب حاصل از برنامه‌ي Microsoft Keyboard Layout Creator، مدخل جديدي را به صفحه كليدهاي قابل انتخاب ويندوز در كنترل پنل اضافه مي‌كند كه نيازي به reboot ندارد.


۱۳۸۸/۰۹/۱۵

چند خبر كوتاه در مورد jQuery


  • نگارش جديد جي‌كوئري (jQuery 1.4 Alpha 1) منتشر شد : + و +
  • انتخاب jQuery به عنوان بهترين كتابخانه‌ي سورس باز سال 2009 از طرف مجله‌ي دات نت: +
  • بهترين افزونه‌هاي jQuery سال 2009 :+

۱۳۸۸/۰۹/۱۴

چه زمان‌هايي ممكن است Page_Load يك صفحه ASP.Net دوبار اجرا شود؟


سؤال مربوط به حالت نخ نماي Page.IsPostBack نيست. مربوط به حالتي است كه دقيقا در اولين بار مشاهده‌ي عادي يك صفحه، Page_Load دوبار يا بيشتر (!) اجرا مي‌شود.

الف) برنامه‌ي ASP.Net 1.x خود را به نگارش‌هاي 2+ ارتقاء داده‌ايد.
در اين حالت هر چند VS.Net پيغام تبديل با موفقيت يك پروژه‌ي قديمي را به شما ارائه خواهد داد اما يك سري موارد را پس از تبديل، بايد اصلاح كرد.
پروژه‌هاي قديمي ASP.Net در روال InitializeComponent خود سطر زير را همانند يك پروژه WinForm و امثال آن براي معرفي روال رخداد گردان Page_Load دارند.

this.Load += new System.EventHandler(this.Page_Load);

اما در پروژه‌هاي ASP.Net 2.0 به بعد ديگر از اين روال خبري نيست. پس در اين پروژه‌ها كامپايلر چگونه متوجه خواهد شد كه Page_Load واقعا يك روال رخ داد گردان است و نه يك روال معمولي؟ در پروژه‌هاي جديد VS.Net ، خاصيت AutoEventWireup صفحه به true تنظيم شده و ديگر نيازي به معرفي صريح روال‌هاي رخ داد گرداني مانند Page_Load و يا Page_Init نبوده و تشخيص آن‌ها به صورت خودكار انجام مي‌شود.

<% @Page AutoEventWireup="true" %>
بر اين اساس با انتقال يك پروژه قديمي به VS.Net جديد، هم AutoEventWireup=true را خواهيم داشت و هم سطرهاي موجود در متد قديمي InitializeComponent از پروژه حذف نشده‌اند. بنابراين متد Page_Load در دو نقطه، يكبار به صورت خودكار (متد Page_Load بر اساس نام آن با توجه به AutoEventWireup=true تشخيص داده شده و اجرا مي‌شود) و يكبار هم بر اساس تعريف دستي موجود فراخواني مي‌شود.
براي حل اين مشكل و سازگاري بهتر با نگارش‌هاي جديدتر، سطر تعريف دستي روال رخ داد گردان متد Page_Load را حذف كنيد.
لازم به ذكر است كه اين سيم كشي خودكار تنها براي متدهاي زير انجام خواهد شد و نسبت به حذف ساير موارد موجود اقدام نكنيد!

Page_PreInit
Page_Init
Page_InitComplete
Page_PreLoad
Page_Load
Page_LoadComplete
Page_DataBind
Page_SaveStateComplete
Page_PreRender
Page_PreRenderComplete
Page_Unload
Page_Error
Page_AbortTransaction
Page_CommitTransaction


ب) وجود هر نوع دكمه‌ي تصويري يا كلا تصويري با ويژگي src مقدار دهي نشده در صفحه
مرورگر IE با اين مساله مشكلي ندارد. اما فايرفاكس‌هاي جديد اگر به src مقدار دهي نشده‌ي تصويري برخورد كنند دقيقا آدرس جاري صفحه را بجاي مقدار src قرار داده و مجددا صفحه را درخواست مي‌كنند (و البته اين مورد ارتباط مستقيمي به ASP.Net يا PHP و امثال آن ندارد و يك مساله‌ي عمومي است). اين مورد سبب خواهد شد كه Page_Load صفحه، نه فقط دوبار بلكه به تعداد بار src خالي تصاويري كه در صفحه وجود دارند، بر اساس درخواست‌هاي مجدد فايرفاكس از سرور اجرا شود. (مرورگر IE بجاي فراخواني آدرس صفحه جاري، يك null/ را به انتهاي آدرس جاري اضافه كرده و آن‌را فراخواني مي‌كند. بنابراين سبب اجراي مجدد هيچ روالي نخواهد شد.)


مآخذ:
Inside AutoEventWireup
How Firefox Handles Empty SRC tags