هر متغیر استاتیک تنها دارای یک مقدار، در یک AppDomain مشخص است (مگر اینکه با ویژگی ThreadStatic مزین شود). هر برنامهی ASP.NET هم AppDomain جداگانه و منحصر به خود را دارا است. بنابراین تعریف یک متغیر استاتیک در یک برنامهی ASP.NET به معنای به اشتراک گذاری آن در بین تمامی درخواستهای رسیده به سرور است. بنابراین عموما استفاده از متغیرهای استاتیک در برنامههای چند کاربره ASP.NET یک اشتباه بزرگ است و در صورت استفاده از آن باید منتظر تخریب اطلاعات یا دریافت نتایج غیرمنتظرهای باشید (مگر اینکه واقعا میدانید دارید چکار میکنید، برای مثال کش کردن نگاشتهای NHibernate به این صورت و استفاده از الگوی singleton یا روشهای مشابه که باید بین تمام کاربران به یک صورت و یک شکل به اشتراک گذاشه شود و در حین اجرای برنامه تغییری در آن حاصل نمیشود). برای مثال اگر کاربر یک، در صفحهی یک، متغیر استاتیکی را مقدار دهی کند، کاربر 2 نیز با مقدار به روز شدهی کاربر یک کار خواهد کرد که به طور قطع این مورد مد نظر شما نیست (چون به احتمال زیاد طراحی شما بر اساس کار کاربر در یک Session است و نه یک مقدار برای تمام سشنهای موجود در سایت) و همچنین باید دقت داشت که امنیت سیستم نیز در این حالت زیر سؤال است (زیرا در این حالت تمامی کاربران، صرفنظر از سطوح دسترسی تعریف شده برای آنها، دسترسی به اطلاعاتی خواهند داشت که نباید داشته باشند).
نکتهی دیگری را هم که باید در مورد ASP.NET به خاطر داشت این است که ویژگی ThreadStatic نیز در اینجا کمکی نمیکند؛ زیرا مطابق طراحی آن از تردها استفادهی مجدد میگردد.به عبارت دیگر در ASP.NET الزامی ندارد که آغاز یک درخواست جدید حتما به همراه ایجاد یک ترد جدید باشد.
طول عمر این نوع متغیرها هم تا زمانی است که وب سرور یا برنامه ری استارت شوند. فقط در این حالت است که نمونهی موجود تخریب شده و سپس با اجرای مجدد برنامه، بازسازی خواهند شد.
بنابراین متغیرهای استاتیک در ASP.NET همانند شیء Application عمل میکنند و از آن سریعتر هستند زیرا زمانیکه به آنها ارجاع میشود نیازی به جستجو در یک جدول و یافتن آنها نیست (برخلاف شیء Application) و همچنین در اینجا نیازی هم به عملیات تبدیل نوع دادهای وجود ندارد (برخلاف نوع شیء Application که به صورت Object تعریف شده است). وجود اشیاء Application در ASP.NET فقط به جهت حفظ سازگاری آن با ASP کلاسیک است و توصیه شده است در ASP.NET به دلایلی که ذکر شد، اگر و تنها اگر نیاز به اشیایی در سطح برنامه داشتید از متغیرهای استاتیک استفاده کنید. شیء Cache نیز در ASP.NET همین کاربرد را دارد با این تفاوت که میتوان برای آن مدت زمان منقضی شدن تعریف کرد یا اینکه وب سرور بسته به حق تقدم و اهمیتی که برای آن تعریف شده است، مجاز به حذف کردن آن در زمانی است که با کمبود منابع مواجه میشود. همچنین باید دقت داشت که تنها مکان ذخیره سازی متغیرهای استاتیک حافظه است اما امکان دخیره سازی کش بر روی فایل سیستم تا بانک اطلاعاتی و غیره نیز مهیا است.
سؤال: آیا تعریف SqlConnection به صورت استاتیک جزو مواردی است که "مگر واقعا میدانید دارید چکار میکنید؟" ؟
پاسخ: خیر. در اینجا هم واقعا این شخص نمیداند که دارد چکار میکند! یعنی در مورد سازوکار درونی ADO.NET اطلاعاتی ندارد. باز کردن یک کانکشن در ADO.NET به معنای مراجعه به استخر (pool) کانکشنها و بازکردن یکی از آنها و در مقابل، بستن یک کانکشن هم به معنای علامتگذاری یک کانکشن به صورت غیرفعال است و آماده سازی آن برای استفاده در درخواست بعدی. به معنای دیگر این عملیات سربار آنچنانی ندارد که بخواهید آنرا استاتیک تعریف کنید.
همچنین مورد دیگری را هم که این برنامه نویس نمیداند این است که متغیرهای استاتیک thread safe نیستند. به عبارتی حین استفاده از آنها در یک برنامهی چندکاربرهی ASP.NET حتما باید مکانیزمهای قفلگذاری بر روی این نوع متغیرها و اشیاء اعمال شود (که این هم خود یک سربار اضافی است در مقیاس چند 10 یا چند 100 کاربر همزمان). این مشکلات همزمانی به چه معنا است؟ فرض کنید کاربر یک، شیء استاتیک SqlConnection ایی را باز کرده است و با آن مشغول کوئری گرفتن است. کاربر 2 نیز همزمان شروع به استفاده از این کانکشن باز در حال استفاده میکند (SqlConnection استاتیک یعنی استفادهی تمام کاربران فقط و فقط از یک کانکشن باز شده)، نتیجه این خواهد بود که برای مثال پیغام خطایی را دریافت میکند مانند: فیلد مورد نظر در جدول موجود نیست! چرا؟ چون روی شیء استاتیک SqlConnection تعریف شده قفل گذاری صورت نگرفته است و در حین استفاده از آن هر کاربری در سایت نیز همان را استفاده خواهد کرد یا از آن بدتر ممکن است یک کاربر زودتر از کاربر دیگری آنرا ببندد! کاربر سوم در وسط کار با پیغام غیرمعتبر بودن کانکشن مواجه میشود، یا اینکه به صورت پیش فرض یک datareader را بیشتر نمیتوان بر روی یک کانکشن باز شده اعمال کرد. کاربر 4 مشغول خواندن اطلاعات است، کاربر 5 ، پیغام غیرمعتبر بودن کوئری را دریافت میکند.
معماری پیازی توسط جفری پالرمو در سال 2008 ابداع شد. این معماری راه بهتری را برای ساخت برنامههای کاربردی جهت تست پذیری، نگهداری و قابلیت اطمینان بهتر بر روی زیرساختهایی مانند پایگاههای داده و خدمات ارائه میدهد. هدف اصلی این معماری، پرداختن به چالشهای پیش روی معماری 3 لایه و ارائه راه حلی برای مشکلات رایج مانند اتصال و جداسازی وابستگیها است. دو نوع اتصال وجود دارند؛ اتصال محکم و اتصال ضعیف که در ادامه آنها را بررسی میکنیم.
اتصال محکم
هنگامی که یک کلاس، به یک وابستگی مشخصی وابسته است، گفته میشود که به شدت با آن کلاس همراه است. یک اتصال محکم جفت شده، به یک شیء دیگر وابسته است. این بدان معناست که تغییر یک شیء در یک برنامهی با اتصال محکم جفت شده، اغلب نیاز به تغییر در تعدادی از اشیاء دیگر دارد. هنگامیکه یک برنامه کوچک است، دشوار نیست، اما در یک برنامهی بزرگ، ایجاد تغییرات بسیار دشوار است.
اتصال ضعیف
یعنی دو شیء مستقل هستند و یک شیء میتواند بدون اینکه به آن وابسته باشد، از شیء دیگری استفاده کند. این یک هدف طراحی است که به دنبال کاهش وابستگیهای متقابل بین اجزای یک سیستم، با هدف کاهش خطر این است که تغییرات در یک جزء، مستلزم تغییر در هر جزء دیگر باشد.
مزایای معماری پیازی
چندین مزیت برای معماری پیازی وجود دارند که در زیر ذکر شدهاند:
- قابلیت نگهداری بهتری را فراهم میکند؛ زیرا همه کدها به لایهها یا مرکز، بستگی دارند.
- تست پذیری بهتری را فراهم میکند؛ زیرا آزمون واحد را میتوان برای لایههای جداگانه، بدون تأثیر بر سایر ماژولهای برنامه ایجاد کرد.
- این برنامه یک برنامهی کاربردی با اتصال آزاد را ایجاد میکند؛ زیرا لایه بیرونی برنامه، همیشه از طریق واسطها با لایه داخلی، ارتباط برقرار میکند.
- هرگونه پیاده سازی پیوسته، در زمان اجرا به برنامه ارائه میشود.
- موجودیتهای دامنه، هسته و بخش مرکزی هستند. میتواند به هر دو لایه پایگاه داده و UI دسترسی داشته باشد.
- لایههای داخلی هرگز به لایه خارجی وابسته نیستند. کدی که ممکن است تغییر کرده باشد، باید بخشی از یک لایه خارجی باشد.
لایههای معماری پیاز
این معماری به شدت به اصل وارونگی وابستگی، متکی است. رابط کاربری از طریق واسطها با منطق تجاری ارتباط برقرار میکند و دارای چهار لایه است. لایهها به سمت مرکز هستند. بخش مرکزی، موجودیتهای Domain است که نشاندهنده موضوعات تجاری و رفتاری است. این لایهها میتوانند متفاوت باشند اما لایه موجودیتهای دامنه، همیشه بخشی از دامنهی مرکزی است. لایه دیگر، رفتار بیشتر یک شیء را تعریف میکند. در ادامه به توضیح لایههای معماری پیاز توجه فرمایید:
Domain Entities Layer
این بخش مرکزی معماری است. تمام اشیاء دامنهی برنامه را در خود نگه میدارد. اگر برنامه ای با چهارچوب موجودیت ORM توسعه داده شود، این لایه دارای کلاسهای POCO (Code First) یا Edmx (Database First) با موجودیتها است. این نهادهای دامنه هیچ وابستگی ندارند.
Repository Layer
این لایه برای ایجاد یک لایه Abstraction بین لایه نهادهای دامنه و لایه منطق تجاری یک برنامه، در نظر گرفته شدهاست. این یک الگوی دسترسی به دادهاست که باعث میشود یک رویکرد مرتبطتر برای دسترسی به دادهها وجود داشته باشد. ما یک مخزن عمومی را ایجاد میکنیم که منبع داده را برای دادهها جستجو میکند، دادهها را از منبع داده به یک نهاد تجاری نگاشت میکند و تغییرات موجودیت تجاری را به منبع داده ارائه میدهد.
Service Layer
این لایه دارای رابطهایی است که برای برقراری ارتباط بین لایه UI و لایه مخزن استفاده میشود و به همراه منطق تجاری برای یک موجودیت است. بنابراین به آن لایه منطق تجاری نیز میگویند.
UI Layer
خارجیترین لایه است و میتواند برنامهی وب، Web API یا پروژه واحد تست باشد. این لایه دارای یک پیاده سازی از جنس Dependency Inversion Principle است بطوری که برنامه، یک برنامهی کاربردی جفت شدهی آزاد میسازد و از طریق واسطها با لایه داخلی ارتباط برقرار میکند.
در مطالب بعدی با مبحث معماری پیازی، نکات تکمیلی و مهمتری از لایه پیاز را تشریح میکنیم و یک پروژه را با معماری پیاز، راه اندازی میکنیم.
استفاده از چندین Context در EF 6 Code first
- استفاده از چند Context برای اینکه هر کدام قرار است در یک دیتابیس جدا ذخیره شوند؟ نمیشود FK بین اینها (جداول دو دیتابیس مختلف) تعریف کرد (SQL Server چنین کاری را پشتیبانی نمیکند).
- اگر برنامه ماژولار است، در EF میتوان به صورت خودکار تمام ماژولها را در طی یک Context یکپارچه بارگذاری کرد (^ و ^).
- هدف از ایجاد Schema در SQL Server، ایجاد ظروفی برای گروه بندی منطقی اشیاء است. مثلا عدهای به سه SP خاص دسترسی داشته باشند. عدهای فقط بتوانند با Viewها کار کنند. یا حتی عدهای به تمام موارد دسترسی داشته باشند. بنابراین یک نوع ایزوله سازی قسمتهای مختلف بانک اطلاعاتی مدنظر هست، در اصل. حالا اگر عدهای فقط به سه جدول خاص دسترسی دارند، آیا میتوانند ارجاعی را به جدول چهارمی که در یک schema دیگر تعریف شده داشته باشند؟ بله. البته فقط به این شرط که کاربران schema سه جدول فعلی به schema جدول چهارم، دسترسی و مجوز لازم را داشته باشد و برای این دسترسی دادنها هم باید مستقلا T-SQL بنویسید.
و ... ضمنا گاهی از اوقات از Schema برای مدیریت نامهای هم نام استفاده میشود. چیزی شبیه به namespace در سیشارپ مثلا. نمونهاش طراحی چند مستاجری است.
نتیجه گیری؟ برای سرگرمی Schema ایجاد نکنید؛ مگر اینکه واقعا قصد ایزوله سازی قسمتهای مختلف یک بانک اطلاعاتی را از کاربرانی خاص داشته باشید. به Schema به شکل یک Sandbox امنیتی (یک قرنطینه) نگاه کنید.
برای مطالعه بیشتر
Understanding the Difference between Owners and Schemas in SQL Server
Implementation of Database Object Schemas
موفق باشید.
کنترل DatePicker شمسی مخصوص Silverlight 4
- فکر خوبیه. انجام شد:
http://slpdatepicker.codeplex.com/
@Meysam
- هدف بالا بردن تست پذیری برنامه است. مدیریت نهایی آن دیگر با شما است.
- بله. در سی شارپ private methods باید با حروف کوچک شروع شوند و public methods با حروف بزرگ.
از چند مانیتور برای برنامه نویسی استفاده میکنید؟
- خطایابی بهتر (استفاده از پنجره output یا intermediate ویژوال استودیو)
- توسعه سریعتر (بخصوص برای طراحان وب)
- مقایسه پذیری بالاتر
- همزمانی استفاده (در یک زمان قصد کار برروی وهله از sql server داشته باشید)
Horizontal scaling یا Scale-out
هردو روش
هیچکدام
تا بحال شرایطی پیش نیامده که نیاز به توسعه پذیری سیستمی که طراحی کردهام باشد.