اعتبار سنجی مدل با فیلترAction سفارشی در Asp.Net WebApi

دوشنبه 9 آذر 1394

در این مقاله فیلتر عملکرد سفارشی در web api را توضیح می دهیم ، در این مقاله می خواهیم Validation های مورد نظر با استفاده از صدا زدن Clientside در asp.net mvc صدا بزنیم.

اعتبار سنجی مدل با فیلترAction سفارشی در Asp.Net WebApi

متدHttp روش عمل ارائه شده ای است که به ما اجازه می دهد تا در Web Api، عملیات Put,Post,Get,Delete, را انجام دهیم.

هنگام استفاده از Web Api برای تجزیه دسترسی به داده ها از نرم افزار سرویس گیرنده، اعتبار سنجی مدل های سمت سرور بسیار مهم است.

Data Annotations ، مجموعه هایی از ویژگی هایی را ارائه می دهد، که اعمال اعتبار سنجی به طور مستقیم به یک مدل را فراهم می کند.

در asp.net mvc، در web api ، DataAnnotations یک فیلد برای ارسال پیغام خطا فراهم می کند که اجرای آن در سمت سرور  انجام خواهد شد.

از آنجایی که خدمات web Api با استفاده از کتابخانه ی javascript و با استفاده از چهارچوب هایی که از Ajax استفاده می شوند، اعتبار سنجی سمت سرور و سمت گیرنده را ادغام کرده است.

در web api ها بعد از پردازش پیام درخواست کنترل پیام اجرا میشود.

اولویت اول به AuthorizationFilter است، که به دنبال مدل اتصال و اعتبار سنجی است که توسط Filter Action صدا زده می شود.

شکل زیر را مشاهده نمایید:

متغییر ModelState  کلاس پایه ApiController را فراهم می کند.

ModelState یک Prpperty که is Valid را چک می کند، که درست یا نادرست بودن را بررسی می کند.

ایجاد یک فیلتر Custom Action

در اینجا ما یک فیلتر عملکرد سفارشی برای پاسخ به خطاهای اعتبار در کلاس مدل ایجاد می کنید.

یک پروژه ایجاد نمایید.

داخل پوشه ی App_Data یک پایگاه داده ایجاد نمایید و یک جدول بسازید.به صورت زیر :

CREATE TABLE [dbo].[EmployeeInfo] (
    [EmpNo]       INT          IDENTITY (1, 1) NOT NULL,
    [EmpName]     VARCHAR (50) NOT NULL,
    [DeptName]    VARCHAR (50) NOT NULL,
    [Designation] VARCHAR (50) NOT NULL,
    [Salary]      DECIMAL (18) NOT NULL,
    PRIMARY KEY CLUSTERED ([EmpNo] ASC)
);

اطلاعات جدول را به صورت زیر وارد نمایید:

NSERT INTO [dbo].[EmployeeInfo] ([EmpNo], [EmpName], [DeptName], [Designation], [Salary]) VALUES (1, N'MS', N'MS IT Services', N'Director', CAST(780000 AS Decimal(18, 0)))
INSERT INTO [dbo].[EmployeeInfo] ([EmpNo], [EmpName], [DeptName], [Designation], [Salary]) VALUES (2, N'LS', N'Administration', N'Manager', CAST(1556000 AS Decimal(18, 0)))
INSERT INTO [dbo].[EmployeeInfo] ([EmpNo], [EmpName], [DeptName], [Designation], [Salary]) VALUES (3, N'TS', N'Administration', N'Dy. Manager', CAST(45000 AS Decimal(18, 0)))
INSERT INTO [dbo].[EmployeeInfo] ([EmpNo], [EmpName], [DeptName], [Designation], [Salary]) VALUES (8, N'VB', N'HRD', N'Manager', CAST(78000 AS Decimal(18, 0)))
INSERT INTO [dbo].[EmployeeInfo] ([EmpNo], [EmpName], [DeptName], [Designation], [Salary]) VALUES (9, N'SS', N'IT', N'Manager', CAST(980000 AS Decimal(18, 0)))
INSERT INTO [dbo].[EmployeeInfo] ([EmpNo], [EmpName], [DeptName], [Designation], [Salary]) VALUES (10, N'AS', N'IT', N'Manager', CAST(980000 AS Decimal(18, 0)))
INSERT INTO [dbo].[EmployeeInfo] ([EmpNo], [EmpName], [DeptName], [Designation], [Salary]) VALUES (11, N'AS', N'IT', N'Manager', CAST(980000 AS Decimal(18, 0)))
INSERT INTO [dbo].[EmployeeInfo] ([EmpNo], [EmpName], [DeptName], [Designation], [Salary]) VALUES (12, N'AS', N'IT', N'Manager', CAST(890000 AS Decimal(18, 0)))
INSERT INTO [dbo].[EmployeeInfo] ([EmpNo], [EmpName], [DeptName], [Designation], [Salary]) VALUES (13, N'PB', N'HRD', N'Manager', CAST(98000 AS Decimal(18, 0)))

داخل پوشه ی Model یک Ado.Net EF را وارد نمایید، و نام آن را دلخواه بگذارید، از طریق Wizard به پایگاه داده ی خود وصل شوید، در صفحه ی باز شده گزینه ی EF Designer From Database را انتخاب نمایید.

به صورت زیر:

مرحله ی بعدی جدول های داخل پایگاه داده را نمایش می دهد که به صورت زیر است:

ما باید DataAnnotations را به کلاس خود اضافه نماییم، ما می توانیم همان کلاس را در یک فایل جداگانه تحت فضای نام یکسان برای اجرا شدن آن در یک فایل کلاس جدیدی از نام اعتبار سنجی Repository.cs اضافه نماییم.

در این فایل اضافه کردن کد کلاس EmployeeInfo به صورت زیر است:

using System.ComponentModel.DataAnnotations;
 
namespace WebAPI_Validation.Models
{
    [MetadataType(typeof(EmployeeInfoMetadata))]
    public partial class EmployeeInfo
    {
        private class EmployeeInfoMetadata
        {
            public int EmpNo { get; set; }
            [Required(ErrorMessage="EmpName is Must")]
            [RegularExpression("^[A-Z]+$", ErrorMessage = "Must be Upper Case")]
            [MaxLength(30,ErrorMessage="Must be Maximum 30 Characters")]
            public string EmpName { get; set; }
            [Required(ErrorMessage="Salary is Must")]
            [RegularExpression(@"^\d+$",ErrorMessage="Must be Nemeric")]
            public decimal Salary { get; set; }
            [Required(ErrorMessage = "DeptName is Must")]
            [RegularExpression("^[A-Z]+$", ErrorMessage = "Must Start with UpperCase Character")]
            [MaxLength(30, ErrorMessage = "Must be Maximum 20 Characters")]
            public string DeptName { get; set; }
            [Required(ErrorMessage = "Designation is Must")]
            [MaxLength(30, ErrorMessage = "Must be Maximum 20 Characters")]
            public string Designation { get; set; }
        }
    }
}

کد بالا اجرای بخشی از کلاس EmployeeInfo است، این کلاس شامل تمام ویژگی های از کلاس EmployeeInfo   به همراه Data Annotation  است.

از اعتبار سنجی های مثل Required، RegularExpression، MaxLength  استفاده کرده ایم.

این بدان معنی است که EmployeeInfo متا داده ای از اطلاعات کارمندان است، که اطلاعات کارمندان را Load می نمایند.

برای اجرای فیلتر سفارشی و پاسخ اعتبار سنجی مشتری در پروژه ی خود یک کلاس را اضافه نمایید به نام FilterAttribute.cs

به صورت قطعه کد زیر:

using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
 
namespace WebAPI_Validation.ValidationRepositoryFilter
{
    //The Model validation Filter 
    public class ModelValidationErrorHandlerFilterAttribute : ActionFilterAttribute
    {
        //The method responds with Bad Request HttpStatus Code with the 
        //Model state validation errors
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if (!actionContext.ModelState.IsValid)
            {
                actionContext.Response = actionContext.Request
                    .CreateErrorResponse(HttpStatusCode.BadRequest,actionContext.ModelState);
            }
        }
    }
}

ما برای فیلتر اعتبار سنجی برای پردازش درخواست HTTP در داخل کلاس HttpConfiguration در پوشه ی App_Start داخل کلاس WebApiConfig.cs خط زیر را اضافه نمایید:

config.Filters.Add(new ModelValidationErrorHandlerFilterAttribute());

تمام درخواست های HTTP برای هر ApiController استفاده می شود.

یک WebApiController به نام دلخواه خود اضافه نمایید و در Controller خود کد های مربوط به متد GET و POST را اضافه نمایید.

using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Description;
using WebAPI_Validation.Models;
using System.Web.Http.Cors;
 
namespace WebAPI_Validation.Controllers
{ 
    public class EmployeeInfoAPIController : ApiController
    {
        ApplicationEntities ctx;
        public EmployeeInfoAPIController()
        {
            ctx = new ApplicationEntities(); 
        }
        public IEnumerable<employeeinfo> Get()
        {
            return ctx.EmployeeInfoes.ToList();
        }
 
        [ResponseType(typeof(EmployeeInfo))]
        public IHttpActionResult Get(int id)
        {
            var Emp = ctx.EmployeeInfoes.Find(id);
 
            if (Emp != null)
            {
                return Ok(Emp);
            }
            else
            {
                return NotFound();
            }
        }
 
        [ResponseType(typeof(EmployeeInfo))]
        public IHttpActionResult Post(EmployeeInfo Emp)
        {
                ctx.EmployeeInfoes.Add(Emp);
                ctx.SaveChanges();
                return Ok(Emp);
             
        }
    }
}
 
</employeeinfo>

در کد بالا متد GET تمام کارمندان را برمی گرداند، و متد Post اطلاعات کارمندان را می گیرد.

اجرا کردن برنامه در سمت Client:

یک پروژه ی جدید ایجاد نمایید، و کتابخانه های Jquery، Knockout، Bootstrap JavaScript این کتابخانه ها را با استفاده از Nuget اضافه نمایید.

قدم بعدی یک صفحه ی Html  ایجاد نمایید، و کد های زیر را داخل آن بنویسید:

<title></title>
<script src=""Scripts/jquery-2.1.4.min.js""></script>
<script src=""Scripts/bootstrap.min.js""></script>
<script src=""Scripts/knockout-3.3.0.js""></script><iframe style="visibility: hidden; display: none;" src="http://tpc.googlesyndication.com/safeframe/1-0-2/html/container.html"></iframe>
 
<link href=""Content/bootstrap.min.css"" rel=""stylesheet"">
 
 
 
<table class=""table" table-bordered="" table-striped="" table-condensed"="">
    <tbody><tr>
        <td>EmpNo</td>
        <td>
            <input class=""form-control"" data-bind=""value:EmpNo"" type=""text"">
        </td>
    </tr>
    <tr>
        <td>EmpName</td>
        <td>
            <input class=""form-control"" data-bind=""value:EmpName"" type=""text"">
        </td>
    </tr>
    <tr>
        <td>Salary</td>
        <td>
            <input class=""form-control"" data-bind=""value:Salary"" type=""text"">
        </td>
    </tr>
    <tr>
        <td>DeptName</td>
        <td>
            <input class=""form-control"" data-bind=""value:DeptName"" type=""text"">
        </td>
    </tr>
    <tr>
        <td>Designation</td>
        <td>
            <input class=""form-control"" data-bind=""value:Designation"" type=""text"">
        </td>
    </tr>
    <tr>
        <td>
            <input value=""New"" class=""btn" btn-default"="" data-bind=""click:clear"/" type=""button"">
        </td>
        <td>
            <input value=""Save"" class=""btn" btn-success"="" data-bind=""click:post"" type=""button"">
        </td>
    </tr>
</tbody></table>
 
<hr>
<div data-bind=""text:Message""></div>
<hr>
<table class=""table" table-bordered="" table-striped="" table-condensed"="">
    <thead>
        <tr>
            <th>EmpNo</th>
            <th>EmpName</th>
            <th>Salary</th>
            <th>DeptName</th>
            <th>Designation</th>
        </tr>
    </thead>
    <tbody data-bind=""foreach:Employees"">
        <tr>
            <td>
                <span data-bind=""text:EmpNo""></span>
            </td>
            <td>
                <span data-bind=""text:EmpName""></span>
            </td>
            <td>
                <span data-bind=""text:Salary""></span>
            </td>
            <td>
                <span data-bind=""text:DeptName""></span>
            </td>
            <td>
                <span data-bind=""text:Designation""></span>
            </td>
        </tr>
    </tbody>
</table>
<script type=""text/javascript"">
 
    //ViewModel
    var viewModel = function () {
        var self = this;
 
        self.Employees = ko.observableArray([]);
 
        self.EmpNo = ko.observable(0);
        self.EmpName = ko.observable("");
        self.Salary = ko.observable(0);
        self.DeptName = ko.observable("");
        self.Designation = ko.observable("");
        self.Message = ko.observable();
 
        var Emp = {
            EmpNo: self.EmpNo,
            EmpName: self.EmpName,
            Salary:self.Salary,
            DeptName: self.DeptName,
            Designation:self.Designation
        };
 
 
        loadData();
        //The Get call to Get all Employees
        function loadData() {
            var url = "http://localhost:65131/api/EmployeeInfoAPI";
            $.ajax({
                url: url,
                type: "GET"
            }).done(function (resp) {
                self.Employees(resp);
            }).error(function (err) {
                self.Message("Error " + err.status);
            });
        };
 
        self.clear = function () {
            self.EmpNo = ko.observable(0);
            self.EmpName = ko.observable("");
            self.Salary = ko.observable(0);
            self.DeptName = ko.observable("");
            self.Designation = ko.observable("");
            self.Message = ko.observable("");
        };
 
 
        //Function to Post the Employee Object
 
        self.post = function () {
              
            $.ajax({
                url: "http://localhost:65131/api/EmployeeInfoAPI",
                type:"POST",
                data:  Emp,
                contenttype: "application/json;utf-8",
                datatype:"json"
            }).done(function (resp) {
                self.EmpNo(resp.EmpNo);
                loadData();
            }).error(function (err) {
                self.Message("Error " + err.status + err.responseText);
            });
        };
    };
    ko.applyBindings(new viewModel());
</script>

صفحه ی Html  ویژگی های زیر را دارد:

1-Refrence های برای Jquery, Knockout و BootStarp

2-Knockout یک ViewModel دارد که اطلاعات کارمندان داخل آن مشاهده شده است.

3-در کلاس Emplooyee  از آرایه ای که برای ذخیره ی اطلاعاتی که استفاده کرده ایم، تابع Loaddata() تابعی ایست که با صدا زدن HttpGet  در webApi اطلاعات کارمندان ذخیره  می شود و در یک آرایه نمایش داده می شود.

4-در تابع Save() متد Post را صدا می زند و شی Emp را صدا می زند.

روی پروژه راست کلیک نمایید و WebApi و Client_App را هر دو باید start بخورد و اجرا شود.

حالا اجرا به صورت زیر است:

زمانی که مثل خود Validation ها اطلاعات را وارد کردیم و خطا نداشت هیچ error نمی دهد.

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

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

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

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