Globalization در ASP.NET MVC
متن نشانی زیر را مطالعه کنید
http://geekswithblogs.net/shaunxu/archive/2012/09/04/localization-in-asp.net-mvc-ndash-upgraded.aspx
عدم اجرای پروژه در VS 2012
پروژه رو توی ویژوال استدیو 2012 وقتی Debug میکنم اجرا نمیشه، هر بار هم روی پورت 18600 اجرا میشه، تصویر خطا :
تعریف بازسازی کد
- Refactoring بازسازی است، نه بازنویسی
- بازسازی مربوط به ساختار درونی یک نرم افزار است؛ نه رفتاری که مشتریان از یک نرم افزار یا کامپوننت انتظار دارند
- حاصل بازسازی باید سهولت درک کد و سادگی نگهداری آن باشد
چرا کد را بازسازی کنیم؟
1- طراحی نرم افزار را بهبود میبخشد
2- درک کد را آسانتر میکند
یکی از مزیتهای کد خوب، درک آسان آن توسط سایر افراد است. هنگام بازسازی کد، با کدی مواجه هستیم که کار میکند، ولی نظم و طراحی درستی ندارد. درک آسان کد، یکی از کلیدیترین نکات جهت سهولت نگهداری یک نرم افزار است.
3- به یافتن خطاها کمک میکند
4- سرعت توسعه را بالا میبرد
چه زمانی کد را بازسازی کنیم؟
- زمانیکه امکان جدیدی اضافه می شود
- زمانیکه باگ یا اشکالی، رفع می شود
- زمان بازبینی کد یا Code review
میدانید که در پروژه و نرم افزارهایی که توسعه داده میشوند بعضی مواقع مشاهده میکنیم قسمتی از برنامه نیاز به زمان یا پردازش بیشتری دارد تا عملیات خود را به اتمام برساند و رابط کاربری (User Interface) برنامه در این حین منتظر میماند و یا به اصطلاح (Freeze) میشود تا یک پردازش طولانی به اتمام برسد و بعد رابط کاربری به کار خود ادامه میدهد و بعضی مواقع پنجره Windows explorer is not responding را مشاهده کردهاید که با کلیک بر روی Close the program از آن گذر میکنیم. در حالی که برنامه ما باید حالت Responsive داشته باشد و نباید برنامه با یکچنین مواردی روبه رو شود.
ساختمان Thread :
تمامی اشیاء (Objects) در این مدل به دو گروه تقسیم بندی میشوند:
STA شامل فقط یک Thread میباشد و تمامی اشیاء در این ساختمان فقط میتوانند متدی را که در این Thread صدا زده میشود دریافت کنند؛ یا به عبارتی دیگر هنگامیکه شیء به Thread ای متصل میشود دیگر شما قادر نخواهید بود اشیاء UI را به صورت مستقیم و یا از طریق Threadهای دیگر تغییر دهید. لازم به ذکر است WPF از مدل STA پشتیبانی میکند که شامل نکات زیر میباشد:
1. یک Thread در کل برنامه اجرا میشود و شامل همه Objectهای WPF میباشد.
2. عناصر یا المانهای WPF، قابلیت تنظیم Thread Affinity را دارند. منظور این میباشدکه Threadها نمیتوانند با یکدیگر ارتباط برقرار کنند.
3. اشیاء WPF که قابلیت Thread Affinityرا دارند، از یک Object Dispatcher مشتق میشوند.
4. اشیاء WPF متعلق به Thread ای میباشند که توسط آن ایجاد شده است و Thread دیگر قادر به دسترسی مستقیم به این اشیاء نمیباشد.
ساختمان Multi-Threaded Apartment (MTA) :
MTA شامل یک یا چندین Thread میباشد. تمامی اشیاء در این مدل میتوانند از هر Thread ای فراخوانی شوند. در حقیقت رجیسترهای CPU و Ram که در اختیار برنامه قرار داده شده تکه تکه میشوند و برنامه ما تعداد Threadهای مورد نظر را اجرا میکند و یکی از راه حلهای بر طرف کردن اینکه رابط کاربری ما در حالت انتظار باقی نماند استفاده از پردازش کارها بصورت غیر همزمان (Asynchronous) میباشد که در اصطلاح Multithreading نامیده میشود.
WPF Dispatcher :
WPF از مدل STA پشتیبانی میکند. زمانیکه برنامه WPF اجرا میشود، به طور خودکار یک Dispatcher Object ساخته میشود و متد Run صدا زده میشود و از آن برای آماده سازی صف پیامها استفاده میشود که مدیریت یک صف از کارها بر عهده آن است و کارهای UI را در یک صف FIFO اجرا میکند. WPF یک Dispatcher را برای UI Thread ایجاد میکند. بنابراین شما نمیتوانید یک dispatcher دیگر برای آن تعریف کنید.
نکته : دیاگرام زیر نمایش میهد که تمامی اشیاء WPF
از DispatcherObject مشتق شدهاند.
نکته : زمانیکه برنامه WPF اجرا میشود دو Thread ساخته میشود:
1. UI Thread (Main Thread)
2. Render Thread
UI Thread : مسئولیت تمامی ورودیهای کاربر، handle events, paints screen و اجرای کدهای برنامه را بر عهده دارد.
Render Thread : در Background اجرا میشود و برای Render صفحه نمایش WPF استفاده میشود.
نکته: همانطور که آشنا شدیم WPF نمیتواند UI Thread را از طریق یک Thread دیگر به روز رسانی کند و یا به عبارتی دیگر یک Thread نمیتواند بصورت مستقیم به اشیایی که توسط Thread دیگر ایجاد شده، دسترسی داشته باشد.
Dispatcher برای این کار دو متد را در اختیار ما قرار میدهد :
متد Invoke : یک Action یا Delegate را میگیرد و متد آنرا به صورت همزمان اجرا میکند. این مورد به این معنا است که تا زمانی که اجرای متد کامل نگردد، عملیاتی صورت نخواهد گرفت و یا به عبارتی دیگر فراخوان را تا زمانیکه زمانبندی به پایان برسد، در حالت مسدود نگهداری خواهد کرد.
مثال :
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Task.Factory.StartNew(() => { InvokeMethodExample(); }); } private void InvokeMethodExample() { Thread.Sleep(2000); Dispatcher.Invoke(() => { btn1.Content = "By Invoke"; }); } }
مثال :
public MainWindow() { InitializeComponent(); Task.Factory.StartNew(() => { BeginInvokeExample(); }); } private void BeginInvokeExample() { DispatcherOperation op = Dispatcher.BeginInvoke((Action)(() => { btn1.Content = "By BeginInvoke"; })); }
با کلیدهای ترکیبی Ctrl + Tab و Ctrl + Shift + Tab میتوانید بین پنجرههای Active جابجا شوید. با کلیدهای جهتنما هم میتوانید به بقیه پنجرهها از جمله Properties منتقل شوید. ناگفته نماند که این امکان در اکثر قسمتهای ویندوز و نرم افزارهایی مثل کروم و حتی SSMS نیز وجود دارد.
به طور کلی کلید شیفت برای دو کاربرد «برگشت از عملیات» و «انتخاب» استفاده میشود.
برای اینکه جستجویی را فیلتر کنید، میتوانید از الگوهای زیر استفاده کنید:
f جستجو در فایلها؛ r برای فایلهای اخیر؛ t جستجو در تایپها (مثل کلاس)؛ m برای جستجو در اعضا (متدها، پراپرتیها و Eventها).
برای مثال: اگر بنویسید t Controller، فقط Typeها را جستوجو میکند و نمایش میدهد.
۳) کلیپبورد چرخشی : «Ctrl + Shift + V»
ویژوال استودیو تا ۲۰ مقدار کپیشده قبلی را در حافظه خود ذخیره نگه میدارد. با دکمههای ترکیبی گفته شده میتوان از مقادیر قبلی کلیپبورد هم استفاده کرد. این قابلیت از ویژوال استودیو ۲۰۰۳ وجود داشته است.
۴) اجرای سریع : « Ctrl + Q »
برای دسترسی سریع به تنظیمات ویژوال استودیو (مثل فونت) یا بازکردن پنجرههایی که کلید میانبر استاندارد برای آنها تعریف نشدهاست، میتوان از این منو استفاده کرد.
حتی میتوان @nuget را نوشت، سپس اسم پکیج موردنظر نوشته میشود. با انجام این کار Manage NuGet Packages باز میشود و پکیجهای مرتبط نمایش داده میشوند.
۵) پیدا کردن ابتدا و انتهای براکت: « Ctrl + ] »
کاربرد این روش در هنگامی است با Legacy codeی مواجه میشوید که بلوکهای بزرگی از کد را دارد که فهم ابتدا و انتهای آن سخت است. با زدن این کلیدها میتوانید به محلی که براکت باز و بسته مربوطه هست، منتقل شوید.
۶) رفتن به محل کرسر قبلی: « Ctrl + - »
با زدن کلیکهای کنترل و Dash میتوانید به جاهایی که قبلا کرسر بوده است، بروید. البته اگر Shift را هم بگیرید، برعکس این کار انجام میشود.
منابع:
این افزونه با استفاده از ابزار Visual Studio Tools for Office که به VSTO مشهور شده است، تهیه شد. در بسته به روز رسانی سیستم که در ذیل (معرفی افزونه) نیز معرفی شد نگارش sp1 vsto3.0 آن به صورت خودکار نصب خواهد شد.
برای ایجاد این پروژه در VS.Net 2008 ، تنها کافی است یک پروژه جدید Word add-in را آغاز نمائیم. (شکل زیر)
قبل از ادامه بحث، بهتر است در مورد بانک اطلاعاتی مورد استفاده نیز توضیح داده شود. در اینجا از SQLite استفاده شد. (بسیار سبک، کم حجم و سریع است و اساسا یک کاربر نهایی برای تنظیمات آن نیازی نیست اطلاعاتی داشته باشد). بسته به روز رسانی سیستم (در مطلب قبلی)، این مورد را نیز به صورت خودکار نصب خواهد کرد (در GAC باید نصب شود وگرنه افزونه قادر به یافتن آن نخواهد شد).
برای ایجاد این بانک اطلاعاتی، از افزونه SQLite manager برای فایرفاکس استفاده شد. (این افزونه رایگان شما را از هر ابزار جانبی برای مدیریت یک بانک اطلاعاتی SQLite بینیاز میکند)
برای مثال فایل ErrorsBank.sqlite برنامه افزونه فارسی به پارسی را توسط افزونه SQLite manager فایرفاکس باز کنید (این فایل را در محل نصب افزونه میتوانید پیدا کنید). در اینجا میتوان جداول جدید را ایجاد کرد، کوئریهای دلخواه را اجرا نمود و یا اطلاعات را مرور کرده، حذف یا ویرایش کرد (شکل زیر).
و خوشبختانه این بانک اطلاعاتی و محصور کنندههای آن با اطلاعات یونیکد فارسی هیچ مشکلی ندارند و برای کارهایی با وسعت کم و تعداد رکورد پائین یکی از بهترین انتخابها بهشمار میروند.
نحوه استفاده از SQLite نیز در دات نت بسیار ساده است. اگر با ADO.Net کار کرده باشید، پس از افزودن ارجاعی از اسمبلی System.Data.SQLite.DLL به پروژه و معرفی فضای نام آن به پروژه، تنها کافی است در کدهای قبلی خود برای مثال SqlConnection را به SQLiteConnectionتغییر دهید و امثال آن. یعنی دانش ADO.Net شما در اینجا نیز کاملا قابل استفاده خواهد بود و نیازی نیست مدتی را صرف آشنا شدن با کلاسها و مفاهیم جدید نمائید (البته این تنها زمانی معنا خواهد داشت که به ویزاردها عادت نکرده باشید و کارهای خود را با کد نویسی انجام داده باشید).
تنها یک نکته را باید بهخاطر داشت و آن هم مربوط است به ساز و کار درونی SQLite . هنگام انجام عملیات update یا insert حتما از transaction استفاده کنید تا سرعت کوئریهای شما در SQLite به نحو شگفت انگیزی افزایش یابد. مثالی در این مورد را در فایل chm راهنمای SQLite.NET میتوانید پیدا کنید.
مطلب دیگری که پیش از پرداختن به کد نویسی افزونه باید با آن آشنا شویم، مفهوم smart tags در مجموعه آفیس است که در این پروژه از آن استفاده گردید.
smart tags در مجموعه آفیس برچسبهایی هستند که به صورت خودکار توسط یکی از محصولات آفیس مثلا ورد یا اکسل و امثال آن، پس از تشخیص یک کلمه خاص ایجاد میشوند و میتوان اعمالی را به این برچسب ایجاد شده انتساب داد. برای مثال در اینجا امکان جایگزین کردن کلمه فارسی با معادل پارسی در نظر گرفته شد.
ویدیویی در مورد نحوه ایجاد اسمارت تگها در VS.Net و یا مثالی پیشرفتهتر در مورد تشخیص دمای فارنهایت در یک متن و ایجاد smart tag مخصوص به آن برای تبدیل به سلسیوس. (از regular expressions جهت یافتن یک الگو در متن استفاده شده است)
در این پروژه، حدود 3800 واژه فارسی به یک smart tag انتساب داده میشود (در روال استاندارد ThisAddIn_Startup). سپس در هنگام نمایش آن، معادل پارسی کلمه نیز به منوی باز شده افزوده گشته و در روال رخداد کلیک آن، تعویض کلمه تشخیص داده شده با واژه پیدا شده صورت خواهد گرفت.
در ادامه فرض بر این است که یک پروژه جدید word add-in را در VS.Net ایجاد کردهاید و همچنین ارجاعی را به فایل System.Data.SQLite.DLL افزودهاید.
using System;
using System.Diagnostics;
using Microsoft.Office.Tools.Word;
using Action = Microsoft.Office.Tools.Word.Action;
private SmartTag _st;
private void init()
{
try
{
//Enable Smart Tags in Word
if (!Application.Options.LabelSmartTags)
{
//ممکن است اسمارت تگها در ورد غیرفعال باشند. به این صورت میشود آنها را فعال کرد
Application.Options.LabelSmartTags = true;
}
_st = new SmartTag(@"www.microsoft.com/Demo#FarsiSmartTag", @"فارسی به پارسی");
//دریافت واژههای فارسی از دیتابیس و افزودن خودکار آنها به اسمارت تگها
if (!DBhelper.AddSmartTagItems(_st, "select distinct farsi from tblFarsiToParsi")) return;
Action stActions = new Action("تبدیل");//تعریف یک اکشن جدید
stActions.Click += stActions_Click;//انتساب روالهای رخداد گردان
stActions.BeforeCaptionShow += stActions_BeforeCaptionShow;
_st.Actions = new[] { stActions };
VstoSmartTags.Add(_st);//افزودن اسمارت تگ به مجموعه
}
catch (Exception ex)
{
EventLog.WriteEntry("FarsiToParsi", ex.ToString(), EventLogEntryType.Error, 7);
}
}
private void ThisAddIn_Startup(object sender, EventArgs e)
{
init();
}
static void stActions_BeforeCaptionShow(object sender, ActionEventArgs e)
{
try
{
Action clickedAction = sender as Action;
if (clickedAction != null)
{
string parsi = DBhelper.FindParsi(e.Text);//معادل پارسی از دیتابیس دریافت میشود
clickedAction.Caption = (parsi == string.Empty ? e.Text : parsi);
}
}
catch (Exception ex)
{
EventLog.WriteEntry("FarsiToParsi", ex.ToString(), EventLogEntryType.Error, 7);
}
}
static void stActions_Click(object sender, ActionEventArgs e)
{
try
{
Action clickedAction = sender as Action;
if (clickedAction != null)
{
e.Range.Text = clickedAction.Caption;//جایگزینی متن موجود با عنوانی که پیشتر پارسی شده است
}
}
catch (Exception ex)
{
EventLog.WriteEntry("FarsiToParsi", ex.ToString(), EventLogEntryType.Error, 7);
}
}
همچنین باید دقت داشت که اگر متغیری در سطح کلاس تعریف نشود به احتمال زیاد تا دقایقی بعد توسط garbage collector به دیار باقی خواهد شتافت (تعریف st_ در اینجا). اینجاست که شاید ساعتها وقت صرف کنید که چرا روالهای رخداد گردان دیگر اجرا نمیشوند. چرا افزونه دیگر کار نمیکند.
همین! کل سورس این add-in منهای بحث دریافت اطلاعات از دیتابیس همین بود! وظیفهی تشخیص کلمات معرفی شده به ms-word بهعهدهی خود آن است و اینکار را نیز بهخوبی انجام میدهد. در گذشتههای نچندان دور ایجاد یک افزونه برای word واقعا مشکل بود که با این روش بسیاری از موانع برطرف شده است.
کلاس DBHelper که کار دریافت اطلاعات واژهها را از دیتابیس SQLite انجام میدهد به شرح زیر است:
using System;
using System.Data.SQLite;
using System.Diagnostics;
using System.Reflection;
using Microsoft.Office.Tools.Word;
namespace Farsi2Parsi
{
class DBhelper
{
#region Methods (2)
// Public Methods (2)
public static bool AddSmartTagItems(SmartTag st, string strSQL)
{
SQLiteDataReader myReader = null;
SQLiteCommand sqlCmd = null;
bool ret = false;
try
{
SQLiteConnection sqlCon = new SQLiteConnection
{
ConnectionString = "Data Source=" + ConStr.ConnectionString
};
sqlCon.Open();
sqlCmd = new SQLiteCommand(strSQL, sqlCon);
myReader = sqlCmd.ExecuteReader();
if (myReader != null)
while (myReader.Read())
{
if (myReader.GetValue(0) != DBNull.Value)
st.Terms.Add(myReader.GetValue(0).ToString());
}
ret = true;
}
catch (Exception ex)
{
EventLog.WriteEntry("FarsiToParsi", ex + "\n" + Environment.CurrentDirectory + "\n" +
Assembly.GetExecutingAssembly().Location, EventLogEntryType.Error, 7);
}
finally
{
if (myReader != null)
myReader.Close();
if (sqlCmd != null)
sqlCmd.Connection.Close();
}
return ret;
}
public static string FindParsi(string farsi)
{
SQLiteDataReader myReader = null;
SQLiteCommand sqlCmd = null;
string ret = string.Empty;
string strSQL = "select parsi from tblFarsiToParsi where farsi='" + farsi.Replace("'", "''") + "'";
try
{
SQLiteConnection sqlCon = new SQLiteConnection
{
ConnectionString = "Data Source=" + ConStr.ConnectionString
};
sqlCon.Open();
sqlCmd = new SQLiteCommand(strSQL, sqlCon);
myReader = sqlCmd.ExecuteReader();
if (myReader != null)
{
myReader.Read(); //اولین مورد کافی است
if (myReader.GetValue(0) != DBNull.Value)
ret = myReader.GetValue(0).ToString();
}
}
catch (Exception ex)
{
EventLog.WriteEntry("FarsiToParsi", ex + "\n" + Environment.CurrentDirectory + "\n" +
Assembly.GetExecutingAssembly().Location, EventLogEntryType.Error, 8);
}
finally
{
if (myReader != null)
myReader.Close();
if (sqlCmd != null)
sqlCmd.Connection.Close();
}
return ret;
}
#endregion Methods
}
}
هنگام نصب برنامه، مسیر پوشه نصب در رجیستری ویندوز توسط نصاب نوشته خواهد شد. از همین مورد برای ایجاد رشته اتصالی به دیتابیس استفاده گردید.
class ConStr
{
public static string ConnectionString
{
get
{
return Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\\FarsiToParsi").GetValue("folder") + "\\ErrorsBank.sqlite";
}
}
}
نصاب برنامه با استفاده از NSIS ایجاد شده که در روزی دیگر دربارهی آن توضیح خواهم داد.
اگر قصد داشته باشید از روشهای متداول استفاده کنید، مشاهده ویدیوی زیر توصیه میشود:
http://msdn.microsoft.com/en-us/office/bb851702.aspx
برای توزیع این نوع افزونهها علاوه بر دات نت فریم ورک، به چهار به روز رسانی دیگر نیز نیاز خواهد بود:
به روز رسانی نصاب ویندوز (که احتمالا نصب هست)
WindowsInstaller-KB893803-v2-x86.exe
Microsoft Office System Update: Redistributable Primary Interop Assemblies :
o2007pia.msi
نصب vsto و همچنین sp1 آن
vstor30.exe
vstor30sp1-KB949258-x86.exe
این موارد را من در بسته به روز رسانی سیستم قرار دادهام که به صورت خودکار و یکی پس از دیگری اجرا و نصب خواهند شد.
پس از آن با کلیک بر روی فایلی با پسوند vsto که در پوشه build برنامه موجود است، میتوان افزونه را نصب کرد (click once installation).
سایر اطلاعات در مورد پروژههای VSTO را میتوان از طریق وبلاگ رسمی آنها دنبال کرد:
http://blogs.msdn.com/vsto/
ایدههای دیگری را هم در همین رابطه میتوان پیاده سازی کرد. برای مثال درست کردن یک افزونه برای بررسی آئین نگارش فارسی در متون word. دقیقا با همین روش قابل پیاده سازی است و یا ایجاد غلط یاب بهتری نسبت به آنچه که هم اکنون برای آفیس 2003 توسط مایکروسافت ارائه شده است (این غلط یاب با صفحه کلید استاندارد تایپ ایران همخوانی ندارد، به همین جهت با استقبال نیز مواجه نشد).