۱۳۸۹/۰۵/۱۶

يكسان سازي "ي" و "ك" دريافتي در حين استفاده از WCF RIA Services


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

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

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

در مورد ‌مقدمات WCF RIA Services كه درSilverlight و ASP.NET كاربرد دارد مي‌توانيد به اين مطلب مراجعه كنيد: +

جهت تكميل اين بحث متدي تهيه شده كه كار يكسان سازي ي و ك دريافتي از كاربر را حين ثبت توسط امكانات WCF RIA Services انجام مي‌دهد (دقيقا پيش از فراخواني متد SubmitChanges بايد بكارگرفته شود):


namespace SilverlightTests.RiaYeKe
{
public static class PersianHelper
{
public static string ApplyUnifiedYeKe(this string data)
{
if (string.IsNullOrEmpty(data)) return data;
return data.Replace("ی", "ي").Replace("ک", "ك");
}
}
}

using System.Linq;
using System.Windows.Controls;
using System.Reflection;
using System.ServiceModel.DomainServices.Client;

namespace SilverlightTests.RiaYeKe
{
public class RIAHelper
{
/// <summary>
/// يك دست سازي ي و ك در عبارات ثبت شده در بانك اطلاعاتي پيش از ورود به آن
/// اين متد بايد پيش از فراخواني متد
/// SubmitChanges
/// استفاده شود
/// </summary>
/// <param name="dds"></param>
public static void ApplyCorrectYeKe(DomainDataSource dds)
{
if (dds == null)
return;

if (dds.DataView.TotalItemCount <= 0)
return;

//پيدا كردن موجوديت‌هاي تغيير كرده
var changedEntities = dds.DomainContext.EntityContainer.GetChanges().Where(
c => c.EntityState == EntityState.Modified ||
c.EntityState == EntityState.New);

foreach (var entity in changedEntities)
{
//يافتن خواص اين موجوديت‌ها
var propertyInfos = entity.GetType().GetProperties(
BindingFlags.Public | BindingFlags.Instance
);

foreach (var propertyInfo in propertyInfos)
{
//اگر اين خاصيت رشته‌اي است ي و ك آن را استاندارد كن
if (propertyInfo.PropertyType != typeof (string)) continue;
var propName = propertyInfo.Name;
var val = new PropertyReflector().GetValue(entity, propName);
if (val == null) continue;
new PropertyReflector().SetValue(
entity,
propName,
val.ToString().ApplyUnifiedYeKe());
}
}
}
}
}

توضيحات:
از آنجائيكه حين فراخواني متد SubmitChanges فقط موجوديت‌هاي تغيير كرده جهت ثبت ارسال مي‌شوند، ابتدا اين موارد يافت شده و سپس خواص عمومي تك تك اين اشياء توسط عمليات Reflection بررسي مي‌گردند. اگر خاصيت مورد بررسي از نوع رشته‌اي بود، يكبار اين يك دست سازي اطلاعات ي و ك دريافتي صورت خواهد گرفت (و از آنجائيكه اين تعداد هميشه محدود است عمليات Reflection سربار خاصي نخواهد داشت).
اگر در كدهاي خود از DomainDataSource استفاده نمي‌كنيد باز هم تفاوتي نمي‌كند. متد ApplyCorrectYeKe را از قسمت DomainContext.EntityContainer به بعد دنبال كنيد.
اكنون تنها مورد باقيمانده بحث جستجو است كه با اعمال متد ApplyUnifiedYeKe به مقدار ورودي متد جستجوي خود، مشكل حل خواهد شد.

كلاس PropertyReflector بكارگرفته شده هم از اينجا به عاريت گرفته شد.
دريافت كدهاي اين بحث