در اینجا مدل User، کنترلری به نام Home و View متناظر با آن را ملاحظه میکنید:
namespace ModelStateTest.Models { public class User { public string Email { set; get; } } }
using System.Web.Mvc; using ModelStateTest.Models; namespace ModelStateTest.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } [HttpPost] public ActionResult Index(User model) { model.Email = "?"; return View(model); } } }
@model ModelStateTest.Models.User @{ ViewBag.Title = "Index"; } <h2>Index</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>User</legend> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> }
model.Email = "?";
احتمالا عنوان میکنید که خوب ... همان مقدار علامت سؤال انتساب داده شده. اما ... اینچنین نیست! دقیقا همان مقداری که در حین Postback به سرور ارسال شده، نمایش داده میشود.
این مورد نکتهای است که عدم آشنایی با آن ممکن است چندین ساعت را به دیباگ یک برنامه اختصاص دهد، بدون اینکه نتیجه مفیدی حاصل شود.
مطابق نظر طراحان اصلی ASP.NET MVC، اینکار و این رفتار، دقیقا به همین نحو صحیح است و باگ نیست.
«فرض کنید در فیلدی عددی، کاربر عبارت «تست» را وارد کرده است. نیاز است در خطای اعتبار سنجی پس از Postback به او عنوان کنیم، لطفا بجای «تست»، عدد وارد کنید. چون خاصیت متناظر قید شده در مدل، عددی است، مقدار «تست» وارد شده را از دست خواهیم داد. به همین جهت همان مقدار اولیه وارد شده را در HTML Helpers پس از Postback حفظ میکنیم.»
راه حلهای ممکن، برای به روز رسانی وضعیت مدل پس از Postback
الف) استفاده از متد ModelState.Clear
این متد کلیه دادههای موجود در ModelState را منجمله خطاهای حاصل از اعتبارسنجی، حذف میکند. در این حالت مطابق مثال فوق پس از Postback، مقدار علامت سؤال نسبت داده شده به خاصیت ایمیل، نمایش داده خواهد شد.
ب) استفاده از متد ModelState.Remove
this.ModelState.Remove("Email");
ج) عدم استفاده از HTML Helpers
این مورد را فقط با متدهای کمکی For دار، مانند Html.EditorFor مشاهده خواهید کرد. اگر نحوه تعریف را به شکل زیر تغییر دهیم، نیازی به استفاده از متد ModelState.Remove نخواهد بود. البته، مزیتهای استفاده از HTML Helpers دارای متدهای For دار را که Strongly typed هستند، از دست میدهیم.
<input type="text" name="Email" id="Email" value="@Model.Email" />
چند نکته کاربردی درباره Entity Framework
- ممکنه شیء در حال استفاده قبلا توسط Context بارگذاری شده و هنوز هست، مثلا در یک متد GetAll الان دوباره میخواهید اضافهاش کنید که نمیشود. یا مدیریت ناصحیح Context و باز نگه داشتن بیش از حد آن به ازای کل برنامه یا چندین فرم مختلف با هم که باز هم سبب این مساله میشود.
- یا حتی ممکنه وضعیت موجودیت EntityState.Detached باشه که باید اول Attach شود. (وضعیت اتصال موجودیتها رو ابتدا چک کنید)
- اگر قراره موجودیت جدیدی اضافه بشه چرا از متد Add استفاده نکردید؟
EF Code First #12
در برنامههای وب، کار صرفا به یک کلیک ساده ختم نمیشود که در همان لحظه، یک Context آغاز و پایان یابد. در طی یک درخواست وب، قسمتی از صفحه لیست گروهها، قسمتی دیگر لیست نویسندگان، قسمتی دیگر گزارش درصد استفاده از مرورگرها و قسمتی دیگر لیست آخرین مطالب را نمایش میدهد. تمام اینها هم در طی یک درخواست رخ میدهند و هرکدام، ماژول ماژول طراحی شدهاند و از هم جدا.
اینجا است که ارزش استفاده از قابلیتهای مدیریت طول عمر IoC containers برای به اشتراک گذاری یک DbContext در طی یک درخواست بهتر مشخص میشود. به این ترتیب میشود به سرباری کم و سرعتی بالا دست یافت چون مدام به ازای قسمتهای مختلف برنامه Context ایجاد و تخریب نمیشود.
1- مدیریت تعداد رکوردهای مورد استفاده(مثلا برای کار ما بر روی 5000 رکورد بود)
2- حذف رکوردهای قدیمی بر اساس زمان استفاده.
این 2 مورد در زمان ذخیره تغییرات اعمال میشدند.
بحث من مدیریت سادهتر بیش از 200 کاربر و کامپیوتر در یک شبکه بود. سادهتر شدن به روز رسانیها، مدیریت و تهیه پشتیبان از اطلاعات، دسترسی ریموت به برنامهها، امکان دسترسی به برنامه از سیستم عاملهای مختلف و کلیه مواردی که ذکر شد. در اینجاها windows application نویسی مقرون به صرفه نیست.
و گرنه نوشتن windows service یا برنامههای تک کاربره یا حتی چندکاربره در مقایس کم مثلا یک شرکت 5 نفره ... و امثال آن لزومی ندارد که با وب اپلیکیشن باشد.
Fiddler ابزاری است که به صورت یک پروکسی عمل میکند و تمام اطلاعات ارسالی و دریافتی از طریق مرورگر وب شما را میتواند مونیتور نموده و اطلاعات لازم را به شما ارائه دهد.
برای مثال IE8 ارائه شده و مطابق بررسیها سرعت بارگذاری صفحات در آن اگر کمتر از فایرفاکس نباشد، حداقل برابر یا کمی بیشتر است یا حداقل سرعت آن دوبرابر IE7 گزارش شده. حال شاید این سؤال پیش بیاید که این اندازه گیریها که گاهی در حد میلی ثانیه است چگونه صورت میگیرد؟ از چه ابزاری برای اینکار استفاده میکنند؟
یکی از ابزارهای دقیق انجام اینکار استفاده از Fiddler است (شکل زیر).
این برنامه مستقل از مرورگر عمل میکند و برای مثال تنظیمات پروکسی فایرفاکس برای استفاده از آن در این صفحه توضیح داده شده است.
اخیرا افزونهای سورس باز برای این برنامه تحت عنوان Casaba Security Watcher ارائه شده است که از آدرس زیر قابل دریافت است:
برای نصب آن، دو فایل dll آنرا که اسمبلیهای دات نتی هستند، به درون فولدر scripts برنامه فیدلر کپی کرده و سپس برنامه را اجرا کنید. یک tab جدید به فیدلر تحت عنوان security auditor اضافه میشود که کار آن بررسی محتوای رد و بدل شده و گوشزد کردن موارد امنیتی مرتبط است:
ASP.NET MVC #8
معرفی HTML Helpers
یک HTML Helper تنها یک متد است که رشتهای را بر میگرداند و این رشته میتواند حاوی هر نوع محتوای دلخواهی باشد. برای مثال میتوان از HTML Helpers برای رندر تگهای HTML، مانند img و input استفاده کرد. یا به کمک HTML Helpers میتوان ساختارهای پیچیدهتری مانند نمایش لیستی از اطلاعات دریافت شده از بانک اطلاعاتی را پیاده سازی کرد. به این ترتیب حجم کدهای تکراری تولید رابط کاربری در Viewهای برنامههای ASP.NET MVC به شدت کاهش خواهد یافت، به همراه قابلیت استفاده مجدد از متدهای الحاقی HTML Helpers در برنامههای دیگر.
HTML Helpers در ASP.NET MVC معادل کنترلهای ASP.NET Web forms هستند اما نسبت به آنها بسیار سبکتر میباشند؛ برای مثال به همراه ViewState و همچنین Event model نیستند.
ASP.NET MVC به همراه تعدادی متد HTML Helper توکار است و برای دسترسی به آنها شیء Html که وهلهای از کلاس توکار HtmlHelper میباشد، در تمام Viewها قابل استفاده است.
نحوه ایجاد یک HTML Helper سفارشی
از دات نت سه و نیم به بعد امکان توسعه اشیاء توکار فریم ورک، به کمک متدهای الحاقی (extension methods) میسر شده است. برای نوشتن یک HTML Helper نیز باید همین شیوه عمل کرد و کلاس HtmlHelper را توسعه داد. در ادامه قصد داریم یک HTML Helper را جهت رندر تگ label در صفحه ایجاد کنیم. برای این منظور پوشهی جدیدی به نام Helper را به پروژه اضافه نمائید (جهت نظم بیشتر). سپس کلاس زیر را به آن اضافه کنید:
using System;
using System.Web.Mvc;
namespace MvcApplication4.Helpers
{
public static class LabelExtensions
{
public static string MyLabel(this HtmlHelper helper, string target, string text)
{
return string.Format("<label for='{0}'>{1}</label>", target, text);
}
}
}
همانطور که ملاحظه میکنید متد Label به شکل یک متد الحاقی توسعه دهنده کلاس HtmlHelper که تنها یک رشته را بر میگرداند، تعریف شده است. اکنون برای استفاده از این متد در View دلخواهی خواهیم داشت:
@using MvcApplication4.Helpers
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
@Html.MyLabel("firstName", "First Name:")
ابتدا فضای نام مرتبط با متد الحاقی باید پیوست شود و سپس از طریق شیء Html میتوان به این متد الحاقی دسترسی پیدا کرد. اگر برنامه را اجرا کنید، این خروجی را مشاهده خواهیم کرد. چرا؟
Index
<label for='firstName'>First Name:</label>
علت این است که Razor، اطلاعات را Html encoded به مرورگر تحویل میدهد. برای تغییر این رویه باید اندکی متد الحاقی تعریف شده را تغییر داد:
using System.Web.Mvc;
namespace MvcApplication4.Helpers
{
public static class LabelExtensions
{
public static MvcHtmlString MyLabel(this HtmlHelper helper, string target, string text)
{
return MvcHtmlString.Create(string.Format("<label for='{0}'>{1}</label>", target, text));
}
}
}
تنها تغییر صورت گرفته، استفاده از MvcHtmlString بجای string معمولی است تا Razor آنرا encode نکند.
تعریف HTML Helpers سفارشی به صورت عمومی:
میتوان فضای نام MvcApplication4.Helpers این مثال را عمومی کرد. یعنی بجای اینکه بخواهیم در هر View آنرا ابتدا تعریف کنیم، یکبار آنرا همانند تعاریف اصلی یک برنامه ASP.NET MVC، عمومی معرفی میکنیم. برای این منظور فایل web.config موجود در پوشه Views را باز کنید (و نه فایل web.config قرار گرفته در ریشه اصلی برنامه). سپس فضای نام مورد نظر را در قسمت namespaces صفحات اضافه نمائید:
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="MvcApplication4.Helpers"/>
</namespaces>
به این ترتیب متدهای الحاقی تعریف شده در فضای نام MvcApplication4.Helpers، در تمام Viewهای برنامه در دسترس خواهند بود.
استفاده از کلاس TagBuilder برای تولید HTML Helpers سفارشی:
using System.Web.Mvc;
namespace MvcApplication4.Helpers
{
public static class LabelExtensions
{
public static MvcHtmlString MyNewLabel(this HtmlHelper helper, string target, string text)
{
var labelTag = new TagBuilder("label");
labelTag.MergeAttribute("for", target);
labelTag.InnerHtml = text;
return MvcHtmlString.Create(labelTag.ToString());
}
}
}
در فضای نام System.Web.Mvc، کلاسی وجود دارد به نام TagBuilder که کار تولید تگهای HTML، مقدار دهی ویژگیها و خواص آنها را بسیار ساده میکند و روش توصیه شدهای است برای تولید متدهای HTML Helper. یک نمونه از کاربرد آنرا برای بازنویسی متد MyLabel ذکر شده در اینجا ملاحظه میکنید.
شبیه به همین کلاس، کلاس دیگری به نام HtmlTextWriter در فضای نام System.Web.UI برای انجام اینگونه کارها وجود دارد.
نوشتن HTML Helpers ویژه، به کمک امکانات Razor
نوع دیگری از این متدهای کمکی، Declarative HTML Helpers نام دارند. از این جهت هم Declarative نامیده شدهاند که مستقیما درون فایلهای cshtml یا vbhtml به کمک امکانات Razor قابل تعریف هستند. تولید این نوع متدهای کمکی به این شکل نسبت به مثلا روش TagBuilder سادهتر است، چون توسط Razor به سادگی و به نحو طبیعیتری میتوان تگهای HTML و کدهای مورد نظر را با هم ترکیب کرد (این رفتار طبیعی و روان، یکی از اهداف Razor است).
به عنوان مثال، تعاریف همان کلاسهای Product و Products قسمت قبل (قسمت هفتم) را در نظر بگیرید. با همان کنترلر و View ایی که ذکر شد.
سپس برای تعریف این نوع خاص از HTML Helpers/Razor Helpers باید به این نحو عمل کرد:
الف) در ریشه پروژه یا سایت، پوشهی جدیدی به نام App_Code ایجاد کنید (دقیقا به همین نام. این پوشه، جزو پوشههای ویژه ASP.NET است).
ب) بر روی این پوشه کلیک راست کرده و گزینه Add|New Item را انتخاب کنید.
ج) در صفحه باز شده، MVC 3 Partial Page/Razor را یافته و مثلا نام ProductsList.cshtml را وارد کرده و این فایل را اضافه کنید.
د) محتوای این فایل جدید را به نحو زیر تغییر دهید:
@using MvcApplication4.Models
@helper GetProductsList(List<Product> products)
{
<ul>
@foreach (var item in products)
{
<li>@item.Name ($@item.Price)</li>
}
</ul>
}
در اینجا نحوه تعریف یک helper method مخصوص Razor را مشاهده میکنید که با کلمه @helper شروع شده است. مابقی آن هم ترکیب آشنای code و markup هستند که به کمک امکانات Razor به این شکل روان میسر شده است.
اکنون اگر Viewایی بخواهد از این اطلاعات استفاده کند تنها کافی است به نحو زیر عمل نماید:
@model List<MvcApplication4.Models.Product>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
@ProductsList.GetProductsList(@Model)
ابتدا نام فایل ذکر شده بعد نام متد کمکی تعریف شده در آن. Model هم در اینجا به لیستی از محصولات اشاره میکند.
همچنین چون در پوشه app_code قرار گرفته، تمام Viewها به اطلاعات آن دسترسی خواهند داشت. علت هم این است که ASP.NET به صورت خودکار محتوای این پوشه ویژه را همواره کامپایل میکند و در اختیار برنامه قرار میدهد.
به علاوه در این فایل ProductsList.cshtml، باز هم میتوان متدهای helper دیگری را اضافه کرد و از این بابت محدودیتی ندارد. همچنین میتوان این متد helper را مستقیما داخل یک View هم تعریف کرد. بدیهی است در این حالت قابلیت استفاده مجدد از آنرا به همراه داشتن Viewهایی تمیز و کم حجم، از دست خواهیم داد.
جهت تکمیل بحث
Turn your Razor helpers into reusable libraries
در پی همکاری با بنیاد هویت غیرمتمرکز، شرکت مایکروسافت از برنامه خودش برای بهرهگیری از فناوری بلاکچین با هدف حل چالشهای مدیریت هویت خبر داده است.
بهطور دقیقتر این شرکت بزرگ فناوری با طراحی یک اپلیکیشن در پی استفاده از امکانات فناوری زنجیرهبلوک برای مدیریت بهتر اوراق هویتی دیجیتال است.
برعکس مدلهای امروزی مدیریت هویت، یک سیستم غیرمتمرکز توسط هیچ شخص یا سازمان مرکزی کنترل نمیشود.
این سیستمهای غیرمتمرکز مبتنی بر ساختار زنجیرهبلوک همچنین امکان سانسور و دستکاری اطلاعات هویتی را از بین میبرند درنتیجه نمیتوان برای افراد سو سابقه جعلی ایجاد کرد.
تیم مایکروسافت بعد از بررسی انواع این سیستمهای غیرمتمرکز ترجیح داده به دلایل محرمانگی، مالکیت فردی و دسترسی بدون اجازه از شبکههای بلاکچین عمومی استفاده کند.
مایکروسافت همچنین برای راهاندازی سیستم غیرمتمرکز هویت که بهاختصار آن را DID نامیده از بیتکوین، اتریوم و لایتکوین بهعنوان پلتفرمهای مناسب نامبرده است.