آشنایی و معرفی Data Annotation ها در MVC

سه شنبه 30 خرداد 1396

هر زمان که یک فرمی ثبت می شود باید مطمئن شوید که داده سمت سرور اعتبارسنجی می شوند. بعضی از توسعه دهندگان تنها اعتبار سنجی سمت کاربر را انجام می دهند و اعتبار سنجی سمت سرور را رها می کنند. این کار یک روش به شدت اشتباه است زیرا اگر کاربر تنها جاوا اسکریپت را در مرورگر غیر فعال کند به راحتی می تواند داده های غیر معتبر را وارد نماید. در نتیجه همیشه مطمئن شوید اعتبار سنجی سمت سرور انجام می شود.

آشنایی و معرفی Data Annotation ها در MVC

اعتبار سنجی سمت سرور توسط ASP.NET MVC

در برنامه ASP.NET MVC ما می توانیم یک اعتبارسنجی سمت سرور انجام دهیم بر روی مدل با استفاده از  Data Annotation ها.

Data Annotation فضای نامی است که مجموعه ای از کلاس ها را برایتان فعل می کند که با استفاده از Meta Data برای کنترل ها استفاده می کند.

این MetaData یک مجموعه از خواص را تعریف می کند. MVC حجم زیادی از Annotation ها را در کلاس قرار داده است. برخی از مهم ترین آن ها شامل:

در این مورد اگر شما بخواهید از اعتبار سنجی سفارشی برای انجام کارهایتان استفاده کنید، شما می توانید توسط Custom Validation Attribute این کار را انجام دهید. در این کلاس شما اعتبارسنجی سفارشی خودتان را می نویسید. ما به شما توضیح می دهیم که چگونه این کلاس را بسازید.

برای اینکه شما بتوانید اعتبار سنجی سمت سرور را انجام دهید، یک پروژه بسازید و فیلد هایی را در آن قرار دهید. مثلا فرم استخدامی برای کاربر را در نظر بگیرید.

فرم به این شکل نمایش داده می شود:

بر روی این فرم یک کلید قرار دارد که با کلیک کردن بر روی submit فرم استخدامی باید بررسی شود. بنابراین ما باید مطمئن شویم که annotation ها انجام می شود.

با راست کلیک کردن بر روی پوشه مدل یک کلاس با نام JobApplication.cs بسازید.

کد زیر را حتما وارد نمایید.

using System.ComponentModel.DataAnnotations;

نام: این فیلد باید اجباری باشد. بنابراین ویژگی اجباری را به آن می دهیم.

[Required]
public string name { get; set; }

تجربه: تنها اعداد را باید پذیرا باشد و باید بین سه رقم تا 15 رقم باشد. برای اینکار یک ویژگی بازه ای به فیلدمان می دهیم.

[Range(3, 15, ErrorMessage = "Experience must be from 3 to 15 years")]
public int experience { get; set; }

تاریخ تولد: باید بازه زمانی خاصی را بگیرد. اینکار را با DataType انجام می دهیم.

[DataType(DataType.Date)]

برای سفارشی سازی تاریخ تولد ابتدا پیام خطای آن را می نویسیم سپس بصورت دستی بازه زمانی آن را مشخص می کنیم.

[ValidBirthDate(ErrorMessage = "DOB Should be between 01-25-1970 & 01-25-2000")]

به این شکل در می آید:

[Display(Name = "Date of Birth")]
[DataType(DataType.Date)]
[ValidBirthDate(ErrorMessage = "DOB Should be between 01-25-1970 & 01-25-2000")]
public DateTime birthDate { get; set; }

در مرحله بعد یک کلاس برای سفارشی سازی کلاس مورد نظرمان می سازیم. ما این کلاس را در پوشه ای به نام class قرار می دهیم. سپس با راست کلیک بر روی new sealed class با نام ValidBirthDate می سازیم که البته مشتق شده از CustomValidation.cs.

اکنون کافیست متد IsValid را باز نویسی کنیم یا به عبارتی override کنیم.

کد به شکل زیر در می آید:

using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
 
namespace demo.MVC.Class
{
    public class CustomValidation
    {
    }
    public sealed class ValidBirthDate : ValidationAttribute
    {
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            DateTime _birthJoin = Convert.ToDateTime(value);
            DateTime minDate = Convert.ToDateTime("01-25-1970");
            DateTime maxDate = Convert.ToDateTime("01-25-2000");
 
            if (_birthJoin > minDate && _birthJoin < maxDate)
                return ValidationResult.Success;
            else
                return new ValidationResult(ErrorMessage);
        }
    }
} 

ایمیل : این فیلد باید قانون خاصی را رعایت کند که توسط regular expression این کار را انجام می دهیم.

[Required]             
[RegularExpression(@"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$", ErrorMessage = "Invalid email")]
public string email { get; set; }

جنسیت: باید از یک لیست آبشاری استفاده کند. این لیست آبشاری باید سه انتخاب داشته باشد. انتخاب، مرد، زن. یک شخص باید یکی از گزینه های مرد یا زن را انتخاب نماید.

[SexValidation(ErrorMessage = "Select your sex")]
public string sex { get; set; }

برای جنسیت نیز باید یک اعتبار سنجی سفارشی بسازیم.

public class SexValidation : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (Convert.ToString(value) == "M" || Convert.ToString(value) == "F")
            return ValidationResult.Success;
        else
            return new ValidationResult(ErrorMessage);
    }
}

در کد زیر یک شرط قرار دادیم که اگر M یا F بود، اعتبار سنجی را با موفقیت انجام بده در غیر اینصورت با خطا مواجه شود.

حقوق درخواستی

آن باید حدود بازه ای از دو عدد باشد. ما یک ویژگی regularExpression برای آن تعریف کردیم به این شکل:

[RegularExpression(@"^(0(?!\.00)|[1-9]\d{0,6})\.\d{2}$", ErrorMessage = "Invalid salary 3500.50")]
public decimal expectedMonthlySalary { get; set; } 

مهارت ها: ما می خواهیم شخص مهارت ها را پر کند مثلا C#، ASP، Jquery و ... . که البته حداقل باید سه عدد باشند. ما یک کلاس اعتبار سنجی می سازیم که این موضوع را بررسی کند. ابتدا یک خاصیت به شکل زیر می سازیم.

[SkillValidation(ErrorMessage = "Select at least 3 skills")]
public List<CheckBox> skills { get; set; }

همانطور که مشاهده می کنید فیلد ما از نوع چک باکس است. در view ما چک باکس ها را با خاصیت isChecked می سازیم.

public class CheckBox
{
    public bool IsChecked { get; set; }
}

در مرحله بعد کد زیر را می نویسیم:

public class SkillValidation : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        List<CheckBox> instance = value as List<CheckBox>;
        int count = instance == null ? 0 : (from p in instance
                                                where p.IsChecked == true
                                                select p).Count();
        if (count >= 3)
            return ValidationResult.Success;
        else
            return new ValidationResult(ErrorMessage);
    }
}

ما برای بررسی اینکه حداقل باید سه مورد اضافه کرده باشد کاربر، از لینک استفاده کردیم.

توضیحات شغل قبلی: در این قسمت کاربر باید درباره شغل قبلی خود توضیح دهد.

مطمئن شوید این کد Required را داشته باشد.

[Required]
public string previousJobDescription { get; set; }

مرحله بعدی قبول کردن قوانین شرکت است. بنابراین کاربر باید چک باکس آن را تایید کند.

[RequiredTerms(ErrorMessage ="Must accept our terms")]
public Boolean terms { get; set; }

اعتبار سنجی سفارشی آن به این شکل می شود:

public sealed class RequiredTerms : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (Convert.ToBoolean(value) == false)
            return new ValidationResult(ErrorMessage);
        else
            return ValidationResult.Success;
    }
}

ساخت کنترلر برنامه استخدامی شغل

یک کنترلر با نام JobApplicationController اضافه می کنیم. این کنترلر یک Index ActionResult دارد که از نوع Get است و همین متد را یک بار دیگر برای متد POST می نویسیم.

[HttpPost]
[ValidateInput(false)]
public ActionResult Index(Models.JobApplication jobApplication)
{
    if (ModelState.IsValid)
        ViewBag.Result = "Form Submitted Successfully.";
    else
        ViewBag.Result = "Invalid Entries, Kindly Recheck.";
    return View();
} 

زمانی که کاربر روی ثبت کلیک کرد، باید فیلد ها بررسی شوند. ما از CkEditor استفاده کردیم.

اضافه کردن پوشه CkEditor به پروژه و اضافه کردن فایل های جاوا اسکریپتی به آن را باید انجام دهید تا CKEditor کار کند.

<script src="~/Content/Component/ckeditor/ckeditor.js" type="text/javascript" language="javascript"></script>

اضافه کردن مرجع یا reference به مدل

@model demo.MVC.Models.JobApplication

CSS زیر را برای طراحی اضافه می کنیم

<style>
    #viewContent .jobApplicationDiv label {
        display: block;
        margin: 0;
        text-transform: capitalize;
    }
 
    #viewContent .jobApplicationDiv table tr > td > span {
        display: block;
        color: burlywood;
    }
 
    #viewContent table {
        width: 100%;
    }
 
        #viewContent table tr {
            height: 80px;
            background: darkcyan;
        }
 
            #viewContent table tr td {
                width: 50%;
                padding-left: 5px;
            }
 
    #viewContent .studentDiv {
        padding-top: 25px;
    }
 
        #viewContent .studentDiv table thead {
            background-color: #0f40e0;
        }
 
        #viewContent .studentDiv table tbody {
            background-color: #ff6a00;
        }
</style>

مرحله بعدی اضافه کردن مدل به view است و نمایش فیلد ها:

<h3>@ViewBag.Result</h3>
<div id="viewContent">
    <div class="jobApplicationDiv">
        @using (Html.BeginForm())
            {
            <table>
                <tr>
                    <td>
                        @Html.LabelFor(model => model.name)
                        @Html.EditorFor(model => model.name)
                        @Html.ValidationMessageFor(model => model.name)
                    </td>
                    <td>
                        @Html.LabelFor(model => model.experience)
                        @Html.EditorFor(model => model.experience)
                        @Html.ValidationMessageFor(model => model.experience)
                    </td>
                </tr>
                <tr>
                    <td>
                        @Html.LabelFor(model => model.birthDate)
                        @Html.EditorFor(model => model.birthDate)
                        @Html.ValidationMessageFor(model => model.birthDate)
                    </td>
                    <td>
                        @Html.LabelFor(model => model.email)
                        @Html.EditorFor(model => model.email)
                        @Html.ValidationMessageFor(model => model.email)
                    </td>
                </tr>
                <tr>
                    <td>
                        @Html.LabelFor(model => model.sex)
                        @Html.DropDownListFor(model => model.sex, new List<SelectListItem> { new SelectListItem { Text = "Select", Value = "Select" }, new SelectListItem { Text = "Male", Value = "M" }, new SelectListItem { Text = "Female", Value = "F" } })
                        @Html.ValidationMessageFor(model => model.sex)
                    </td>
                    <td>
                        @Html.LabelFor(model => model.expectedMonthlySalary)
                        @Html.EditorFor(model => model.expectedMonthlySalary)
                        @Html.ValidationMessageFor(model => model.expectedMonthlySalary)
                    </td>
                </tr>
                <tr>
                    <td>
                        @Html.LabelFor(model => model.skills)
                        @Html.CheckBoxFor(m => m.skills[0].IsChecked, new { id = "csharpSkill" }) C#
                        @Html.CheckBoxFor(m => m.skills[1].IsChecked, new { id = "aspSkill" }) ASP.NET
                        @Html.CheckBoxFor(m => m.skills[2].IsChecked, new { id = "jquerySkill" }) jQuery
                        @Html.CheckBoxFor(m => m.skills[3].IsChecked, new { id = "mvcSkill" }) ASP.NET MVC
                        @Html.CheckBoxFor(m => m.skills[4].IsChecked, new { id = "razorSkill" }) Razor
                        @Html.CheckBoxFor(m => m.skills[5].IsChecked, new { id = "htmlSkill" }) HTML
                        @Html.ValidationMessageFor(model => model.skills)
                    </td>
                    <td>
                        @Html.LabelFor(model => model.usWorkPermit)
                        @Html.RadioButtonFor(m => m.usWorkPermit, "True") Yes I have
                        @Html.RadioButtonFor(m => m.usWorkPermit, "False") No I don't
                        @Html.ValidationMessageFor(model => model.usWorkPermit)
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        @Html.LabelFor(model => model.previousJobDescription)
                        @Html.TextAreaFor(model => model.previousJobDescription)
                        @Html.ValidationMessageFor(model => model.previousJobDescription)
                        <script type="text/javascript" language="javascript">
                            CKEDITOR.replace(@Html.IdFor(model => model.previousJobDescription));
                            CKEDITOR.config.toolbar = [
                               ['Styles', 'Format', 'Font', 'FontSize'],
                               '/',
                               ['Bold', 'Italic', 'Underline', 'StrikeThrough', '-', 'Undo', 'Redo', '-', 'Cut', 'Copy', 'Paste', 'Find', 'Replace', '-', 'Outdent', 'Indent', '-', 'Print'],
                               '/',
                               ['NumberedList', 'BulletedList', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
                               ['Image', 'Table', '-', 'Link', 'Flash', 'Smiley', 'TextColor', 'BGColor', 'Source']
                            ];
                        </script>
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        Accept our Terms and conditions
                        @Html.CheckBoxFor(model => model.terms)
                        @Html.ValidationMessageFor(model => model.terms)
                    </td>
 
                </tr>
                <tr><td colspan="2"><button id="submitButton" type="submit">Submit</button></td></tr>
            </table>
        }
    </div>
</div>

توضیحات تکمیلی

ViewBag.Result برای نمایش پیغام از طرف کنترلر استفاده می شود. در view ما به این شکل فیلد ها یمان را ساختیم.

نام: با استفاده از EditorFor ساختیم. @Html.EditorFor(mode => model.name) متد EditorFor یک Textbox می سازد. ما همچنین از LabelFor برای نمایش عنوان برای فیلد استفاده کردیم.

به همین ترتیب برای فیلد های دیگر

 

برای منو آبشاری به این شکل:

@Html.DropDownListFor(model => model.sex, new List { new SelectListItem { Text = “Select”, Value = “Select” }, new SelectListItem { Text = “Male”, Value = “M” }, new SelectListItem { Text = “Female”, Value = “F” } })

برای مهارت ها به این شکل عمل کردیم:

@Html.CheckBoxFor(m => m.skills[0].IsChecked, new { id = "csharpSkill" }) C#
@Html.CheckBoxFor(m => m.skills[1].IsChecked, new { id = "aspSkill" }) ASP.NET
@Html.CheckBoxFor(m => m.skills[2].IsChecked, new { id = "jquerySkill" }) jQuery
@Html.CheckBoxFor(m => m.skills[3].IsChecked, new { id = "mvcSkill" }) ASP.NET MVC
@Html.CheckBoxFor(m => m.skills[4].IsChecked, new { id = "razorSkill" }) Razor
@Html.CheckBoxFor(m => m.skills[5].IsChecked, new { id = "htmlSkill" }) HTML

برای RadioButton ها به این شکل

@Html.RadioButtonFor(m => m.usWorkPermit, "True") Yes I have
@Html.RadioButtonFor(m => m.usWorkPermit, "False") No I don't

برای CKEditor اینگونه عمل کردیم:

<script type="text/javascript" language="javascript">
    CKEDITOR.replace(@Html.IdFor(model => model.previousJobDescription));
    CKEDITOR.config.toolbar = [
        ['Styles', 'Format', 'Font', 'FontSize'],
        '/',
        ['Bold', 'Italic', 'Underline', 'StrikeThrough', '-', 'Undo', 'Redo', '-', 'Cut', 'Copy', 'Paste', 'Find', 'Replace', '-', 'Outdent', 'Indent', '-', 'Print'],
        '/',
        ['NumberedList', 'BulletedList', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
        ['Image', 'Table', '-', 'Link', 'Flash', 'Smiley', 'TextColor', 'BGColor', 'Source']
    ];
</script>

در نهایت خروجی به شکل زیر شد:

آموزش asp.net mvc

فایل های ضمیمه

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید