WPF لرجل الإنترنت قصة من الألم واليأس والتعلّم
حسناً، حسناً، لقد بالغت في الدراما على هذا الأمر: (كما لاحظتم من الوظـال مـن الوظـف مـن الوظـف بدأت العمل في بعض الاشياء التي تقع خارج منطقة راحتي . )كك(التي تعمل من أجل فصل مسمّى @ ROBRTAGRyالمشروع الأول الذي نعمل عليه هو موقع بيع الصور... تعلمون نوع من مثل Getty الصور / Smugmug / Flickr باستثناء مبيعات المصورين والزبائن المباشرة. مطور كامل الوقت الكامل (حتى الآن!) لقد تم تكليفي ببناء الغالبية العظمى من التطبيقات (سواء كانت الويب، والحواسيب المكتبية، وما إلى ذلك) التي نحتاجها للعمل التجاري للعمل.
من الواضح أن أحد أكثر الأجزاء أهمية بالنسبة لموقع التجارة الإلكترونية هو ما يمكن بيعه! في حالتنا هذا هو مخزون من الصور ذات الجودة العالية التي التقطها المصورون المحترفون في جميع أنحاء العالم. والسؤال الأول: كيف نحصل على هذه الصور على الموقع، وكيف نسمح للمصورين بإضافة معلومات إلى صورهم ليتمكن الناس الذين يريدون شرائها من العثور عليها؟ حسناً، هذه هي المشكلة الأولى التي طُلب مني حلها!
وعند العمل على المتطلبات، سرعان ما أصبح من الواضح أن هذا لابد أن يكون تطبيقاً منضدياً، وكان من الضروري أن يسمح بالعمليات على صور فوتوغرافية متعددة الميجابايت، وكان من الضروري أن يسمح لـ "التدوين" بالتوقف عن العمل. خاصة أثناء التحميل الأولي، هناك 10.100 آلاف من الصور التي يتم العمل عليها... وإرغامها على أن تكون على الإنترنت تضيف تخلفاً سيئاً وتجعل المهمة ألماً في المؤخرة لتكتمل. وقبل كل شيء، كان من الضروري أن تكون موثوقة!
الآن، في رأسي dev هذا أدى إلى عدد من القرارات حول الميزات التي يحتاج التطبيق لدعمها:
- UI بديهي، مستجيب، المستخدمون ليسوا بالضرورة مثقفين بالحاسوب، يحتاجون إلى استخدام استعارات UI واضحة وجعلها سريعة بما فيه الكفاية لتكون ممتعة للاستخدام.
- نحتاج إلى القيام ببعض معالجة الصور خارج الشبكة؛ نحن نخطط لاستضافة هذا على السحابة....
- يجب أن يعمل خارج
- من الضروري أن تبنى حول تحميل موثوق به لملفات متعددة الأحرف (عرضات اتصال يحتمل أن تكون صغيرة).
إذاً، هذه هي الاحتياجات الأساسية تقنياً هذا يقودني إلى بعض الخيارات التكنولوجية:
- التعدّد التّعدّد / التّتويج (مثل أيّ تطبيق سطحي حقيقيّ) هو المفتاح وكذلك تقنية سطح المكتب اللائقة
- انظر أعلاه، نحن بحاجة إلى " مراقبة " الملفات الجديدة التي تصل، وجعل الأظافر الإبهام شفافة، إلخ
- لذا فهي تحتاج نوعاً ما من الثبات... جنباً إلى جنب مع متطلبات أخرى غير أساسية (مثل التلميح) نحن سنحتاج على الأرجح إلى القليل من DB خفيف الوزن.
- تحميلات قائمة على الاحتياجات من 'الحاجات` مع إعادة / التحقق من الأصناف المحملة
من حسن الحظ انني كنت متدينا منذ فترة طويلة وكان لدي على الاقل فكرة عن من اين ابدأ التحدي الاكبر هو التعلُّم !
أولاً، منصة سطح المكتب الواضحة دي جور هي WPF... هذا في جوهره البديل الحالي ل WinForms، وهو قابل للتكييف جداً ولكنه لديه منحنى تعليمي حاد بشكل غير معروف. لقد أنفقت قليلاً من المال على هذا المنحنى. بما في ذلك وُجِسْتُبعد ثلاثة أسابيع سأرتاح أخيراً معه...
ثانيا، كنت بحاجة إلى DB... تحتاج إلى أن تكون خفيفة الوزن، مطلوبة لدعم LINQ (ما، وأنا أحب LINQ:) ، يحتاج لدعم نوع من تكنولوجيا ORM.
الاختيار الأكثر وضوحاً كان ، نوع من خادم SQL الذي هو عظيم لتطبيقات سطح المكتب... على أي حال... لم أتمكن من جعله يعمل! تبين أنه حساس حقا إلى نسخ من مختلف المكونات المثبتة. هذا كان ضوء أحمر بالنسبة لي... كنت بحاجة إلى DB أن يكون قائما بذاته قدر الإمكان! ذلك ترك خيارا واضحا واحدا:
من الموقع:
QLite هي مكتبة برامج حاسوبية تنفذ لـل, خ, سِفر- سِيف, المعاملة محرك قاعدة بيانات SQL. SQLit هو: التي نُشرت على نطاق واسع محرك قاعدة بيانات قاعدة بيانات SQL في العالم. المصدر رمز لـ SQLit هو بوصة المجال العام العام.’
ممتاز، من أجل الدعم، استخدمت مقدم خدمات SQLite Ado.net (هناك & فقط منفذ من SQLitالنشر يتضمن حرفياً مرجعاً وإنشاء ملف... الآن لديه قيد واحد حاد جداً سأغطيه لاحقاً:
خياراتي كانت م٨ هناك دعم لـ SQLite في كل من هذه المنصات.
الآن، لقد استخدمت neHiberanate لـ مشروع حديث و أحد الأشياء التي أزعجتني كان العدد الكبير من الاعتمادات، و الهشاشة الظاهرية عبر نسخ من هذه الاعتمادات. بالنسبة لتطبيق سطح مكتب منخفض التأثير، كان هذا مجرد بصمة كبيرة جداً و مخاطرة كبيرة جداً. لذا كان علي عدها.
هذا تركني مع خيار واحدأُكِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِِْْالآن، هذا لم يكن خياراً سهلاً... لقد إستخدمت الـ EF في الماضي (متلاعباً به) ووجدته تجربة مؤلمة... إلى هذاالآن، أنا لا أخوض في السياسة وراء اختيار MS لدفع EF (ونعم، كان خيارا سياسيا)، ولكن V1 هو حشرة إلى حد ما، وبالنسبة لي على الأقل غير طبيعي إلى حد ما. وأدى هذا إلى تعلمي الثاني 'الفرصة`... إطار هيئة الماجستير! وفي الوقت الذي أكتب فيه هذا، إنها حرفيا ساعتان منذ أن حللت آخر جزء لي من ألم EF... الذي أدى إلى هذا النموذج:
يبدو الأمر بسيطاً... حسناً، أجل... لكنّه أخذني (AGES) للوصول إلى هذا... أنا أعرف SQL جيداً حقاً، C# حقاً حسناً، لكن مزيج المفاهيم الغامضة، الوثائق السيئة ورسائل الخطأ المشوشة تجعل العمل/التعلم بطريقة EF صعبة جداً! EF 4 (في VS 2010/NET 4) يحسّن هذا... ولا يمكن أن يأتي قريباً بما فيه الكفاية!
إذاً، هذا ما تم التوصل إليه آمل:
لذا فقد ذكرت سابقاً أن SQLite لديها بعض المشاكل... إنها في الحقيقة لا تحب التعاون. حسناً، هذا مبالغة... إنه نظام كتابة متعدد القراءة وموحد. بمجرد أن تدرك أنها قضية من السهل حلها إلى حد ما. أنا أستخدم هذا النمط:
public static void AddRange(IEnumerable<UploadFile> files)
{
using (PixEntities ent = new PixEntities())
{
using (new ReadLock(entityLock))
{
using (new WriteLock(entityLock))
{
foreach (var file in files)
{
ent.AddToUploadFiles(file);
ent.SaveChanges();
}
}
}
}
}
كما ترون، هذا له عنصران رئيسيان رئيسيان أنا استخدم adleLoc (حيث أقرأ عادة) * من* DB، في هذه الحالة umm، أنا لا: ()) ثم استخدم كتابة Lock لتغليف أي عملية حيث أكتب إلى DB. الملاحظة ستلاحظ أيضا ما يشبه علة... أنا أعمل ent. Savechages () لكل تكرار من الحلقة... هذا هو آخر SQLite querk، أنه لا يدعم تحديثات الدفعة... ويعطي خطأ غريب حول قفل الملف إذا حاولت:)
هذا النوع من القفل الصغير الذي أستخدمه هو من هنا هناعلى أي حال، هذا الجزء جزء من عدة أجزاء من خبراتي في العمل على )كك(البقاء مُنَدّد!
public static class Locks
{
public static void GetReadLock(ReaderWriterLockSlim locks)
{
bool lockAcquired = false;
while (!lockAcquired)
lockAcquired = locks.TryEnterUpgradeableReadLock(1);
}
public static void GetReadOnlyLock(ReaderWriterLockSlim locks)
{
bool lockAcquired = false;
while (!lockAcquired)
lockAcquired = locks.TryEnterReadLock(1);
}
public static void GetWriteLock(ReaderWriterLockSlim locks)
{
bool lockAcquired = false;
while (!lockAcquired)
lockAcquired = locks.TryEnterWriteLock(1);
}
public static void ReleaseReadOnlyLock(ReaderWriterLockSlim locks)
{
if (locks.IsReadLockHeld)
locks.ExitReadLock();
}
public static void ReleaseReadLock(ReaderWriterLockSlim locks)
{
if (locks.IsUpgradeableReadLockHeld)
locks.ExitUpgradeableReadLock();
}
public static void ReleaseWriteLock(ReaderWriterLockSlim locks)
{
if (locks.IsWriteLockHeld)
locks.ExitWriteLock();
}
public static void ReleaseLock(ReaderWriterLockSlim locks)
{
ReleaseWriteLock(locks);
ReleaseReadLock(locks);
ReleaseReadOnlyLock(locks);
}
public static ReaderWriterLockSlim GetLockInstance()
{
return GetLockInstance(LockRecursionPolicy.SupportsRecursion);
}
public static ReaderWriterLockSlim GetLockInstance(LockRecursionPolicy recursionPolicy)
{
return new ReaderWriterLockSlim(recursionPolicy);
}
}
public abstract class BaseLock : IDisposable
{
protected ReaderWriterLockSlim _Locks;
public BaseLock(ReaderWriterLockSlim locks)
{
_Locks = locks;
}
public abstract void Dispose();
}
public class ReadLock : BaseLock
{
public ReadLock(ReaderWriterLockSlim locks)
: base(locks)
{
Locks.GetReadLock(this._Locks);
}
public override void Dispose()
{
Locks.ReleaseReadLock(this._Locks);
}
}
public class ReadOnlyLock : BaseLock
{
public ReadOnlyLock(ReaderWriterLockSlim locks)
: base(locks)
{
Locks.GetReadOnlyLock(this._Locks);
}
public override void Dispose()
{
Locks.ReleaseReadOnlyLock(this._Locks);
}
}
public class WriteLock : BaseLock
{
public WriteLock(ReaderWriterLockSlim locks)
: base(locks)
{
Locks.GetWriteLock(this._Locks);
}
public override void Dispose()
{
Locks.ReleaseWriteLock(this._Locks);
}
}