چون این اطلاعات سراسری به ازای یک کاربر معنا پیدا میکنند و به ازای هر کاربر لاگین شده به سیستم میتوانند متفاوت باشند، استفاده از سشن، کوکی و یا HTML5 local storage برای اینکار مفید هستند.
در حالتی که کاربر وارد شده و Authorize مقدار true دارد و ولی Role مد نظر را ندارد چطوری میتوان کاربر را به صفحه لاگین هدایت کرد؟
نظرات مطالب
کتابخانهی انواع و اقسام مدلهای دادهای
خیلی مفید بود. متشکرم.
آیا اینچنین مجموعه جامعی در مورد استراتژیهای طراحی GUI برنامه، ایجاد تعامل مفید بین کاربر و واسط کاربری و از این دست مطالب سراغ ندارید؟؟ (مسلما با توجه به نوع برنامه و سطح مخاطب آن، طراحی کاربر باید متفاوت باشد)
فکر میکنم لازم باشد که خودمان، اینچنین مجموعهای از تصاویر واسطهای کاربری، در برنامههای موفق (فارسی) تهیه و در دسترس عموم قرار بدهیم.
آیا اینچنین مجموعه جامعی در مورد استراتژیهای طراحی GUI برنامه، ایجاد تعامل مفید بین کاربر و واسط کاربری و از این دست مطالب سراغ ندارید؟؟ (مسلما با توجه به نوع برنامه و سطح مخاطب آن، طراحی کاربر باید متفاوت باشد)
فکر میکنم لازم باشد که خودمان، اینچنین مجموعهای از تصاویر واسطهای کاربری، در برنامههای موفق (فارسی) تهیه و در دسترس عموم قرار بدهیم.
پاسخ به بازخوردهای پروژهها
دلیل استفاده از DirectPermissions در جدول user
/// <summary> /// دسترسیهای مستقیم کاربر بدون وابستی به گروههای کاربری او /// </summary> public string DirectPermissions { get; set; } /// <summary> /// ساختار اکس ام ال دسترسیهای مستقیم کاربر بدون وابستی به گروههای کاربری او /// </summary> public XElement XmlDirectPermissions { get { return XElement.Parse(DirectPermissions); } set { DirectPermissions = value.ToString(); } }
در سایت جاری مطالب زیادی درباره ASP.NET MVC نوشته شده است. این مطلب و قسمت بعدی آن مروری خواهد داشت بر Best Practiceها در ASP.NET MVC.
استفاده از NuGet Package Manager برای مدیریت وابستگیها
درباره اهمیت NuGet برای مصرف کنندگان قبلا این مطلب نوشته شده است.
بجای صرف وقت برای اینکه بررسی کنیم آیا این نسخهی جدید کتابخانهی X یا اسکریپت jQuery آمده است یا خیر، میتوان این وظیفه را به NuGet سپرد. علاوه بر این NuGet مزیتهای دیگری هم دارد؛ مثلا تیمهای برنامه نویسی میتوانند کتاب خانههای مشترک خودشان را در مخزنهای سفارشی NuGet قرار دهند و توزیع و Versioning آنرا به NuGet بسپارند.
تکیه بر Abstraction (انتزاع)
Abstraction در طراحی سیستمها منجر به تولید نرم افزار هایی Loosely coupled با قابلیت نگهداری بالا و همچنین فراهم شدن زمینه برای نوشتن Unit Test میشود.
اگر به مطالب قبلی وب سایت برگردیم در مطلب چرا ASP.NET MVC گفته شد که :
2) دستیابی به کنترل بیشتر بر روی اجزای فریم ورک :
در طراحی ASP.NET MVC همهجا interfaceها قابل مشاهد هستند. همین مساله به معنای افزونه پذیری اکثر قطعات تشکیل دهنده ASP.NET MVC است؛ برخلاف ASP.NET web forms. برای مثال تابحال چندین view engine، routing engine و غیره توسط برنامه نویسهای مستقل برای ASP.NET MVC طراحی شدهاند که هیچکدام با ASP.NET web forms میسر نیست. برای مثال از view engine پیش فرض آن خوشتان نمیآید؟ عوضش کنید! سیستم اعتبار سنجی توکار آنرا دوست ندارید؟ آنرا با یک نمونه بهتر تعویض کنید و الی آخر ...
به علاوه طراحی بر اساس interfaceها یک مزیت دیگر را هم به همراه دارد و آن هم ساده سازی mocking (تقلید) آنها است جهت ساده سازی نوشتن آزمونهای واحد.
از کلمهی کلیدی New استفاده نکنید
هر جا ممکن است کار وهله سازی اشیاء را به لایه و حتی Framework دیگری بسپارید. هر زمان اشیاء نرم افزار خودتان را با کلمهی new وهله سازی میکنید اصل Abstraction را فراموش کرده اید. هر زمان اشیاء نرم افزار را مستقیم وهله سازی میکنید در نظر داشته باشید میتوانید آنها را به صورت وابستگی تزریق کنید.
در همین رابطه مطالب زیر را از دست ندهید :
از HttpContext مستقیما استفاده نکنید (از HttpContextBase استفاده کنید)
از .NET 4 به بعد فضای نامی تعریف شده که در بر دارندهی کلاسهای انتزاعی (Abstraction) خیلی از قسمتهای اصلی ASP.NET است. یکی از مواردی که در توسعهی ASP.NET معمولا زیاد استفاده میشود، شیء HttpContext است . استفاده از HttpContextBase را به استفاده از HttpContext ترجیح دهید. اهمیت این موضوع در راستای اهمیت انتزاع (Abstraction) میباشد.
از "رشتههای جادویی" اجتناب کنید
استفاده از رشتههای جادویی در خیلی از جاها کار را ساده میکند؛ بعضی وقتها هم به آنها نیاز است اما مشکلات زیادی دارند :
مثال دوم :
مثلا مثال دوم مشکلات رشتههای جادویی را ندارد.
در رابطه با Magic strings این مطلب را مطالعه بفرمایید.
از نوشتن HTML در کدهای "Backend" خودداری کنید
با توجه به اصل جداسازی وابستگیها (Separation of Concerns) وظیفهی کنترلرها و دیگر کدهای backend رندر کردن HTML نیست. (ساده سازی کنترلر ها) البته در نظر داشته باشید که قطعا تولید HTML در متدهای کمکی کلاس هایی که "تنها" وظیفهی آنها کمک به Viewها جهت تولید کد هست ایرادی ندارد. این کلاسها بخشی از View در نظر گرفته میشوند نه کدهای "backend".
در Viewها "Business logic" انجام ندهید
معکوس بند قبلی هم کاملا صدق میکند ، منظور این است که Viewها تا جایی که ممکن است باید حاوی کمترین Business logic ممکن باشند. در واقع تمرکز Viewها باید استفاده و نحوهی نمایش داده ای که برای آنها فراهم شده باشد نه انجام عملیات روی آن.
استفاده از Presentation Model را به استفاده مستقیم از Business Objectها ترجیح دهید
در مطالب مختلف وب سایت اشاره به اهمین ViewModelها شده است. برای اطلاعات بیشتر بند ج آموزش 11 از سری آموزشهای ASP.NET MVC را مطالعه بفرمایید.
Ifهای شرطی را در Viewها را در متدهای کمکی کپسوله کنید
استفاده از شرطها در View کار توسعه دهنده را برای یک سری اعمال ساده میکند اما میتواند باعث کمی کثیف کاری هم شود. مثلا:
میتوان این کد که تا حدودی شامل منطق تجاری هم هست را در یک متد کمکی کپسوله کرد :
اکنون برای نمایش آواتار کاربر به سادگی میتوان نوشت :
به این ترتیب کد ما تمیزتر شده ، قابلیت نگهداری آن بالاتر رفته ، منطق تجاری یک بار و در یک قسمت نوشته شده از این کد در جاهای مختلف سایت میتوان استفاده کرد و اگر لازم به تغییر باشد با تغییر در یک قسمت همه جا اعمال میشود.
منتظر قسمت بعدی باشید.
استفاده از NuGet Package Manager برای مدیریت وابستگیها
درباره اهمیت NuGet برای مصرف کنندگان قبلا این مطلب نوشته شده است.
بجای صرف وقت برای اینکه بررسی کنیم آیا این نسخهی جدید کتابخانهی X یا اسکریپت jQuery آمده است یا خیر، میتوان این وظیفه را به NuGet سپرد. علاوه بر این NuGet مزیتهای دیگری هم دارد؛ مثلا تیمهای برنامه نویسی میتوانند کتاب خانههای مشترک خودشان را در مخزنهای سفارشی NuGet قرار دهند و توزیع و Versioning آنرا به NuGet بسپارند.
تکیه بر Abstraction (انتزاع)
Abstraction در طراحی سیستمها منجر به تولید نرم افزار هایی Loosely coupled با قابلیت نگهداری بالا و همچنین فراهم شدن زمینه برای نوشتن Unit Test میشود.
اگر به مطالب قبلی وب سایت برگردیم در مطلب چرا ASP.NET MVC گفته شد که :
2) دستیابی به کنترل بیشتر بر روی اجزای فریم ورک :
در طراحی ASP.NET MVC همهجا interfaceها قابل مشاهد هستند. همین مساله به معنای افزونه پذیری اکثر قطعات تشکیل دهنده ASP.NET MVC است؛ برخلاف ASP.NET web forms. برای مثال تابحال چندین view engine، routing engine و غیره توسط برنامه نویسهای مستقل برای ASP.NET MVC طراحی شدهاند که هیچکدام با ASP.NET web forms میسر نیست. برای مثال از view engine پیش فرض آن خوشتان نمیآید؟ عوضش کنید! سیستم اعتبار سنجی توکار آنرا دوست ندارید؟ آنرا با یک نمونه بهتر تعویض کنید و الی آخر ...
به علاوه طراحی بر اساس interfaceها یک مزیت دیگر را هم به همراه دارد و آن هم ساده سازی mocking (تقلید) آنها است جهت ساده سازی نوشتن آزمونهای واحد.
از کلمهی کلیدی New استفاده نکنید
هر جا ممکن است کار وهله سازی اشیاء را به لایه و حتی Framework دیگری بسپارید. هر زمان اشیاء نرم افزار خودتان را با کلمهی new وهله سازی میکنید اصل Abstraction را فراموش کرده اید. هر زمان اشیاء نرم افزار را مستقیم وهله سازی میکنید در نظر داشته باشید میتوانید آنها را به صورت وابستگی تزریق کنید.
در همین رابطه مطالب زیر را از دست ندهید :
- تزریق وابستگی (dependency injection) به زبان ساده
- تزریق وابستگی (Dependency Injection) و توسعه پذیری
از HttpContext مستقیما استفاده نکنید (از HttpContextBase استفاده کنید)
از .NET 4 به بعد فضای نامی تعریف شده که در بر دارندهی کلاسهای انتزاعی (Abstraction) خیلی از قسمتهای اصلی ASP.NET است. یکی از مواردی که در توسعهی ASP.NET معمولا زیاد استفاده میشود، شیء HttpContext است . استفاده از HttpContextBase را به استفاده از HttpContext ترجیح دهید. اهمیت این موضوع در راستای اهمیت انتزاع (Abstraction) میباشد.
از "رشتههای جادویی" اجتناب کنید
استفاده از رشتههای جادویی در خیلی از جاها کار را ساده میکند؛ بعضی وقتها هم به آنها نیاز است اما مشکلات زیادی دارند :
- رشتهها معنای باطنی ندارند (مثلا : دشوار است که از روی نام یک ID مشخص کنم این ID چطور به ID دیگری مرتبط است و یا اصلا ربط دارد یا خیر)
- با اشتباهات املایی یا عدم رعایت حروف بزرگ و کوچک ایجاد مشکل میکنند.
- به Refactoring واکنش خوبی نشان نمیدهند. (برای درک بهتر این مطلب را بخوانید.)
<p> <label for="FirstName">First Name:</label> <span id="FirstName">@ViewData["FirstName"]</span> </p>
<p> <label for="FirstName">First Name:</label> <span id="FirstName">@Model.FirstName</span> </p>
در رابطه با Magic strings این مطلب را مطالعه بفرمایید.
از نوشتن HTML در کدهای "Backend" خودداری کنید
با توجه به اصل جداسازی وابستگیها (Separation of Concerns) وظیفهی کنترلرها و دیگر کدهای backend رندر کردن HTML نیست. (ساده سازی کنترلر ها) البته در نظر داشته باشید که قطعا تولید HTML در متدهای کمکی کلاس هایی که "تنها" وظیفهی آنها کمک به Viewها جهت تولید کد هست ایرادی ندارد. این کلاسها بخشی از View در نظر گرفته میشوند نه کدهای "backend".
در Viewها "Business logic" انجام ندهید
معکوس بند قبلی هم کاملا صدق میکند ، منظور این است که Viewها تا جایی که ممکن است باید حاوی کمترین Business logic ممکن باشند. در واقع تمرکز Viewها باید استفاده و نحوهی نمایش داده ای که برای آنها فراهم شده باشد نه انجام عملیات روی آن.
استفاده از Presentation Model را به استفاده مستقیم از Business Objectها ترجیح دهید
در مطالب مختلف وب سایت اشاره به اهمین ViewModelها شده است. برای اطلاعات بیشتر بند ج آموزش 11 از سری آموزشهای ASP.NET MVC را مطالعه بفرمایید.
Ifهای شرطی را در Viewها را در متدهای کمکی کپسوله کنید
استفاده از شرطها در View کار توسعه دهنده را برای یک سری اعمال ساده میکند اما میتواند باعث کمی کثیف کاری هم شود. مثلا:
@if(Model.IsAnonymousUser) { <img src="@Url.Content("~/content/images/anonymous.jpg")" /> } else if(Model.IsAdministrator) { <img src="@Url.Content("~/content/images/administrator.jpg")" /> } else if(Model.Membership == Membership.Standard) { <img src="@Url.Content("~/content/images/member.jpg")" /> } else if(Model.Membership == Membership.Preferred) { <img src="@Url.Content("~/content/images/preferred_member.jpg")" /> }
public static string UserAvatar(this HtmlHelper<User> helper) { var user = helper.ViewData.Model; string avatarFilename = "anonymous.jpg"; if (user.IsAnonymousUser) { avatarFilename = "anonymous.jpg"; } else if (user.IsAdministrator) { avatarFilename = "administrator.jpg"; } else if (user.Membership == Membership.Standard) { avatarFilename = "member.jpg"; } else if (user.Membership == Membership.Preferred) { avatarFilename = "preferred_member.jpg"; } var urlHelper = new UrlHelper(helper.ViewContext.RequestContext); var contentPath = string.Format("~/content/images/{0}", avatarFilename) string imageUrl = urlHelper.Content(contentPath); return string.Format("<img src='{0}' />", imageUrl); }
@Html.UserAvatar()
منتظر قسمت بعدی باشید.
State machine چیست؟
State machine مدلی است بیانگر نحوه واکنش سیستم به وقایع مختلف. یک ماشین حالت وضعیت جاری قسمتی از سیستم را نگهداری کرده و به ورودیهای مختلف پاسخ میدهد. این ورودیها در نهایت وضعیت سیستم را تغییر خواهند داد.
نحوه پاسخگویی یک ماشین حالت (State machine) را به رویدادی خاص، انتقال (Transition) مینامند. در یک انتقال مشخص میشود که ماشین حالت بر اساس وضعیت جاری خود، با دریافت یک رویداد، چه عکس العملی را باید بروز دهد. عموما (و نه همیشه) در حین پاسخگویی ماشین حالت به رویدادهای رسیده، وضعیت آن نیز تغییر خواهد کرد. در اینجا گاهی از اوقات پیش از انجام عملیاتی، نیاز است شرطی بررسی شده و سپس انتقالی رخ دهد. به این شرط، guard گفته میشود.
بنابراین به صورت خلاصه، یک ماشین حالت، مدلی است از رفتاری خاص، تشکیل شده از حالات، رویدادها، انتقالات، اعمال (actions) و شرطها (Guards). در اینجا:
- یک حالت (State)، شرطی منحصربفرد در طول عمر ماشین حالت است. در هر زمان مشخصی، ماشین حالت در یکی از حالات از پیش تعریف شده خود قرار خواهد داشت.
- یک رویداد (Event)، اتفاقی است که به ماشین حالت اعمال میشود؛ یا همان ورودیهای سیستم.
- یک انتقال (Transition)، بیانگر نحوه رفتار ماشین حالت جهت پاسخگویی به رویداد وارده بر اساس وضعیت جاری خود میباشد. در طی یک انتقال، سیستم از یک حالت به حالتی دیگر منتقل خواهد شد.
- برای انجام یک انتقال، نیاز است یک شرط (Guard/Conditional Logic) بررسی شده و در صورت true بودن آن، انتقال صورت گیرد.
- یک عمل (Action)، بیانگر نحوه پاسخگویی ماشین حالت در طول دوره انتقال است.
چگونه میتوان الگوی ماشین حالت را تشخیص داد؟
اکثر برنامههای وب، متشکل از پیاده سازی چندین ماشین حالت میباشند؛ مانند ثبت نام در سایت، درخواست یک کتاب از کتابخانه، ارسال درخواستها و پاسخگویی به آنها و یا حتی ارسال یک مطلب در سایت، تائید و انتشار آن.
البته عموما در حین طراحی برنامهها، کمتر به این نوع مسایل به شکل یک ماشین حالت نگاه میشود. به همین جهت بهتر است معیارهایی را برای شناخت زود هنگام آنها مدنظر داشته باشیم:
- آیا در جدول بانک اطلاعاتی خود فیلدهایی مانند State (حالت) یا Status (وضعیت)دارید؟ اگر بله، به این معنا است که در حال کار با یک ماشین حالت هستید.
- عموما فیلدهای Bit و Boolean، بیانگر حضور ماشینهای حالت هستند. مانند IsPublished ، IsPaid و یا حتی داشتن یک فیلد timeStamp که میتواند NULL بپذیرد نیز بیانگر استفاده از ماشین حالت است؛ مانند فیلدهای published_at، paid_at و یا confirmed_at.
- داشتن رکوردهایی که تنها در طول یک بازه زمانی خاص، معتبر هستند. برای مثال آبونه شدن در یک سایت در طول یک بازه زمانی مشخص.
- اعمال چند مرحلهای؛ مانند ثبت نام در سایت و دریافت ایمیل فعال سازی. سپس فعال سازی اکانت از طریق ایمیل.
مثالی ساده از یک ماشین حالت
یک کلید برق را در نظر بگیرید. این کلید دارای دو حالت (states) روشن و خاموش است. زمانی که خاموش است، با دریافت رخدادی (event)، به وضعیت (state/status) روشن، منتقل خواهد شد (Transition) و برعکس.
در اینجا حالات با مستطیلهای گوشه گرد نمایش داده شدهاند. انتقالات توسط فلشهایی انحناء دار که حالات را به یکدیگر متصل میکنند، مشخص گردیدهاند. برچسبهای هر فلش، مشخص کننده نام رویدادی است که سبب انتقال و تغییر حالت میگردد. با شروع یک ماشین حالت، این ماشین در یکی از وضعیتهای از پیش تعیین شدهاش قرار خواهد گرفت (initial state)؛ که در اینجا حالت خاموش است.
این نوع نمودارها میتوانند شامل جزئیات بیشتری نیز باشند؛ مانند برچسبهایی که نمایانگر اعمال قابل انجام در طی یک انتقال هستند.
رسم ماشینهای حالت در برنامههای وب، به کمک کتابخانه jsPlumb
کتابخانههای زیادی برای رسم فلوچارت، گردشهای کاری، ماشینهای حالت و امثال آن جهت برنامههای وب وجود دارند و یکی از معروفترینهای آنها کتابخانه jsPlumb است. این کتابخانه به صورت یک افزونه jQuery طراحی شده است؛ اما به عنوان افزونهای برای کتابخانههای MooTools و یا YUI3/Yahoo User Interface 3 نیز قابل استفاده میباشد. کتابخانه jsPlumb در مرورگرهای جدید از امکانات ترسیم SVG و یا HTML5 Canvas استفاده میکند. برای سازگاری با مرورگرهای قدیمیتر مانند IE8 به صورت خودکار به VML سوئیچ خواهد کرد. همچنین این کتابخانه امکانات ترسیم تعاملی قطعات به هم متصل شونده را نیز دارا است (شبیه به طراح یک گردش کاری). البته برای اضافه شدن امکاناتی مانند کشیدن و رها کردن در آن نیاز به jQuery-UI نیز خواهد داشت.
برای نمونه اگر بخواهیم مثال فوق را توسط jsPlumb ترسیم کنیم، روش کار به صورت زیر خواهد بود:
مستندات کامل jsPlumb را در سایت آن میتوان ملاحظه نمود.
در مثال فوق، ابتدا css و فایلهای js مورد نیاز ذکر شدهاند. توسط css، مکان قرارگیری اولیه المانهای متناظر با حالات، مشخص میشوند.
سپس زمانیکه اشیاء صفحه در دسترس هستند، تنظیمات jsPlumb انجام خواهد شد. برای مثال در اینجا نوع نمایشی Endpointها به نقطه تنظیم شده است. موارد دیگری مانند مستطیل نیز قابل تنظیم است. سپس نیاز است منبع و مقصدها به کتابخانه jsPlumb معرفی شوند. به کمک متد jsPlumb.makeTarget، تمام المانهای دارای کلاس w به عنوان منبع و با شمارش divهایی با class=ep، مقصدهای قابل اتصال تعیین شدهاند (jsPlumb.makeSource). متد jsPlumb.bind یک callback function است و هربار که اتصالی برقرار میشود، فراخوانی خواهد شد. متد jsPlumb.draggable تمام عناصر دارای کلاس w را قابل کشیدن و رها کردن میکند و در آخر توسط متدهای jsPlumb.connect، مقصد و منبعهای مشخصی را هم متصل خواهیم کرد. نمونه نهایی تهیه شده برای بررسی بیشتر.
برای مطالعه بیشتر
Finite-state machine
UML state machine
UML 2 State Machine Diagrams
مثالهایی در این مورد
State machine مدلی است بیانگر نحوه واکنش سیستم به وقایع مختلف. یک ماشین حالت وضعیت جاری قسمتی از سیستم را نگهداری کرده و به ورودیهای مختلف پاسخ میدهد. این ورودیها در نهایت وضعیت سیستم را تغییر خواهند داد.
نحوه پاسخگویی یک ماشین حالت (State machine) را به رویدادی خاص، انتقال (Transition) مینامند. در یک انتقال مشخص میشود که ماشین حالت بر اساس وضعیت جاری خود، با دریافت یک رویداد، چه عکس العملی را باید بروز دهد. عموما (و نه همیشه) در حین پاسخگویی ماشین حالت به رویدادهای رسیده، وضعیت آن نیز تغییر خواهد کرد. در اینجا گاهی از اوقات پیش از انجام عملیاتی، نیاز است شرطی بررسی شده و سپس انتقالی رخ دهد. به این شرط، guard گفته میشود.
بنابراین به صورت خلاصه، یک ماشین حالت، مدلی است از رفتاری خاص، تشکیل شده از حالات، رویدادها، انتقالات، اعمال (actions) و شرطها (Guards). در اینجا:
- یک حالت (State)، شرطی منحصربفرد در طول عمر ماشین حالت است. در هر زمان مشخصی، ماشین حالت در یکی از حالات از پیش تعریف شده خود قرار خواهد داشت.
- یک رویداد (Event)، اتفاقی است که به ماشین حالت اعمال میشود؛ یا همان ورودیهای سیستم.
- یک انتقال (Transition)، بیانگر نحوه رفتار ماشین حالت جهت پاسخگویی به رویداد وارده بر اساس وضعیت جاری خود میباشد. در طی یک انتقال، سیستم از یک حالت به حالتی دیگر منتقل خواهد شد.
- برای انجام یک انتقال، نیاز است یک شرط (Guard/Conditional Logic) بررسی شده و در صورت true بودن آن، انتقال صورت گیرد.
- یک عمل (Action)، بیانگر نحوه پاسخگویی ماشین حالت در طول دوره انتقال است.
چگونه میتوان الگوی ماشین حالت را تشخیص داد؟
اکثر برنامههای وب، متشکل از پیاده سازی چندین ماشین حالت میباشند؛ مانند ثبت نام در سایت، درخواست یک کتاب از کتابخانه، ارسال درخواستها و پاسخگویی به آنها و یا حتی ارسال یک مطلب در سایت، تائید و انتشار آن.
البته عموما در حین طراحی برنامهها، کمتر به این نوع مسایل به شکل یک ماشین حالت نگاه میشود. به همین جهت بهتر است معیارهایی را برای شناخت زود هنگام آنها مدنظر داشته باشیم:
- آیا در جدول بانک اطلاعاتی خود فیلدهایی مانند State (حالت) یا Status (وضعیت)دارید؟ اگر بله، به این معنا است که در حال کار با یک ماشین حالت هستید.
- عموما فیلدهای Bit و Boolean، بیانگر حضور ماشینهای حالت هستند. مانند IsPublished ، IsPaid و یا حتی داشتن یک فیلد timeStamp که میتواند NULL بپذیرد نیز بیانگر استفاده از ماشین حالت است؛ مانند فیلدهای published_at، paid_at و یا confirmed_at.
- داشتن رکوردهایی که تنها در طول یک بازه زمانی خاص، معتبر هستند. برای مثال آبونه شدن در یک سایت در طول یک بازه زمانی مشخص.
- اعمال چند مرحلهای؛ مانند ثبت نام در سایت و دریافت ایمیل فعال سازی. سپس فعال سازی اکانت از طریق ایمیل.
مثالی ساده از یک ماشین حالت
یک کلید برق را در نظر بگیرید. این کلید دارای دو حالت (states) روشن و خاموش است. زمانی که خاموش است، با دریافت رخدادی (event)، به وضعیت (state/status) روشن، منتقل خواهد شد (Transition) و برعکس.
در اینجا حالات با مستطیلهای گوشه گرد نمایش داده شدهاند. انتقالات توسط فلشهایی انحناء دار که حالات را به یکدیگر متصل میکنند، مشخص گردیدهاند. برچسبهای هر فلش، مشخص کننده نام رویدادی است که سبب انتقال و تغییر حالت میگردد. با شروع یک ماشین حالت، این ماشین در یکی از وضعیتهای از پیش تعیین شدهاش قرار خواهد گرفت (initial state)؛ که در اینجا حالت خاموش است.
این نوع نمودارها میتوانند شامل جزئیات بیشتری نیز باشند؛ مانند برچسبهایی که نمایانگر اعمال قابل انجام در طی یک انتقال هستند.
رسم ماشینهای حالت در برنامههای وب، به کمک کتابخانه jsPlumb
کتابخانههای زیادی برای رسم فلوچارت، گردشهای کاری، ماشینهای حالت و امثال آن جهت برنامههای وب وجود دارند و یکی از معروفترینهای آنها کتابخانه jsPlumb است. این کتابخانه به صورت یک افزونه jQuery طراحی شده است؛ اما به عنوان افزونهای برای کتابخانههای MooTools و یا YUI3/Yahoo User Interface 3 نیز قابل استفاده میباشد. کتابخانه jsPlumb در مرورگرهای جدید از امکانات ترسیم SVG و یا HTML5 Canvas استفاده میکند. برای سازگاری با مرورگرهای قدیمیتر مانند IE8 به صورت خودکار به VML سوئیچ خواهد کرد. همچنین این کتابخانه امکانات ترسیم تعاملی قطعات به هم متصل شونده را نیز دارا است (شبیه به طراح یک گردش کاری). البته برای اضافه شدن امکاناتی مانند کشیدن و رها کردن در آن نیاز به jQuery-UI نیز خواهد داشت.
برای نمونه اگر بخواهیم مثال فوق را توسط jsPlumb ترسیم کنیم، روش کار به صورت زیر خواهد بود:
<!doctype html> <html> <head> <title>State Machine Demonstration</title> <style type="text/css"> #opened { left: 10em; top: 5em; } #off { left: 12em; top: 15em; } #on { left: 28em; top: 15em; } .w { width: 5em; padding: 1em; position: absolute; border: 1px solid black; z-index: 4; border-radius: 1em; border: 1px solid #346789; box-shadow: 2px 2px 19px #e0e0e0; -o-box-shadow: 2px 2px 19px #e0e0e0; -webkit-box-shadow: 2px 2px 19px #e0e0e0; -moz-box-shadow: 2px 2px 19px #e0e0e0; -moz-border-radius: 0.5em; border-radius: 0.5em; opacity: 0.8; filter: alpha(opacity=80); cursor: move; } .ep { float: right; width: 1em; height: 1em; background-color: #994466; cursor: pointer; } .labelClass { font-size: 20pt; } </style> <script type="text/javascript" src="jquery.min.js"></script> <script type="text/javascript" src="jquery-ui.min.js"></script> <script type="text/javascript" src="jquery.jsPlumb-all-min.js"></script> <script type="text/javascript"> $(document).ready(function () { jsPlumb.importDefaults({ Endpoint: ["Dot", { radius: 5}], HoverPaintStyle: { strokeStyle: "blue", lineWidth: 2 }, ConnectionOverlays: [ ["Arrow", { location: 1, id: "arrow", length: 14, foldback: 0.8}] ] }); jsPlumb.makeTarget($(".w"), { dropOptions: { hoverClass: "dragHover" }, anchor: "Continuous" }); $(".ep").each(function (i, e) { var p = $(e).parent(); jsPlumb.makeSource($(e), { parent: p, anchor: "Continuous", connector: ["StateMachine", { curviness: 20}], connectorStyle: { strokeStyle: '#42a62c', lineWidth: 2 }, maxConnections: 2, onMaxConnections: function (info, e) { alert("Maximum connections (" + info.maxConnections + ") reached"); } }); }); jsPlumb.bind("connection", function (info) { }); jsPlumb.draggable($(".w")); jsPlumb.connect({ source: "opened", target: "off" }); jsPlumb.connect({ source: "off", target: "on", label: "Turn On" }); jsPlumb.connect({ source: "on", target: "off", label: "Turn Off" }); }); </script> </head> <body> <div class="w" id="opened"> Begin <div class="ep"> </div> </div> <div class="w" id="off"> Off <div class="ep"> </div> </div> <div class="w" id="on"> On <div class="ep"> </div> </div> </body> </html>
در مثال فوق، ابتدا css و فایلهای js مورد نیاز ذکر شدهاند. توسط css، مکان قرارگیری اولیه المانهای متناظر با حالات، مشخص میشوند.
سپس زمانیکه اشیاء صفحه در دسترس هستند، تنظیمات jsPlumb انجام خواهد شد. برای مثال در اینجا نوع نمایشی Endpointها به نقطه تنظیم شده است. موارد دیگری مانند مستطیل نیز قابل تنظیم است. سپس نیاز است منبع و مقصدها به کتابخانه jsPlumb معرفی شوند. به کمک متد jsPlumb.makeTarget، تمام المانهای دارای کلاس w به عنوان منبع و با شمارش divهایی با class=ep، مقصدهای قابل اتصال تعیین شدهاند (jsPlumb.makeSource). متد jsPlumb.bind یک callback function است و هربار که اتصالی برقرار میشود، فراخوانی خواهد شد. متد jsPlumb.draggable تمام عناصر دارای کلاس w را قابل کشیدن و رها کردن میکند و در آخر توسط متدهای jsPlumb.connect، مقصد و منبعهای مشخصی را هم متصل خواهیم کرد. نمونه نهایی تهیه شده برای بررسی بیشتر.
برای مطالعه بیشتر
Finite-state machine
UML state machine
UML 2 State Machine Diagrams
مثالهایی در این مورد
ممنون از پستی که گذاشتید.
فقط یک موردی هست، این سبک پیاده سازی شما فقط برای کاربران لاگین شده قابل استفاده است. در حالی که کاربرانی که از سایت ما دیدن میکنند ممکن است اکثرا لاگین نکرده باشند.
از طرفی پروتکل HTTP، از نوع state-less هست و نمیشه فهمید که درخواستها از یک شخص مشخص دریافت شده اند و جز آمار نیاریم. البته میشه با cookie این مشکل را هم تا حدودی رفع کرد.
در حالت کلی فکر کنم استفاده از SignalR روش بهتری باشه
چند روز پیش تصمیم گرفتم از ASP.NET FriendlyUrls برای سفارشی کردن Urlهای سایت استفاده کنم
وقتی در لوکال تست میکردم همه چیز درست بود و بدون مشکل کار میکرد اما به محض اینکه سایت رو روی سرور Publish کردم و قصد پیمایش بین صفحات رو داشتم، با کلیک بر روی منوها با خطا 404 not found مواجه میشدم!
پس از کمی بررسی متوجه شدم که باید اسمبلی System.Web.Optimization.dll رو به وب سایت اد کنم و چند خط کد به web.config سایت اضافه کنم.
1- برای اضافه کردن System.Web.Optimization.dll به سایت روی References کلیک راست کنید و گزینه Manage Nuget Packages رو انتخاب کنید و سپس با جستجوی عبارت optimize از آیتمهای پیدا شده Microsoft ASP.NET Web Optimization Framework رو نصب کنید.
2- خطوط زیر رو به web.config سایت اضافه کنید
<system.webServer> <modules runAllManagedModulesForAllRequests="true"> <remove name="BundleModule" /> <add name="BundleModule" type="System.Web.Optimization.BundleModule" /> </modules> </system.webServer>
با این تغییرات ایراد ASP.NET FriendlyUrls برطرف شد
نظرات مطالب
معماری میکروسرویسها
من در مورد همه مشکلات میکرو سرویس زیاد با شما موافق نیستم
- از آنجایی که ارتباط بین سرویسها در بستر شبکه انجام میشود، انتظار کندی عملکرد سرویسها دور از ذهن نیست. (اتفاقا بخاطر توزیع برنامه بر روی چند سیستم در زمانی که بار زیادی بر روی سیستم هست پاسخ گویی به کاربر میتونه خیلی بسرعت انجام بپذیره و اتفاقا یکی از مزایای اون هست)
- به دلیل ارتباطات شبکهای، احتمال آسیب پذیریهای امنیتی در این نوع برنامهها بیشتر است. (البته بیشتر این توزیع در server farm انجام میشه ،یعنی پشت فایروال و کسی جز سرورها در این شبکه خصوصی وجود ندارد، نمیگم نیست ولی خیلی نیست)
- نوشتن سرویسهایی که در بستر شبکه با سایر سرویسها در ارتباط هستند سختی و مشکلات خود را دارد. برنامهنویس در این شرایط، درگیر برقراری ارتباط، رمزگذاری دادهها در صورت نیاز و تبدیل آنها میشود.(همان موارد بالا)
- به دلیل مجزا بودن بخشهای مختلف برنامه، مانیتور کردن و ردیابی عملکرد سرویسها، یکی از کارهای اصلی توسعه دهنده یا استفاده کننده از برنامه است. (اینم خودش یک فایده است و طبق اصل SRP و تفاوت MicroServic با SOA بیشتر بر همین نکته تاکید داره که یک میکرو سرویس کاملا مستقل میباشد و راحتتر قابل مانیتور کردن و ردیابی عملکرد سرویس میباشد
- در مجموع سرعت برنامههای نوشته شده با معماری Microservices کندتر از برنامههای نوشته شده با معماری Monolithic است. دلیل آن محیط اجرایی برنامهها است. برنامههایی با معماری Monolithic بر روی حافظه سرور پردازش میشوند. (باز تاکید که اصل استفاده از میکرو سرویس برای سیستم هایی با تراکنش بالا میباشد ،هدف توسعه راحتر و بدون تاثیر بر بقیه سرویسها و حتی بدون توقف آنها میباشد، همچنین امکان horizontal Scalability نرم افزار و بالا بردن تعداد سرورهای ارائه دهنده سرویس براحتی بوجود خواهد امد ، پس میتونه سرعت رو خیلی بالا ببره و مشکل توقف سرویس که در خیلی از سامانههای ایرانی میبینیم رو از بین میبره )
نظرات مطالب
چک لیست تهیه یک برنامه ASP.NET MVC
سلام؛
لایه سرویس باید مستقل از presenation باشد.یکی از اهداف از طراحی سرویس گرا اینست که سرویس ارایه شده قابل استفاده در clientها متفاوت باشد. لذا نباید به viewmodel وابستگی داشته باشد. بنظر میرسد که راه درست این است که سرویس domain model یا DTO برگرداند و در کنترلر با استفاده از automapper یا مپینگ دستی viewmodel ساخته شود و به view ارسال شود.
هرچند طراحی کاملا سلیقه ای و مربوط به دامنه کاربرد است و نمیتوان گفت که غلط است
با تشکر از سایت بسیار مفیدی که ایجاد کرده اید. م
لایه سرویس باید مستقل از presenation باشد.یکی از اهداف از طراحی سرویس گرا اینست که سرویس ارایه شده قابل استفاده در clientها متفاوت باشد. لذا نباید به viewmodel وابستگی داشته باشد. بنظر میرسد که راه درست این است که سرویس domain model یا DTO برگرداند و در کنترلر با استفاده از automapper یا مپینگ دستی viewmodel ساخته شود و به view ارسال شود.
هرچند طراحی کاملا سلیقه ای و مربوط به دامنه کاربرد است و نمیتوان گفت که غلط است
با تشکر از سایت بسیار مفیدی که ایجاد کرده اید. م