مطالب
بیرون نگاه داشتن تنظیمات خصوصی از سورس کنترل
برخی از تنظیمات پروژه نباید به مخازن سورس کنترل ارسال شوند؛ حال یا نیازی به این کار نیست یا مقادیر تنظیمات محرمانه هستند. چند بار پیش آمده‌است که پروژه را از سورس کنترل دریافت و مجبور شده باشید رشته‌های اتصال و دیگر تنظیمات را مجددا ویرایش کنید، چرا که توسعه دهندگان دیگری مثلا فایل‌های Web/App.config خود را به اشتباه push کرده اند؟ حتی اگر تنظیمات پروژه محرمانه هم نباشند (مثلا پسورد دیتابیس‌ها یا ایمیل ها) این موارد می‌توانند دردسر ساز شوند. بدتر از اینها هنگامی است که تنظیمات محرمانه را به مخازنی عمومی (مثلا GitHub) ارسال می‌کنید!

یک فایل web.config معمولی را در نظر بگیرید (اطلاعات غیر ضروری حذف شده اند).

<?xml version="1.0" encoding="utf-8"?>
<!--
  A bunch of ASP.NET MVC web config stuff goes here . . . 
  -->
<configuration>
  <connectionStrings>
    <add name="DefaultConnection" value="YourConnectionStringAndPassword"/>
  </connectionStrings>

  <appSettings file="PrivateSettings.config">
    <add key="owin:AppStartup" value="AspNetIdentity2ExtendingApplicationUser.Startup,AspNetIdentity2ExtendingApplicationUser" />
    <add key="webpages:Version" value="3.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
    <add key="EMAIL_PASSWORD" value="YourEmailPassword"/>
  </appSettings>
</configuration>
در تنظیمات بالا یک رشته اتصال وجود دارد که ترجیحا نمی‌خواهیم به سورس کنترل ارسال کنیم، و یا اینکه این رشته اتصال بین توسعه دهندگان مختلف متفاوت است.
همچنین کلمه عبور یک ایمیل هم وجود دارد که نمی‌خواهیم به مخازن سورس کنترل ارسال شود، و مجددا ممکن است مقدارش بین توسعه دهندگان متفاوت باشد.
از طرفی بسیاری از تنظیمات این فایل متعلق به کل اپلیکیشن است، بنابراین صرفنظر کردن از کل فایل web.config در سورس کنترل گزینه جالبی نیست.

خوشبختانه کلاس ConfigurationManager راه حل هایی پیش پای ما می‌گذارد.

استفاده از خاصیت configSource برای انتقال قسمت هایی از تنظیمات به فایلی مجزا
با استفاده از خاصیت configSource می‌توانیم قسمتی از تنظیمات (configuration section) را به فایلی مجزا منتقل کنیم. بعنوان مثال، رشته‌های اتصال از مواردی هستند که می‌توانند بدین صورت تفکیک شوند.

بدین منظور می‌توانیم فایل تنظیمات جدیدی (مثلا با نام connectionStrings.config) ایجاد کنیم و سپس با استفاده از خاصیت نام برده در فایل web.config به آن ارجاع دهیم. برای این کار فایل تنظیمات جدیدی ایجاد کنید و مقادیر زیر را به آن اضافه کنید (xml header یا هیچ چیز دیگری نباید در این فایل وجود داشته باشد، تنها مقادیر تنظیمات).
<connectionStrings>
  <add name="DefaultConnection" value="YourConnectionStringAndPassword"/>
</connectionStrings>
حال باید فایل web.config را ویرایش کنیم. رشته‌های اتصال را حذف کنید و با استفاده از خاصیت configSource تنها به فایل تنظیمات اشاره کنید.
<connectionStrings configSource="ConnectionStrings.config">
</connectionStrings>
دسترسی به رشته‌های اتصال مانند گذشته انجام می‌شود. به بیان دیگر تمام تنظیمات موجود (حال مستقیم یا ارجاع شده) همگی بصورت یکپارچه دریافت شده و به کد کلاینت تحویل می‌شوند.
var conn = ConfigurationManager.ConnectionStrings["DefaultConnection"];
string connString = conn.ConnectionString;
// etc.
در قطعه کد بالا، دسترسی به رشته‌های اتصال بر اساس نام، آبجکتی از نوع ConnectionStringSettings را بر می‌گرداند. خاصیت configSource برای هر قسمت از تنظیمات پیکربندی می‌تواند استفاده شود.


استفاده از خاصیت file برای انتقال بخشی از تنظیمات به فایلی مجزا
ممکن است فایل تنظیمات شما (مثلا web.config) شامل مقادیری در قسمت <appSettings> باشد که برای کل پروژه تعریف شده اند (global) اما برخی از آنها محرمانه هستند و باید از سورس کنترل دور نگاه داشته شوند. در این سناریو‌ها خاصیتی بنام file وجود دارد که مختص قسمت appSettings است و به ما اجازه می‌دهد مقادیر مورد نظر را به فایلی مجزا انتقال دهیم. هنگام دسترسی به مقادیر این قسمت تمام تنظیمات بصورت یکجا خوانده می‌شوند.

در مثال جاری یک کلمه عبور ایمیل داریم که می‌خواهیم محرمانه بماند. بدین منظور می‌توانیم فایل پیکربندی جدیدی مثلا با نام PrivateSettings.config ایجاد کنیم. این فایل هم نباید xml header یا اطلاعات دیگری داشته باشد، تنها مقادیر appSettings را در آن نگاشت کنید.
<appSettings>
  <add key="MAIL_PASSWORD" value="xspbqmurkjadteck"/>
</appSettings>
حال تنظیمات کلمه عبور را از فایل web.config حذف کنید و با استفاده از خاصیت file، به فایل جدید اشاره کنید.
<appSettings file="PrivateSettings.config">
  <add key="owin:AppStartup" value="AspNetIdentity2ExtendingApplicationUser.Startup,AspNetIdentity2ExtendingApplicationUser" />
  <add key="webpages:Version" value="3.0.0.0" />
  <add key="webpages:Enabled" value="false" />
  <add key="ClientValidationEnabled" value="true" />
  <add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
دسترسی به تنظیمات appSettings مانند گذشته انجام می‌شود. همانطور که گفته شد ConfigurationManager بصورت خودکار اینگونه ارجاعات را تشخیص داده و تمام اطلاعات را بصورت یکجا در اختیار client code قرار می‌دهد.
var pwd = ConfigurationManager.AppSettings["MAIL_PASSWORD"];

فایل‌های ویژه را به gitignore. اضافه کنید
حال می‌توانیم فایل web.config را به سورس کنترل اضافه کنیم، فایل‌های ConnectionStrings.config و PrivateSettings.config را به فایل gitignore. اضافه کنیم و پروژه را commit کنیم. در این صورت فایل‌های تنظیمات خصوصی به مخازن سورس کنترل ارسال نخواهند شد.

مستند سازی را فراموش نکنید!
مسلما اگر چنین رویکردی را در پیش بگیرید باید دیگران را از آن مطلع کنید (مثلا با افزودن توضیحاتی به فایل README.txt). بهتر است در فایل web.config خود هرجا که لازم است توضیحات XML خود را درج کنید و به توسعه دهندگان توضیح دهید که چه فایل هایی را روی نسخه‌های محلی خود باید ایجاد کنند و هر کدام از این فایل‌ها چه محتوایی باید داشته باشند.
مطالب
ASP.NET MVC #12

تولید خودکار فرم‌های ورود و نمایش اطلاعات در ASP.NET MVC بر اساس اطلاعات مدل‌ها

در الگوی MVC، قسمت M یا مدل آن یک سری ویژگی‌های خاص خودش را دارد:
شما را وادار نمی‌کند که مدل را به نحو خاصی طراحی کنید. شما را مجبور نمی‌کند که کلاس‌های مدل را برای نمونه همانند کلاس‌های کنترلرها، از کلاس خاصی به ارث ببرید. یا حتی در مورد نحوه‌ی دسترسی به داده‌ها نیز، نظری ندارد. به عبارتی برنامه نویس است که می‌تواند بر اساس امکانات مهیای در کل اکوسیستم دات نت، در این مورد آزادانه تصمیم گیری کند.
بر همین اساس ASP.NET MVC یک سری قرارداد را برای سهولت اعتبار سنجی یا تولید بهتر رابط کاربری بر اساس اطلاعات مدل‌ها، فراهم آورده است. این قراردادها هم چیزی نیستند جز یک سری metadata که نحوه‌ی دربرگیری اطلاعات را در مدل‌ها توضیح می‌دهند. برای دسترسی به آن‌ها پروژه جاری باید ارجاعی را به اسمبلی‌های System.ComponentModel.DataAnnotations.dll و System.Web.Mvc.dll داشته باشد (که VS.NET به صورت خودکار در ابتدای ایجاد پروژه اینکار را انجام می‌دهد).

یک مثال کاربردی

یک پروژه جدید خالی ASP.NET MVC را آغاز کنید. در پوشه مدل‌های آن، مدل اولیه‌ای را با محتوای زیر ایجاد نمائید:

using System;

namespace MvcApplication8.Models
{
public class Employee
{
public int Id { set; get; }
public string Name { set; get; }
public decimal Salary { set; get; }
public string Address { set; get; }
public bool IsMale { set; get; }
public DateTime AddDate { set; get; }
}
}

سپس یک کنترلر جدید را هم به نام EmployeeController با محتوای زیر به پروژه اضافه نمائید:

using System;
using System.Web.Mvc;
using MvcApplication8.Models;

namespace MvcApplication8.Controllers
{
public class EmployeeController : Controller
{
public ActionResult Create()
{
var employee = new Employee { AddDate = DateTime.Now };
return View(employee);
}
}
}

بر روی متد Create کلیک راست کرده و یک View ساده را برای آن ایجاد نمائید. سپس محتوای این View را به صورت زیر تغییر دهید:

@model MvcApplication8.Models.Employee
@{
ViewBag.Title = "Create";
}

<h2>Create An Employee</h2>

@using (Html.BeginForm(actionName: "Create", controllerName: "Employee"))
{
@Html.EditorForModel()
<input type="submit" value="Save" />
}

اکنون اگر پروژه را اجرا کرده و مسیر http://localhost/employee/create را وارد نمائید، یک صفحه ورود اطلاعات تولید شده به صورت خودکار را مشاهده خواهید کرد. متد Html.EditorForModel بر اساس اطلاعات خواص عمومی مدل، یک فرم خودکار را تشکیل می‌دهد.
البته فرم تولیدی به این شکل شاید آنچنان مطلوب نباشد، از این جهت که برای مثال Id را هم لحاظ کرده، در صورتیکه قرار است این Id توسط بانک اطلاعاتی انتساب داده شود و نیازی نیست تا کاربر آن‌را وارد نماید. یا مثلا برچسب AddDate نباید به این شکل صرفا بر اساس نام خاصیت متناظر با آن تولید شود و مواردی از این دست. به عبارتی نیاز به سفارشی سازی کار این فرم ساز توکار ASP.NET MVC وجود دارد که ادامه بحث جاری را تشکیل خواهد داد.



سفارشی سازی فرم ساز توکار ASP.NET MVC با کمک Metadata خواص

برای اینکه بتوان نحوه نمایش فرم خودکار تولید شده را سفارشی کرد، می‌توان از یک سری attribute و data annotations توکار دات نت و ASP.NET MVC استفاده کرد و نهایتا این metadata توسط فریم ورک، مورد استفاده قرار خواهند گرفت. برای مثال:

using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace MvcApplication8.Models
{
public class Employee
{
//[ScaffoldColumn(false)]

[HiddenInput(DisplayValue=false)]
public int Id { set; get; }

public string Name { set; get; }

[DisplayName("Annual Salary ($)")]
public decimal Salary { set; get; }

public string Address { set; get; }

[DisplayName("Is Male?")]
public bool IsMale { set; get; }

[DisplayName("Start Date")]
[DataType(DataType.Date)]
public DateTime AddDate { set; get; }
}
}

در اینجا به کمک ویژگی HiddenInput از نمایش عمومی خاصیت Id جلوگیری خواهیم کرد یا توسط ویژگی DisplayName، برچسب دلخواه خود را به عناصر فرم تشکیل شده، انتساب خواهیم داد. اگر نیاز باشد تا خاصیتی کلا از رابط کاربری حذف شود می‌توان از ویژگی ScaffoldColumn با مقدار false استفاده کرد. یا توسط DataType، مشخص کرده‌ایم که نوع ورودی فقط قرار است Date باشد و نیازی به قسمت Time آن نداریم.
DataType شامل نوع‌های از پیش تعریف شده دیگری نیز هست. برای مثال اگر نیاز به نمایش TextArea بود از مقدار MultilineText، ‌استفاده کنید:

[DataType(DataType.MultilineText)]

یا برای نمایش PasswordBox از مقدار Password می‌توان کمک گرفت. اگر نیاز دارید تا آدرس ایمیلی به شکل یک لینک mailto نمایش داده شود از مقدار EmailAddress استفاده کنید. به کمک مقدار Url، متن خروجی به صورت خودکار تبدیل به یک آدرس قابل کلیک خواهد شد.
اکنون اگر پروژه را مجددا کامپایل کنیم و به آدرس ایجاد یک کارمند جدید مراجعه نمائیم، با رابط کاربری بهتری مواجه خواهیم شد.



سفارشی سازی ظاهر فرم ساز توکار ASP.NET MVC

در ادامه اگر بخواهیم ظاهر این فرم را اندکی سفارشی‌تر کنیم، بهتر است به سورس صفحه تولیدی در مرورگر مراجعه کنیم. در اینجا یک سری عناصر HTML محصور شده با div را خواهیم یافت. هر کدام از این‌ها هم با classهای css خاص خود تعریف شده‌اند. بنابراین اگر علاقمند باشیم که رنگ و قلم و غیره این موارد تغییر دهیم، تنها کافی است فایل css برنامه را ویرایش کنیم و نیازی به دستکاری مستقیم کدهای برنامه نیست.



انتساب قالب‌های سفارشی به خواص یک شیء

تا اینجا در مورد نحوه سفارشی سازی رنگ، قلم، برچسب و نوع داده‌های هر کدام از عناصر نهایی نمایش داده شده، توضیحاتی را ملاحظه نمودید.
در فرم تولیدی نهایی، خاصیت bool تعریف شده به صورت خودکار به یک checkbox تبدیل شده است. چقدر خوب می‌شد اگر امکان تبدیل آن مثلا به RadioButton انتخاب مرد یا زن بودن کارمند ثبت شده در سیستم وجود داشت. برای اصلاح یا تغییر این مورد، باز هم می‌توان از متادیتای خواص، جهت تعریف قالبی خاص برای هر کدام از خواص مدل استفاده کرد.
به پوشه Views/Shared مراجعه کرده و یک پوشه جدید به نام EditorTemplates را ایجاد نمائید. بر روی این پوشه کلیک راست کرده و گزینه Add view را انتخاب کنید. در صفحه باز شده، گزینه «Create as a partial view» را انتخاب نمائید و نام آن‌را هم مثلا GenderOptions وارد کنید. همچنین گزینه «Create a strongly typed view» را نیز انتخاب کنید. مقدار Model class را مساوی bool وارد نمائید. فعلا یک hello داخل این صفحه جدید وارد کرده و سپس خاصیت IsMale را به نحو زیر تغییر دهید:

[DisplayName("Gender")]
[UIHint("GenderOptions")]
public bool IsMale { set; get; }

توسط ویژگی UIHint، می‌توان یک خاصیت را به یک partial view متصل کرد. در اینجا خاصیت IsMale به partial view ایی به نام GenderOptions متصل شده است. اکنون اگر برنامه را کامپایل و اجرا کرده و آدرس ایجاد یک کارمند جدید را ملاحظه کنید، بجای Checkbox باید یک hello نمایش داده شود.
محتویات این Partial view هم نهایتا به شکل زیر خواهند بود:

@model bool
<p>@Html.RadioButton("", false, !Model) Female</p>
<p>@Html.RadioButton("", true, Model) Male</p>

در اینجا Model که از نوع bool تعریف شده، به خاصیت IsMale اشاره خواهد کرد. دو RadioButton هم برای انتخاب بین حالت زن و مرد تعریف شده‌اند.

یا یک مثال جالب دیگر در این زمینه می‌تواند تبدیل enum به یک Dropdownlist باشد. در این حالت partial view ما شکل زیر را خواهد یافت:

@model Enum
@Html.DropDownListFor(m => m, Enum.GetValues(Model.GetType())
.Cast<Enum>()
.Select(m => {
string enumVal = Enum.GetName(Model.GetType(), m);
return new SelectListItem() {
Selected = (Model.ToString() == enumVal),
Text = enumVal,
Value = enumVal
};
}))

و برای استفاده از آن، از ویژگی زیر می‌توان کمک گرفت (مزین کردن خاصیتی از نوع یک enum دلخواه، جهت تبدیل خودکار آن به یک دراپ داون لیست):

[UIHint("Enum")]


سایر متدهای کمکی تولید و نمایش خودکار اطلاعات از روی اطلاعات مدل‌های برنامه

متدهای دیگری نیز در رده‌ی Templated helpers قرار می‌گیرند. اگر از متد Html.EditorFor استفاده کنیم، از تمام این اطلاعات متادیتای تعریف شده نیز استفاده خواهد کرد. همانطور که در قسمت قبل (قسمت 11) نیز توضیح داده شد، صفحه استاندارد Add view در VS.NET به همراه یک سری قالب تولید فرم‌های Create و Edit هم هست که دقیقا کد نهایی تولیدی را بر اساس همین متد تولید می‌کند.
استفاده از Html.EditorFor انعطاف پذیری بیشتری را به همراه دارد. برای مثال اگر یک طراح وب، طرح ویژه‌ای را در مورد ظاهر فرم‌های سایت به شما ارائه دهد، بهتر است از این روش استفاده کنید. اما خروجی نهایی Html.EditorForModel به کمک تعدادی متادیتا و اندکی دستکاری CSS، از دیدگاه یک برنامه نویس بی نقص است!
به علاوه، متد Html.DisplayForModel نیز مهیا است. بجای اینکه کار تولید رابط کاربری اطلاعات نمایش جزئیات یک شیء را انجام دهید، اجازه دهید تا متد Html.DisplayForModel اینکار را انجام دهد. سفارشی سازی آن نیز همانند قبل است و بر اساس متادیتای خواص انجام می‌شود. در این حالت، مسیر پیش فرض جستجوی قالب‌های UIHint آن، Views/Shared/DisplayTemplates می‌باشد. همچنین Html.DisplayFor نیز جهت کار با یک خاصیت مدل تدارک دیده شده است. البته باید درنظر داشت که استفاده از پوشه Views/Shared اجباری نیست. برای مثال اگر از پوشه Views/Home/DisplayTemplates استفاده کنیم، قالب‌های سفارشی تهیه شده تنها جهت Viewهای کنترلر home قابل استفاده خواهند بود.
یکی دیگر از ویژگی‌هایی که جهت سفارشی سازی نحوه نمایش خودکار اطلاعات می‌تواند مورد استفاده قرار گیرد، DisplayFormat است. برای مثال اگر مقدار خاصیت در حال نمایش نال بود، می‌توان مقدار دیگری را نمایش داد:

[DisplayFormat(NullDisplayText = "-")]

یا اگر علاقمند بودیم که فرمت اطلاعات در حال نمایش را تغییر دهیم، به نحو زیر می‌توان عمل کرد:

[DisplayFormat(DataFormatString  = "{0:n}")]

مقدار DataFormatString در پشت صحنه در متد string.Format مورد استفاده قرار می‌گیرد.
و اگر بخواهیم که این ویژگی در حالت تولید فرم ویرایش نیز درنظر گرفته شود، می‌توان خاصیت ApplyFormatInEditMode را نیز مقدار دهی کرد:

[DisplayFormat(DataFormatString  = "{0:n}", ApplyFormatInEditMode = true)]



بازنویسی قالب‌های پیش فرض تولید فرم یا نمایش اطلاعات خودکار ASP.NET MVC

یکی دیگر از قرارداهای بکارگرفته شده در حین استفاده از قالب‌های سفارشی، استفاده از نام اشیاء می‌باشد. مثلا در پوشه Views/Shared/DisplayTemplates، اگر یک Partial view به نام String.cshtml وجود داشته باشد، از این پس نحوه رندر کلیه خواص رشته‌ای تمام مدل‌ها، بر اساس محتوای فایل String.cshtml مشخص می‌شود؛ به همین ترتیب در مورد datetime و سایر انواع مهیا.
برای مثال اگر خواستید تمام تاریخ‌های میلادی دریافتی از بانک اطلاعاتی را شمسی نمایش دهید، فقط کافی است یک فایل datetime.cshtml سفارشی را تولید کنید که Model آن تاریخ میلادی دریافتی است و نهایتا کار این Partial view، رندر تاریخ تبدیل شده به همراه تگ‌های سفارشی مورد نظر می‌باشد. در این حالت نیازی به ذکر ویژگی UIHint نیز نخواهد بود و همه چیز خودکار است.
به همین ترتیب اگر نام مدل ما Employee باشد و فایل Partial view ایی به نام Employee.cshtml در پوشه Views/Shared/DisplayTemplates قرار گیرد، متد Html.DisplayForModel به صورت پیش فرض از محتوای این فایل جهت رندر اطلاعات نمایش جزئیات شیء Employee استفاده خواهد کرد.
داخل Partial viewهای سفارشی تعریف شده به کمک خاصیت ViewData.TemplateInfo.FormattedModelValue مقدار نهایی فرمت شده قابل استفاده را فراهم می‌کند. این مورد هم از این جهت حائز اهمیت است که نیازی نباشد تا ویژگی DisplayFormat را به صورت دستی پردازش کنیم. همچنین اطلاعات ViewData.ModelMetadata نیز دراینجا قابل دسترسی هستند.



سؤال: Partial View چیست؟

همانطور که از نام Partial view بر‌می‌آید، هدف آن رندر کردن قسمتی از صفحه است به همراه استفاده مجدد از کدهای تولید رابط کاربری در چندین و چند View؛ چیزی شبیه به User controls در ASP.NET Web forms البته با این تفاوت که Page life cycle و Code behind و سایر موارد مشابه آن در اینجا حذف شده‌اند. همچنین از Partial viewها برای به روز رسانی قسمتی از صفحه حین فراخوانی‌های Ajaxایی نیز استفاده می‌شود. مهم‌ترین کاربرد Partial views علاوه بر استفاده مجدد از کدها، خلوت کردن Viewهای شلوغ است جهت ساده‌تر سازی نگهداری آن‌ها در طول زمان (یک نوع Refactoring فایل‌های View محسوب می‌شوند).
پسوند این فایل‌ها نیز بسته به موتور View مورد استفاده تعیین می‌شود. برای مثال حین استفاده از Razor، پسوند Partial views همان cshtml یا vbhtml می‌باشد. یا اگر از web forms view engine استفاده شود، پسوند آن‌ها ascx است (همانند User controls در وب فرم‌ها).
البته چون در حالت استفاده از موتور Razor، پسوند View و Partial viewها یکی است، مرسوم شده است که نام Partial viewها را با یک underline شروع کنیم تا بتوان بین این دو تمایز قائل شد.
اگر این فایل‌ها را در پوشه Views/Shared تعریف کنیم، در تمام Viewها قابل استفاده خواهند بود. اما اگر مثلا در پوشه Views/Home آن‌هارا قرار دهیم، تنها در Viewهای متعلق به کنترلر Home، قابل بکارگیری می‌باشند.
Partial views را نیز می‌توان strongly typed تعریف کرد و به این ترتیب با مشخص سازی دقیق نوع model آن، علاوه بر بهره‌مندی از Intellisense خودکار، رندر آن‌را نیز تحت کنترل کامپایلر قرار داد.
مقدار Model در یک View بر اساس اطلاعات مدلی که به آن ارسال شده است تعیین می‌گردد. اما در یک Partial view که جزئی از یک View را نهایتا تشکیل خواهد داد، بر اساس مقدار ارسالی از طریق View معین می‌گردد.

یک مثال
در ادامه قصد داریم کد حلقه نمایش لیستی از عناصر تولید شده توسط VS.NET را به یک Partial view منتقل و Refactor کنیم.
ابتدا یک منبع داده فرضی زیر را در نظر بگیرید:
using System;
using System.Collections.Generic;

namespace MvcApplication8.Models
{
public class Employees
{
public IList<Employee> CreateEmployees()
{
return new[]
{
new Employee { Id = 1, AddDate = DateTime.Now.AddYears(-3), Name = "Emp-01", Salary = 3000},
new Employee { Id = 2, AddDate = DateTime.Now.AddYears(-2), Name = "Emp-02", Salary = 2000},
new Employee { Id = 3, AddDate = DateTime.Now.AddYears(-1), Name = "Emp-03", Salary = 1000}
};
}
}
}

سپس از آن در یک کنترلر برای بازگشت لیستی از کارکنان استفاده خواهیم کرد:

public ActionResult EmployeeList()
{
var list = new Employees().CreateEmployees();
return View(list);
}

View متناظر با این متد را هم با کلیک راست بر روی متد، انتخاب گزینه Add view و سپس ایجاد یک strongly typed view از نوع کلاس Employee، ایجاد خواهیم کرد.
در ادامه قصد داریم بدنه حلقه زیر را refactor کنیم و آن‌را به یک Parial view منتقل نمائیم تا View ما اندکی خلوت‌تر و مفهوم‌تر شود:

@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Salary)
</td>
<td>
@Html.DisplayFor(modelItem => item.Address)
</td>
<td>
@Html.DisplayFor(modelItem => item.IsMale)
</td>
<td>
@Html.DisplayFor(modelItem => item.AddDate)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
@Html.ActionLink("Details", "Details", new { id=item.Id }) |
@Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}

سپس بر روی پوشه Views/Employee کلیک راست کرده و گزینه Add|View را انتخاب کنید. در اینجا نام _EmployeeItem را وارد کرده و همچنین گزینه Create as a partial view و create a strongly typed view را نیز انتخاب کنید. نوع مدل هم Employee خواهد بود. به این ترتیب فایل زیر تشکیل خواهد شد:
\Views\Employee\_EmployeeItem.cshtml

ابتدای نام فایل‌را با underline شروع کرده‌ایم تا بتوان بین Viewها و Partial views تفاوت قائل شد. همچنین این Partial view چون داخل پوشه Employee تعریف شده، فقط در Viewهای کنترلر Employee در دسترس خواهد بود.
در ادامه کل بدنه حلقه فوق را cut کرده و در این فایل جدید paste نمائید. مرحله اول refactoring یک view به همین نحو آغاز می‌شود. البته در این حالت قادر به استفاده از Partial view نخواهیم بود چون اطلاعاتی که به این فایل ارسال می‌گردد و مدلی که در دسترس آن است از نوع Employee است و نه لیستی از کارمندان. به همین جهت باید item را با Model جایگزین کرد:

@model MvcApplication8.Models.Employee

<tr>
<td>
@Html.DisplayFor(x => x.Name)
</td>
<td>
@Html.DisplayFor(x => x.Salary)
</td>
<td>
@Html.DisplayFor(x => x.Address)
</td>
<td>
@Html.DisplayFor(x => x.IsMale)
</td>
<td>
@Html.DisplayFor(x => x.AddDate)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
@Html.ActionLink("Details", "Details", new { id = Model.Id }) |
@Html.ActionLink("Delete", "Delete", new { id = Model.Id })
</td>
</tr>


سپس برای استفاده از این Partial view در صفحه نمایش لیست کارمندان خواهیم داشت:

@foreach (var item in Model) {
@Html.Partial("_EmployeeItem", item)
}

متد Html.Partial، اطلاعات یک Partial view را پردازش و تبدیل به یک رشته کرده و در اختیار Razor قرار می‌دهد تا در صفحه نمایش داده شود. پارامتر اول آن نام Partial view مورد نظر است (نیازی به ذکر پسوند فایل نیست) و پارامتر دوم، اطلاعاتی است که به آن ارسال خواهد شد.
متد دیگری هم وجود دارد به نام Html.RenderPartial. کار این متد نوشتن مستقیم در Response است، برخلاف Html.Partial که فقط یک رشته را بر می‌گرداند.



نمایش اطلاعات از کنترلر‌های مختلف در یک صفحه

Html.Partial بر اساس اطلاعات مدل ارسالی از یک کنترلر، کار رندر قسمتی از آن‌را در یک View خاص عهده دار خواهد شد. اما اگر بخواهیم مثلا در یک صفحه یک قسمت را به نمایش آخرین اخبار و یک قسمت را به نمایش آخرین وضعیت آب و هوا اختصاص دهیم، از روش دیگری به نام RenderAction می‌توان کمک گرفت. در اینجا هم دو متد Html.Action و Html.RenderAction وجود دارند. اولی یک رشته را بر می‌گرداند و دومی اطلاعات را مستقیما در Response درج می‌کند.

یک مثال:
کنترلر جدیدی را به نام MenuController به پروژه اضافه کنید:
using System.Web.Mvc;

namespace MvcApplication8.Controllers
{
public class MenuController : Controller
{
[ChildActionOnly]
public ActionResult ShowMenu(string options)
{
return PartialView(viewName: "_ShowMenu", model: options);
}
}
}

سپس بر روی نام متد کلیک راست کرده و گزینه Add view را انتخاب کنید. در اینجا قصد داریم یک partial view که نامش با underline شروع می‌شود را اضافه کنیم. مثلا با محتوای زیر ( با توجه به اینکه مدل ارسالی از نوع رشته‌ای است):

@model string

<ul>
<li>
@Model
</li>
</ul>

حین فراخوانی متد Html.Action، یک متد در یک کنترلر فراخوانی خواهد شد (که شامل ارائه درخواست و طی سیکل کامل پردازشی آن کنترلر نیز خواهد بود). سپس آن متد با بازگشت دادن یک PartialView، اطلاعات پردازش شده یک partial view را به فراخوان بازگشت می‌دهد. اگر نامی ذکر نشود، همان نام متد در نظر گرفته خواهد شد. البته از آنجائیکه در این مثال در ابتدای نام Partial view یک underline قرار دادیم، نیاز خواهد بود تا این نام صریحا ذکر گردد (چون دیگر هم نام متد یا ActionName آن نیست). ویژگی ChildActionOnly سبب می‌شود تا این متد ویژه تنها از طریق فراخوانی Html.Action در دسترس باشد.
برای استفاده از آن هم در Viewایی دیگر خواهیم داشت:

@Html.Action(actionName: "ShowMenu", controllerName: "Menu", 
routeValues: new { options = "some data..." })

در اینجا هم پارامتر ارسالی به کمک anonymously typed objects مشخص و مقدار دهی شده است.


سؤال مهم: چه تفاوتی بین RenderPartial و RenderAction وجود دارد؟ به نظر هر دو یک کار را انجام می‌دهند، هر دو مقداری HTML را پس از پرداش به صفحه تزریق می‌کنند.
پاسخ: اگر View والد، دارای کلیه اطلاعات لازم جهت نمایش اطلاعات Partial view است، از RenderPartial استفاده کنید. به این ترتیب برخلاف حالت RenderAction درخواست جدیدی به ASP.NET Pipeline صادر نشده و کارآیی نهایی بهتر خواهد بود. صرفا یک الحاق ساده به صفحه انجام خواهد شد.
اما اگر برای رندر کردن این قسمت از صفحه که قرار است اضافه شود، نیاز به دریافت اطلاعات دیگری خارج از اطلاعات مهیا می‌باشد، از روش RenderAction استفاده کنید. برای مثال اگر در صفحه جاری قرار است لیست پروژه‌ها نمایش داده شود و در کنار صفحه مثلا منوی خاصی باید قرار گیرد، اطلاعات این منو در View جاری فراهم نیست (و همچنین مرتبط به آن هم نیست). بنابراین از روش RenderAction برای حل این مساله می‌توان کمک گرفت.
به صورت خلاصه برای نمایش اطلاعات تکراری در صفحات مختلف سایت در حالتیکه این اطلاعات از قسمت‌های دیگر صفحه ایزوله است (مثلا نمایش چند ویجت مختلف در صفحه)، روش RenderAction ارجحیت دارد.


یک نکته
فراخوانی متدهای RenderAction و RenderPartial در حین کار با Razor باید به شکل فراخوانی یک متد داخل {} باشند:

@{ Html.RenderAction("About"); }
And not @Html.RenderAction("About")

علت این است که @ به تنهایی به معنای نوشتن در Response است. متد RenderAction هم خروجی ندارد و مستقیما در Response اطلاعات خودش را درج می‌کند. بنابراین این دو با هم همخوانی ندارند و باید به شکل یک متد معمولی با آن رفتار کرد.
اگر حجم اطلاعاتی که قرار است در صفحه درج شود بالا است، متدهای RenderAction و RenderPartial نسبت به Html.Action و Html.Partial کارآیی بهتری دارند؛ چون یک مرحله تبدیل کل اطلاعات به رشته و سپس درج نتیجه در Response، در آن‌ها حذف شده است.


نظرات اشتراک‌ها
تحریم شکن بگذر!
اگه به وب سایتش مراجعه کنین گفته شده که سایتهای که ما رو تحریم کردن مثل Google Developer  باز میشن نه سایتهایی که از داخل فیلتر شدن.
من گوگل رو تست کردم و بدون مشکل در دسترس قرار گرفت. همونطور که توی وب سایتشون گفته شده باید DNS‌ها رو بر روی «کانکشن اینترنت» تون ست کنین
نظرات مطالب
مدیریت سفارشی سطوح دسترسی کاربران در MVC
دو مطلب هست. یکی اینکه اگر نیاز به ID کاربر داشتید، این مورد همیشه در User.Identity.Name موجود هست و زمانیکه در حین لاگین انتساب داده شد، در کوکی رمزنگاری شده آن قرار می‌گیره. یعنی واکشی از دیتابیس نداره. ضمنا RoleProvider استفاده شده هم زمانیکه در وب کانفیگ تنظیم میشه، مقدار cacherolesincookie=true داره (در مقاله هست). یعنی این هم کش میشه و هربار از دیتابیس واکشی نمیشه.
مطالب
معماری میکروسرویس‌ها
برنامه‌های بزرگ سمت سرور که با تعداد بسیار زیادی کاربر و داده سر و کار دارند، نباید فقط درگیر پاسخگویی سریع و فراهم کردن وب سرویس‌ها برای پلت‌فرم‌های مختلف باشند. این برنامه‌ها باید بتوانند به سادگی رشد کرده، ارتقاء پیدا کنند و به روز شوند. برای ساخت و توسعه این نوع برنامه‌ها، دو مدل معماری وجود دارد: یکی  معماری Monolithic و دیگری معماری Microservices. برای شناخت معماری Microservices، ابتدا بایستی با معماری Monolithic آشنا شد.


 معماری Monolithic چیست؟ 

در معماری Monolithic بخش‌های مختلف برنامه سمت سرور از جمله پردازش پرداخت آنلاین، مدیریت حساب‌ها، اعلان‌ها و سایر بخش‌ها همگی در یک واحد منفرد جمع شده‌اند. به عبارتی اگر برنامه تحت وب که در سرور قرار دارد به صورت یک جا با تمام متعلقات خود برای پاسخ به درخواست‌های سمت کلاینت، کار با پایگاه داده و انجام سایر الگوریتم‌ها اجرا شود، این برنامه از معماری Monolithic استفاده میکند.


مشکلات معماری Monolithic

  •  در معماری Monolithic زمانیکه ترافیک برنامه در سمت سرور افزایش پیدا میکند، باید برای پاسخگویی، اندازه را افزایش داد. یعنی باید برنامه تحت وب خود را بر روی سرورهای مختلف مجددا اجرا نمود. بخشی به نام Load Balancer، وظیفه توزیع درخواست‌ها را به سرورهای مختلف که بر روی هر یک، یک نسخه از برنامه در حال اجرا است، به عهده دارد. بر اساس توضیحی که از این معماری ارایه شد، در هر یک از این اجرا‌ها، کل برنامه با تمام متعلقاتی که دارد، فارغ از اینکه به همه آنها نیاز است یا نه، از منابع سرور استفاده میکند.

  • در معماری Monolithic برنامه‌ها بر اساس یک زبان برنامه‌نویسی مشخص، برای یک فریم ورک مشخص نوشته می‌شوند. این برنامه‌ها اصطلاحا چند سکویی نیستند و کامپوننت‌های نوشته شده برای آنها فقط در فریم ورک جاری قابل استفاده مجدد هستند.
  • ممکن است برای هر تغییر ریز و درشت در برنامه‌های این معماری، نیاز به Build و Deploy مجدد کل برنامه باشد که احتمال از دسترس خارج شدن برنامه هم وجود دارد.
  • اگر بخشی از برنامه از کار بیافتد، ممکن است باعث از کار افتادن کل برنامه یا بخشهایی از آن شود. 


معماری Microservices

معماری Microservices راه نجات از مشکلات معماری Monolithic است. در معماری Microservices، برنامه سمت سرور به سرویس‌های مختلفی تقسیم میشود. هر سرویس یک فرآیند پردازشی مستقل است که به عنوان یکی از قابلیت‌های خاص برنامه سمت سرور به حساب می‌آید. به عنوان مثال یک سرویس وظیفه پرداخت‌ها را به عهده دارد و دیگری بطور مستقل برای مدیریت حساب‌ها استفاده می‌شود. برنامه‌های نوشته شده با این معماری اجباری برای اجرا شدن در سرورهای جداگانه را ندارند، مگر اینکه یک سرویس، شرایط خاصی از جمله مصرف بالای RAM یا نیاز به پردازش ویژه و زیاد در CPU را داشته باشد. در اینصورت بهتر است که سرویس از یک سرور مجزا اجرا شود. لازم است که سرویس‌ها در بستر شبکه با یکدیگر در ارتباط باشند. 

 در دیاگرام بالا میشود اینطور تصور کرد که Service1، یک وب سرور است که با مرورگر برای دریافت درخواست‌ها در ارتباط است و باقی سرویس‌ها حکم API  برای عملیات‌های مختلف را دارند. 


 ارزش معماری Microservices

  • از آنجایی که سرویس‌ها از طریق زبان مشترک شبکه با یکدیگر در ارتباط هستند، میشود آنها را با زبانهای برنامه‌نویسی مختلف و بر روی فریم‌فرک‌های متفاوت نوشت. 
  • بدیهی است که با این معماری، هر سرویس را میشود به صورت جداگانه ایجاد کرد و تغییر داد که باعث سرعت در به روزرسانی و فرآیند گسترش برنامه میشود.
  • مانیتور کردن سرویس‌ها ساده‌تر خواهد بود. از آنجایی که هر سرویس به صورت یک پردازش جداگانه اجرا خواهد شد، تعیین اینکه هر سرویس از چه منابعی و به چه اندازه‌ای استفاده میکند، آسان‌تر خواهد بود.
  • از آنجایی که این سرویس‌ها از طریق شبکه در تبادل هستند، میشود از آنها در سایر برنامه‌ها مجدداً استفاده کرد. 


افزایش یک سرویس خاص

 یکی از با ارزش‌ترین قابلیت‌های معماری Microservices، افزایش یک سرویس، که به عنوان مثال فقط یک وهله از آن در حال اجراست، به دو یا سه وهله جداگانه است؛ بدون آنکه نیاز باشد سرویس‌های در ارتباط با آنها نیز وهله سازیهای اضافه‌ای داشته باشند. این حالت در دیاگرام زیر قابل مشاهده است. 

 در دیاگرام بالا از سرویس یک، دو وهله، در دو سرور جداگانه ایجاد شده است که Load Balancer ترافیک ورودی را بین آنها تقسیم میکند. باقی سرویس‌ها به همان تعداد که بودند باقی می‌مانند.


مشکلات معماری Microservices

  • از آنجایی که برنامه‌های سمت سرور نوشته شده با این معماری به سرویس‌های مختلفی تقسیم میشوند، گسترش و تنظیمات آنها می‌تواند کاری وقت گیر و طاقت فرسایی باشد.
  • از آنجایی که ارتباط بین سرویس‌ها در بستر شبکه انجام می‌شود، انتظار کندی عملکرد سرویس‌ها دور از ذهن نیست.
  • به دلیل ارتباطات شبکه‌ای، احتمال آسیب پذیری‌های امنیتی در این نوع برنامه‌ها بیشتر است.
  • نوشتن سرویس‌هایی که در بستر شبکه با سایر سرویس‌ها در ارتباط هستند سختی و مشکلات خود را دارد. برنامه‌نویس در این شرایط، درگیر برقراری ارتباط، رمزگذاری داده‌ها در صورت نیاز و تبدیل آنها می‌شود.
  • به دلیل مجزا بودن بخش‌های مختلف برنامه، مانیتور کردن و ردیابی عملکرد سرویس‌ها، یکی از کارهای اصلی توسعه دهنده یا استفاده کننده از برنامه است. 
  • در مجموع سرعت برنامه‌های نوشته شده با معماری Microservices کندتر از برنامه‌های نوشته شده با معماری Monolithic است. دلیل آن محیط اجرایی برنامه‌ها است. برنامه‌هایی با معماری Monolithic بر روی حافظه سرور پردازش می‌شوند.


چه زمانی از معماری Microservices استفاده کنیم؟

در واقع قاعده مشخصی برای انتخاب بین این دو معماری وجود ندارد. شاید بهترین دلیل برای استفاده از این معماری زمانی است که تیم توسعه دهنده به این نتیجه برسد که خصوصیات معماری Monolithic برای آنها مشکل به حساب می‌آید.
اگر تیم توسعه دهنده تصمیم بگیرد که از معماری Monolithic به نوع Microservices تغییر مسیر دهد، نیازی به نوشتن کل برنامه از ابتدا نیست. در این شرایط می‌توان فقط کامپوننت‌هایی را که دردسر ساز شده‌اند، به نوع سرویسی آن تبدیل کرد. به این نوع برنامه‌های سمت سروری که بخش اصلی برنامه به صورت Monolithic ولی برخی از عملکردهای خاص آن به صورت سرویسی نوشته شده باشد، اصطلاحا معماری Microservices با هسته Monolithic گفته می‌شود.

 

 مدیریت داده‌ها: 

در معماری Microservices، هر سرویس می‌تواند پایگاه داده خود را برای ذخیره داده‌ها داشته باشد و یا اینکه از یک پایگاه داده مرکزی بهره ببرد. استفاده از پایگاه داده‌ی مجزای برای هر سرویس، مشکلات خود را دارد. باید بین سرویس‌های مختلف، همگام سازی صورت بگیرد که در این صورت، اگر یکی از سرویس‌ها از کار بیافتد، سرویس‌های وابسته به آن که داده‌ها بین آنها در تبادل هستند، دچار مشکل می‌شود و مسئله می‌تواند به سایر سرویس‌ها که به صورت زنجیر وار به داده‌های در حال تبادل یکدیگر وابسته هستند، سرایت کند. همچنین در این روش داده‌های تکراری وجود خواهند داشت و در نهایت کدنویسی برای این سیستم مشکل خواهد بود. 
در نتیجه بهتر این است که سرویس‌ها با یک پایگاه داده مرکزی سر و کار داشته باشند و اگر سرویس خاصی نیاز داشته باشد که داده‌های بخصوص خود را تولید کند و نمی‌خواهد آن را با سایر سرویس‌ها به اشتراک بگذارد، می‌تواند پایگاه داده مخصوص به خود را داشته باشد. نکته مهم دیگر این است که سرویس‌ها نباید به صورت مستقیم با پایگاه داده مرکزی در ارتباط باشند؛ بلکه به سرویسی مجزا، به نام "سرویس پایگاه داده" که وظیفه فراهم کردن API‌های مخصوص کار با پایگاه داده مرکزی را به عهده دارد، نیاز است.


پیاده‌سازی معماری Microservices‌ها توسط فریم‌فرک Seneca

Seneca یک فریم ورک Node.js است که برای ساخت برنامه‌های سمت سروری با معماری Microservices و هسته Monolithic استفاده می‌شود. در مطلب بعدی به این فریم‌ورک نگاهی گذرا خواهیم داشت.
مطالب
معرفی افزونه‌ی WhySharper

ReSharper جهت بهبود کیفیت کد‌های نوشته شده راهنمایی‌های مختلفی را ارائه می‌دهد. اما اکثر این‌ها مختصر و مفید و خلاصه هستند. برای مثال این متد بهتر است استاتیک شود یا این متغیر بهتر است readonly شود و الی آخر. اما چرا؟
برای رفع این نقیصه، افزونه‌ای برای ReSharper تهیه شده است به نام WhySharper که دلایل راهنمایی‌های ارائه شده از طرف افزونه‌ی اصلی را نیز بیان می‌کند (لینکی را به سایت stackoverflow جهت مشاهده بحث مربوطه ارائه می‌دهد).



این افزونه از گوگل کد و یا رپیدشیر قابل دریافت است.

متاسفانه امکان استفاده از گوگل کد وجود ندارد و این افزونه، فایل بررسی نگارش و همچنین پیشنهادات خود را از گوگل‌کد می‌خواند که سبب عدم بارگذاری آن خواهد شد. برای رفع این مشکل، مسیر زیر را پس از نصب پیدا کنید:

C:\Documents and Settings\UserName\Application Data\JetBrains\WhySharper

سپس دو فایل زیر را در آن مسیر کپی نمائید:
http://whysharper.googlecode.com/svn/trunk/WhySharper/SuggestionsVersion.txt
http://whysharper.googlecode.com/svn/trunk/WhySharper/Suggestions.xml

دریافت این دو فایل

نظرات مطالب
اعتبارسنجی مبتنی بر JWT در ASP.NET Core 2.0 بدون استفاده از سیستم Identity
با سلام؛ پروژه وب سایت همراه با اپ موبایل داریم. برای پیاده سازی احراز هویتی که هم در وب و هم در آپ موبایل  کارا باشه باید چه کنیم؟ آیا امکان این وجود داره همزمان هم از کوکی و توکن استفاده بشه؟
نظرات مطالب
استفاده از قابلیت Speech Recognition ویندوز 7 برای تولید زیرنویس انگلیسی
عالی بود.
نمیشه از موتور تشخیص گفتار وب سایت youtube استفاده کرد؟ (وب سرویسی یا .. موجود نیست؟)
به دلیل حجم بالای آموزسش احتمالا نتیجه بهتری داره.
در ضمن وابسته به یه پلتفرم خاص هم نمیشه.
نظرات مطالب
ASP.NET Web API - قسمت اول
اصولاً در Web API چیزی با عنوان Channel با اون مفهوم که در WCF هست نداریم. در Web API فقط یک Transport Channel برای HTTP وجود داره، چون هدف ایجاد Web API، فقط برقراری ارتباط در سطح HTTP هست، نه مثلاً MSMQ.
Protocol Channel هم همان مفاهیمی هستند که در ASP.NET MVC وجود دارند و مثلاً قسمتی از اون، تصدیق هویت و تعیین مجوز کاربر برای دسترسی به منابع با استفاده از فیلتر Authorize هست.
لطفاً دنبال تطبیق و تناظر بین مفاهیم پیچیده‌ی WCF و یافتن معادل در Web API نباشید. Web API به وجود آمده تا ایجاد وب سرویس‌ها در بستر HTTP رو ساده کنه، همین!