netsh http add sslcert ipport=0.0.0.0:6001 certhash=<thumbprint of certificate> appid={new guid here} certstorename=Root
SSL Certificate add failed, Error: 1312 A specified logon session does not exist. It may already have been terminated.
استفاده از محیط گرافیکی IIS جهت لیست کردن، اضافه و حذف ماژولها
به بخش modules درIIS بروید. در پنل سمت راست همه امکانات جهت افزودن و ویرایش و حذف وجود دارند:
روش معرفی ماژول در خط فرمان با استفاده از دستور Appcmd
Appcmd.exe install module /name:MODULE_NAME /image:PATH_TO_DLL
قسمت name که نام ماژول است و قسمت image هم مسیر قرار گرفتن فایل dll هست.
برای نمونه:
%windir%\system32\inetsrv\appcmd.exe install module /name:DefaultDocumentModule /image:%windir%\system32\inetsrv\defdoc.dll
در صورتیکه ماژولی که قبلا افزوده شده باشد را بخواهید اضافه کنید، خطای زیر را دریافت خواهید کرد:
ERROR ( message:Failed to add duplicate collection element "DefaultDocumentModule". )
جهت حذف ماژول دستور زیر را صادر کنید:
Appcmd.exe uninstall module MODULE_NAME
نمونه:
%windir%\system32\inetsrv\appcmd.exe uninstall module DefaultDocumentModule
گرفتن کوئری یا لیستی از ماژولهای فعال برای یک اپلیکیشن یا عمومی:
Appcmd.exe list modules [/app.name:APPLICATION_NAME]
سوپپچ aap.name اختیاری است ولی اگر نام یک اپلیکیشن را به آن بدهید، فقط ماژولهایی را که روی این اپلیکیشن اجرا میشوند، لیست میکند.
نمونه:
%windir%\system32\inetsrv\appcmd.exe list modules /app.name:"Default Web Site"
کد زیر هم نمونه ای برای لیست کردن تمامی ماژولهای عمومی که بر روی تمامی اپلیکیشنها اجرا میشوند:
%windir%\system32\inetsrv\appcmd.exe list modules
خط زیر یک ماژول را برای همه اپلیکیشنها یا اپلیکیشن خاصی فعال میکند که بستگی دارد سوییچ type چگونه مقداردهی شده باشد:
Appcmd.exe add module /name:MODULE_NAME /type:MGD_TYPE
برای مثال خط زیر باعث میشود ماژول Forms Authentication فقط برای وب اپلیکیشن default web site فعال شود:
%windir%\system32\inetsrv\appcmd.exe add module /name:FormsAuthentication /type:System.Web.Security.FormsAuthenticationModule /app.name:"Default Web Site"
یا در پایین آن را به صورت عمومی یا global فعال میکند:
%windir%\system32\inetsrv\appcmd.exe add module /name:FormsAuthentication /type:System.Web.Security.FormsAuthenticationModule
برای غیرفعال کردن یک ماژول از دستور زیر استفاده میشود:
Appcmd.exe delete module MODULE_NAME [/app.name:APPLICATION_NAME]
اگر غیر فعال کردن یک ماژول در یک اپلیکیشن خاص مدنظر شما باشد دستور زیر نمونه آن است:
%windir%\system32\inetsrv\appcmd.exe delete module FormsAuthentication /app.name:"Default Web Site"
اگر قصد دارید آنرا بر روی تمامی اپلیکیشنها غیرفعال کنید، دستور زیر نمونه آن است:
%windir%\system32\inetsrv\appcmd.exe delete module FormsAuthentication
حفظ کردن یا به خاطر سپردن دستورات بالا ممکن است کار سخت و دشواری باشد، به همین جهت از help کمک بگیرید:
Appcmd.exe module /?
یا به شکل اختصاصیتر برای یک دستور
Appcmd.exe install module /?Appcmd add module /?
MVC Scaffolding #3
<globalization fileEncoding="utf-8" requestEncoding="utf-8" responseEncoding="utf-8"/>
آموزش مقدماتی Silverlight
- لطفا برای این نوع سؤالات از قسمت تماس با من در بالای سایت استفاده کنید.
- و بله میشود. به سیلورلایت همانند یک شیء فلش نگاه کنید. اینها اشیاء سمت کاربر هستند و نه سمت سرور. بنابراین امکان اضافه کردن آنها با کمک گیری از تگ object میسر است. اطلاعات بیشتر به همراه مثال:
http://msdn.microsoft.com/en-us/library/cc189089%28VS.95%29.aspx
در برنامههای وب امروز نیازی به فراخوانی ثوابت که در طول حیات برنامه انگشت شمار تغیر میکنند نیست و با توجه به استفاده از فرامین و متدهای سمت کلاینت احتیاج هست تا این ثوابت بار اول لود صفحه به کلاینت پاس داده شوند.
میتوان در این گونه موارد از قابلیتهای گوناگونی استفاده کرد که در اینجا ما با استفاده از یک فیلد مخفی و json مقدار را به کلاینت پاس میدهیم و در این مثال در سمت کلاینت نیز دراپ دان را با این مقادیر پر میکنیم:
public enum PersistType { Persistable = 1, NotPersist = 2, AlwaysPersist = 3 }
لیست را باید قبل از پر کردن در فیلد مخفی به json بصورت serialize شده تبدیل کرد، برای این منظور از JavaScriptSerializer موجود در اسمبلیهای دات نت در متد زیر استفاده شده:
public static string ConvertEnumToJavascript(Type t) { if (!t.IsEnum) throw new Exception("Type must be an enumeration"); var values = System.Enum.GetValues(t); var dict = new Dictionary<int, string>(); foreach (object obj in values) { string name = System.Enum.GetName(t, obj); dict.Add(Convert.ToInt32(System.Enum.Format(t, obj, "D")), name); } return new JavaScriptSerializer().Serialize(dict); }
با توجه به اینکه در سمت کلاینت مقدار json ذخیره شده در فیلد مخفی را میتوان به صورت آبجکت برخورد کرد پس یک متد در سمت کلاینت این آبجکت را در loop قراد داده و درمتغییری در فایل جاوا اسکریپت نگهداری میکنیم:
var Enum_PersistType = null; function SetEnumTypes() { Enum_PersistType = JSON.parse($('#hfJsonEnum_PersistType').val()); }
و در هر قسمت که نیاز به مقدار enum بود با توجه به ایندکس مقدار را برای نمایش ازاین متغییر بیرون میکشیم:
function GetPersistTypeTitle_Concept(enumId) { return Enum_PersistType[enumId]; }
برای مثال در dropdown در سمت کلاینت این نوع استفاده شده و در حالتی از صفحه فقط برای نمایش عنوان آن احتیاج به دریافت آن از سمت سرور باشد میتوان از این روش کمک گرفت
و یا در سمت javascript میتوان با استفاده از jQuery مقادیر متغییر را در dropdown پر کرد.
function FillDropdown() { $("#ddlPersistType").html(""); $.each(Enum_PersistType, function (key, value) { $("#ddlPersistType").append($("<option></option>").val(key).html(value)); }); }
bower install angular-route --save
<script src="bower_components/angular-route/angular-route.min.js" type="text/javascript"></script>
<div class="col-md-9"> <ng-view></ng-view> </div>
model.panel = { title: "Panel Title", items: [ { title: "Home", url: "#/home" }, { title: "Articles", url: "#/articles" }, { title: "Authors", url: "#/authors" } ] };
var module = angular.module("dntModule", ["ngRoute"]);
module.config(function ($routeProvider) { $routeProvider .when("/home", { template: "<app-home></app-home>" }) .when("/articles", { template: "<app-articles></app-articles>" }) .when("/authors", { template: "<app-authors></app-authors>" }) .otherwise({ redirectTo: "/home" }); });
module.component("appHome", { template: ` <hr><div> <div>Panel heading = HomePage</div> <div> HomePage </div> </div>` }); module.component("appArticles", { template: ` <hr><div> <div>Panel heading = Articles</div> <div> Articles </div> </div>` }); module.component("appAuthors", { template: ` <hr><div> <div>Panel heading = Authors</div> <div> Authors </div> </div>` });
اکنون توسط لینکهای تعریف شده میتوانیم به راحتی درون تمپلیتها، پیمایش کنیم. همانطور که عنوان شد تا اینجا مسیریاب پیشفرض Angular هیچ اطلاعی از کامپوننتها ندارد؛ بلکه آنها را با کمک template، به صورت غیر مستقیم، درون صفحه نمایش دادهایم.
معرفی Component Router
مزیت این روتر این است که به صورت اختصاصی برای کار با کامپوننتها طراحی شده است. بنابراین دیگر نیازی به استفاده از template درون route configuration نیست. برای استفاده از این روتر ابتدا باید پکیج آن را نصب کنیم:
bower install angular-component-router --save
سپس وابستگی فوق را با روتر پیشفرضی که در مثال قبل بررسی کردیم، جایگزین خواهیم کرد:
<script src="bower_components/angular-component-router/angular_1_router.js"></script>
همچنین درون فایل module.js به جای وابستگی ngRoute از ngComponentrouter استفاده خواهیم کرد:
var module = angular.module("dntModule", ["ngComponentRouter"]);
در ادامه به جای تمامی route configurations قبلی، اینبار یک کامپوننت جدید را به صورت زیر ایجاد خواهیم کرد:
module.component("appHome", { template: ` <hr> <div> <div>Panel heading = HomePage</div> <div> HomePage </div> </div>` });
همانطور که مشاهده میکنید برای پاسخگویی به تغییرات URL، مقدار routeConfig$ را مقداردهی کردهایم. در اینجا به جای بارگذاری تمپلیت، خود کامپوننت، در هر یک از ruleهای فوق بارگذاری خواهد شد. برای حالت otherwise نیز از سینتکس **/ استفاده کردهایم.
تمپلیت کامپوننت فوق نیز به صورت زیر است:
<div class="container"> <div class="row"> <div class="col-md-3"> <hr> <dnt-widget></dnt-widget> </div> <div class="col-md-9"> <ng-outlet></ng-outlet> </div> </div> </div>
لازم به ذکر است دیگر نباید از دایرکتیو ng-view استفاده کنیم؛ زیرا این دایرکتیو برای استفاده از روتر اصلی طراحی شده است. به جای آن از دایرکتیو ng-outlet استفاده شده است. این کامپوننت به عنوان یک کامپوننت top level عمل خواهد کرد. بنابراین درون صفحهی index.html از کامپوننت فوق استفاده خواهیم کرد:
<html ng-app="dntModule"> <head> <meta charset="UTF-8"> <title>Using Angular 1.5 Component Router</title> <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css"> <link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css"> </head> <body> <dnt-app></dnt-app> <script src="bower_components/angular/angular.js" type="text/javascript"></script> <script src="bower_components/angular-component-router/angular_1_router.js"></script> <script src="scripts/module.js" type="text/javascript"></script> <script src="scripts/dnt-app.component.js"></script> <script src="scripts/dnt-widget.component.js"></script> </body> </html>
در نهایت باید جهت فعالسازی سیستم مسیریابی جدید، سرویس زیر را همراه با نام کامپوننت فوق ریجستر کنیم:
module.value("$routerRootComponent", "dntApp");
اکنون اگر برنامه را اجرا کنید خواهید دید که همانند قبل، کار خواهد کرد. اما اینبار از روتر جدید و سازگار با کامپوننتها استفاده میکند.
کدهای این قسمت را نیز از اینجا میتوانید دریافت کنید.
برای ادامه دادن این سری از مقالات آموزش MDX Query نیاز میباشد که پایگاه دادهی Advwnture Work DW را نصب کرده و سپس توسط SSAS عمل Deploy را انجام دهیم تا پایگاه دادهی Multidimensional Database توسط SSAS ساخته شود .
در ابتدا میبایست فایل نصب پایگاه داده ی Advwnture Work را دانلود نمایید برای این منظور به آدرس زیر رفته و فایل AdventureWorks2008R2_SR1.exe را دانلود نمایید .
http://www.general-files.biz/download/gs4ac37d18h17i0/AdventureWorks2008R2_SR1.exe.html
یا به آدرس زیر مراجعه کنید
https://msftdbprodsamples.codeplex.com/releases/view/59211
نیاز میباشد قبل از شروع به نصب نرم افزار SQL Server Management Studio را ببندید.
سپس مراحل زیر را انجام دهید.
1. فایل AdventureWorks2008R2_SR1.exe را اجرا نمایید.
2. کمی صبر کنید تا صفحهی زیر نمایش داده شود. و گزینهی I Accept … را انتخاب نماید و دکمهی Next را بزنید.
3. در صورتی که از ویندوز 8 استفاده نماید احتمال دارد با خطای زیر مواجه شوید در این صورت به قسمت روش نصب در ویندوز 8 در ادامهی این مقاله مراجعه کنید .
4. در صورتی که از ویندوزهای Server 2003, XP , Win7 استفاده کنید صفحهی زیر را خواهید دید. در این صفحه ابتدا Instance مربوط به SQL سرور خود را انتخاب نماید (در صورت داشتن چندین Instance روی سرور پایگاه داده) سپس مسیر نصب فایلهای Sample را مشخص نمایید (بعدا از همین مسیر اقدام به Deploy کردن پایگاه دادهی Multidimensional خواهیم کرد) و پیش فرضها را بپذیرید و دکمهی Install را بزنید.
5. کمی صبر کنید تا نصب انجام گردد. و در انتها کلید Finish را بزنید.
پس از مراحل بالا (به جز ویندوز 8) با باز کردن نرم افزار SQL Server Management Studio و اتصال به سرویس Database Engine در قسمت Database تصویر زیر را خواهید دید (البته امکان دارد شما از قبل دارای پایگاه دادههای شخصی بوده باشید که بنابر این آنها نیز در لیست شما وجود خواهند داشت)
همچنین شما میتوانید از پنجرهی Object Explorer در قسمت Connect اقدام به اتصال به سرویس SSAS نموده .
و در پنجرهی باز شده Server Name را انتخاب نمایید (با توجه به اینکه شما در حال حاضر میخواهید به SSAS موجود در سیستم Local متصل شوید ، بنابر این انتخاب سرور Local با وارد کردن کاراکتر (.) انجام میشود.)
بعد از اتصال شکل زیر را خواهید داشت و در شاخهی Database همچنان هیچ Multidimensional Database ی نخواهید داشت.(بعد از عمل Deploy که در ادامه آموزش داده خواهد شد پایگاه دادهی Multidimensional ساخته میشود.)
تنها روشی که تاکنون برای نصب پایگاه دادهی Adventure Work DW برروی ویندوز 8 یافته ام (البته کمی غیر حرفه ای میباشد.) به صورت زیر میباشد.
فایل بالا را ( AdventureWorks2008R2_SR1.exe ) روی سیستم عاملهای ( Server 2003,XP,Win 7 ) نصب کرده (به عنوان یک سیستم عامل واسط) و سپس سرویس Database Engine را Stop کرده و فایلهای پایگاه داده را به سیستم عامل ویندوز 8 انتقال داده و به صورت دستی Restore کنیم.
مراحل ایجاد پایگاه دادهی Multidimensional در ویندوزهای مختلف ، یکسان میباشد.
بعد از نصب پایگاه دادهی Adventure Work DW باید به شاخهی نصب Sample بروید (همان مسیری که در مراحل نصب وارد کردیم و البته آدرس پیش فرض آن C:\Program Files\Microsoft Sql Server\100\Tools\Sample میباشد.)
(در صورتی که در ویندوز 8 مراحل نصب را دنبال میکنید مسیر زیر را در سیستم خود درست نمایید و فایلها و پوشههای موجود در مسیر فوق در سیستم عامل واسط (همان سیستم عاملی که فایل نصب بر روی آن نصب شده است) را به درون آن انتقال دهید.)
سپس به زیر شاخهی \ AdventureWorks 2008R2 Analysis Services Project\enterprise بروید و فایل Adventure Works.sln را با Visual Studio 2010 باز کنید.
احتمال دارد که نیاز باشد روی کل شاخهی enterprise در قسمت Security کاربر جاری را Add کنید و به آن دسترسی Full Control بدهید تا عملیات Convert این پروژه به درستی انجام شود.
پس از باز کردن پروژه در Visual Studio 2010 صفحه ای مطابق تصویر زیر در پنجرهی Solution Explorer خواهید دید.
به هیچ عنوان نگران ساختار این پروژه نباشید ، زیرا در مقالههای آیند شرح کاملی در این خصوص کار با Business Intelligence Management Studio خواهم داد. فعلا هدف ما ایجاد پایگاه دادهی Multidimensional می باشد.
برای ساخت پایگاه دادهی Multidimensional مراحل زیر را دنبال نمایید.
1. در ابتدا روی پروژه کلیک راست کرده و گزینهی Properties را انتخاب نمایید.
2. در قسمت Configuration Properties منوی Deployment را انتخاب کرده و اطمینان حاصل کنید که سرور شما LocalHost و نام پایگاه داده شما Adventure Works DW 2008R2 باشد.
3. سپس روی Adventure Works.ds کلیک راست کنید تا تنظیمات Connection String به DW را انجام دهیم. مطابق شکل زیر
4. سپس در پنجرهی باز شده دکمهی Edit را بزنید .
5. و در صفحه باز شده تنظیمات زیر را مطابق تصویر زیر انجام دهید. دقت داشته باشید که تغییرات را از بالا به پایین باید انجام دهید و قبل از زدن دکمهی OK حتما Test Connection را بزنید تا از صحت تنظیمات مطمعا شوید.
6. سپس دو بار دکمهی OK را در دوصفحه کلیک کنید. (بعد از این مراحل شما آمادهی Deploy کردن میباشد)
7. در ابتدا پروژه را Build نمایید ( CTRl + Shift + B ) و اطمینان حاصل کنید که Build با موفقیت انجام میشود.
8. در انتها برروی نام پروژه کلیک راست نمایید و گزینهی Deploy را انتخاب نمایید. فرایند Deploy کردن میتواند کمی زمان بر باشد بنابر این شکیبا باشید و در انتها پیام Deployment Completed Successfully را دریافت خواهید کرد.
9. حال به SQL Server Management Studio بروید و به سرویس SSAS کانکت شوید . در قسمت DataBase یک پایگاه داده با نام Adventure Works DW 2008R2 مشاهده خواهید کرد .
به شما تبریک میگویم اینک شما یک پایگاه دادهی Multidimensional را ساخته اید .
در مقالهی بعدی توضیحاتی در خصوص BIMS (Business Intelligence Management Studio) خواهم داد و همچنین اولین MDX Query را خواهیم نوشت.
AngularJS #1
در ابتدای بحث، برای آشنایی بیشتر با HTML Helperها به مطالعه این مقاله بپردازین.
در این مقاله قرار است برای یک HTML Helper خاص، قالب نمایشی اختصاصی خودمان را طراحی کنیم و به نحوی HTML Helper موجود را سفارشی سازی کنیم. به عنوان مثال میخواهیم خروجی یک EditorFor() برای یک نوع خاص، به حالت دلخواهی باشد که ما خودمان آن را تولیدش کردیم؛ یا اصلا نه. حتی میشود برای خروجی یک EditorFor() که خصوصیتی از جنس string را میخواهیم به آن انتساب دهیم، به جای تولید input، یک مقدار متنی را برگردانیم. به این حالت:
<div> @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" }) <div> @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" }) </div> </div> <div> @Html.LabelFor(model => model.Genre, htmlAttributes: new { @class = "control-label col-md-2" }) <div> @Html.EditorFor(model => model.Genre, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Genre, "", new { @class = "text-danger" }) </div> </div>
در ادامه یک پروژهی عملی را شروع کرده و در آن کاری را که میخواهیم، انجام میدهیم. پروژهی ما به این شکل میباشد که قرار است در آن به ثبت کتاب بپردازیم و برای هر کتاب هم یک سبک داریم و قسمت سبک کتابهای ما یک Enum است که از قبل میخواهیم مقدارهایش را تعریف کنیم.
مدل برنامه
public class Books { public int Id { get; set; } [Required] [StringLength(255)] public string Name { get; set; } public Genre Genre { get; set; } }
public enum Genre { [Display(Name = "Non Fiction")] NonFiction, Romance, Action, [Display(Name = "Science Fiction")] ScienceFiction }
در داخل کلاس Books یک خصوصیت از جنس Genre برای سبک کتابها داریم و در داخل نوع شمارشی Genre، سبکهای ما تعریف شدهاند. همچنین هر کدام از سبکها هم به ویژگی Display مزین شدهاند تا بتونیم بعدا از مقدار آنها استفاده کنیم.
کنترلر برنامه
public class BookController : Controller { // GET: Book public ActionResult Index() { return View(DataAccess.DataContext.Book.ToList()); } public ActionResult Create() { return View(); } [HttpPost] [ValidateAntiForgeryToken] public ActionResult Create(Books model) { if (!ModelState.IsValid) return View(model); try { DataAccess.DataContext.Book.Add(model); DataAccess.DataContext.SaveChanges(); return RedirectToAction("Index"); } catch (Exception ex) { ModelState.AddModelError("", ex.Message); return View(model); } } public ActionResult Edit(int id) { try { var book = DataAccess.DataContext.Book.Find(id); return View(book); } catch (Exception ex) { return View("Error"); } } [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(Books model) { if (!ModelState.IsValid) return View(model); try { DataAccess.DataContext.Book.AddOrUpdate(model); DataAccess.DataContext.SaveChanges(); return RedirectToAction("Index"); } catch (Exception ex) { ModelState.AddModelError("", ex.Message); return View(model); } } public ActionResult Details(int id) { try { var book = DataAccess.DataContext.Book.Find(id); return View(book); } catch (Exception ex) { return View("Error"); } } }
در قسمت کنترلر هم کار خاصی جز عملیات اصلی نوشته نشدهاست. لیست کتابها را از پایگاه داده بیرون آوردیم و از طریق اکشن Index به نمایش گذاشتیم. با اکشنهای Create، Edit و Details هم کارهای روتین مربوط به خودشان را انجام دادیم. نکتهی قابل تذکر، DataAccess میباشد که کلاسی است که با آن ارتباط برقرار شده با EF و سپس اطلاعات واکشی و تزریق میشوند.
View مربوط به اکشن Create برنامه
@using Book.Entities @model Book.Entities.Books @{ ViewBag.Title = "Create"; } <h2>New Book</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div> <h4>Books</h4> <hr /> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <div> @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" }) <div> @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" }) </div> </div> <div> @Html.LabelFor(model => model.Genre, htmlAttributes: new { @class = "control-label col-md-2" }) <div> @Html.EditorFor(model => model.Genre, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Genre, "", new { @class = "text-danger" }) </div> </div> <div> <div> <input type="submit" value="Create" /> <input type="reset" value="Reset" /> @Html.ActionLink("Back to List", "Index", null, new {@class="btn btn-default"}) </div> </div> </div> } @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
View برنامه هم همان ویویی است که خود Visual Studio برای ما ساختهاست. به جز یک سری دستکاریهایی داخل سیاساس، هدف از گذاشتن View مربوط به Create این بود که قرار است بر روی این قسمت کار کنیم. اگر پروژه رو اجرا کنید و به قسمت Create بروید، مشاهده خواهید کرد که برای Genre یک input ساخته شدهاست که کاربر باید در آن مقدار وارد کند. ولی اگر یادتان باشد، ما سبکهای نگارشی خودمان را در نوع شمارشی Genre ایجاد کرده بودیم. پس عملا باید یک لیست به کاربر نشان داده شود که تا از آن لیست، نوع را انتخاب کند. میتوانیم بیایم همینجا در داخل View مربوطه، بهجای استفاده از HTML Helper پیشفرض، از DropDownList یا EnumFor استفاده کنیم و به طریقی این لیست را ایجاد کنیم. ولی چون قرار است در این مثال به شرح موضوع مقاله خودمان بپردازیم، این کار را انجام نمیدهیم.
در حقیقیت میخوایم متد EditorFor را طوری سفارشی سازی کنیم که برای نوع شمارشی Genre، به صورت خودکار یک لیست ایجاد کرده و برگرداند. از نسخهی سوم ASP.NET MVC به بعد این امکان برای توسعه دهندهها فراهم شدهاست. شما میتوانید در پوشهی Shared داخل پوشه Views برنامه، پوشهای را به اسم EditorTemplates ایجاد کنید؛ همینطور DisplayTemplates و برای نوع خاصی که میخواهید سفارشیسازی را برای آن انجام دهید، یک PartialView بسازید.
Views/Shared/DisplayTemplates/<type>.cshtml
کاری که الان میخواهیم انجام دهیم این است که یک SelectListItem ایجاد کرده تا مقدارهای نوع Genreمان داخلش باشد و بتوانیم به راحتی برای ساختن DropDownList از آن استفاده کنیم. برای این کار Helper مخصوص خودمان را ایجاد میکنیم. پوشهای به اسم Helpers در کنار پوشههای Controllers، Models ایجاد میکنیم و در داخل آن کلاسی به اسم EnumHelpers میسازیم.
public static class EnumHelpers { public static IEnumerable<SelectListItem> GetItems( this Type enumType, int? selectedValue) { if (!typeof(Enum).IsAssignableFrom(enumType)) { throw new ArgumentException("Type must be an enum"); } var names = Enum.GetNames(enumType); var values = Enum.GetValues(enumType).Cast<int>(); var items = names.Zip(values, (name, value) => new SelectListItem { Text = GetName(enumType, name), Value = value.ToString(), Selected = value == selectedValue } ); return items; } static string GetName(Type enumType, string name) { var result = name; var attribute = enumType .GetField(name) .GetCustomAttributes(inherit: false) .OfType<DisplayAttribute>() .FirstOrDefault(); if (attribute != null) { result = attribute.GetName(); } return result; } }
در توضیح کد بالا عنوان کرد که متدها بهصورت متدهای الحاقی به نوع Type نوشته شدند. کار خاصی در بدنهی متدها انجام نشدهاست. در بدنهی متد اول لیست آیتمها را تولید کردیم. در هنگام ساخت SelectListItem برای گرفتن Text، متد GetName را صدا زدیم. برای اینکه بتوانیم مقدار ویژگی Display که در هنگام تعریف نوع شمارشی استفاده کردیم را بدست بیاریم، باید چک کنیم ببینیم که آیا این آیتم به این ویژگی مزین شدهاست یا نه. اگر شده بود مقدار را میگیریم و به خصوصیت Text متد اول انتساب میدهیم.
@using Book.Entities @using Book.Web.Helpers @{ var items = typeof(Genre).GetItems((int?)Model); } @Html.DropDownList("", items, new {@class="form-control"})
کدهایی که در بالا مشاهده میکنید کدهایی میباشند که قرار است داخل PartialViewی Genre قرار دهیم که در پوشهی EditorTemplates ساختیم. ابتدا آمدیم آیتمها را گرفتیم و بعد به DropDownList دادیم تا لیست نوع را برای ما بسازد. حالا اگه برنامه را اجرا کنید میبینید که EditorFor برای شما یه لیست از نوع شمارشی ساخته و حالا قابل استفاده هست.
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید