استفاده از View Modelدر Asp.Net MVC

در این مقاله به صورت عملی نحوه تعریف و استفاده از ViewModel ها و مزایای استفاده از آنها را خواهید دید.ViewModel یک کلاس نمایشی از کلاس های اصلی ما میباشد.

استفاده از View Modelدر Asp.Net MVC

همان طور که می دانید Modle قسمتی از برنامه است که منطق و اشیای دنیای واقعی را که ما قصد برنامه نویسی برای آن را داریم شبیه سازی و یا به عبارتی مدل سازی می کند .

مدل در برنامه های MVC ظرف داده های ماست که در بین کنترلر و View پاس داده می شود .در نمونه ای که ضمیمه این مقاله می باشد قصد داریم تنها به ثبت نام کاربر با کمک View Model ها بپردازیم .در ابتدا یک دیتابیس ایجاد می کنیم که در آن تنها دو جدول user و Role وجود دارد .این دو جدول به همدیگر ارتباط دارند زیرا هر کاربری می تواند چندین نقش داشته باشد.

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

حال به افزودن این مدل با کمک Entity Framework DataBase First می پردازیم .برای افزودن این مدل به برنامه خود بر روی مدل کلیک راست و گزینه Add=>new Item=>ADO.net Entity Data Model را می زنیم .در پنجره ای که باز می شود روش Entity Framework DataBase First را انتخاب می کنیم .

بعد از next کردن بر روی New Connection کلیک کرده و آدرس دیتابیس و جدول مورد نظر را وارد می کنیم . به شکل زیر توجه کنید

بعد از افزوده شدن مدل برای اینکه بتوانیم به property های خود صفت اضافه کنیم باید متادیتا ایجاد کنیم زیرا entity اجازه افزودن هیچ صفتی را به ما نمی دهد و تمام صفت های اضافه شده را پاک می کند . برای اینکه بتوانیم صفت به کلاس های خود در Entity اضافه کنیم باید در model.tt تغییراتی ایجاد کنیم .model.tt الگوی EF برای ساخت کلاس است .در این مدل ابتدا در public string EntityClassOpening(EntityType entity)  خط زیر را اضافه می کنیم

 "[MetadataType(typeof({2}Metadata))]"+Environment.NewLine+

سپس در

public string UsingDirectives(bool inHeader, bool includeCollections = true)

  خط زیر را اضافه می کنیم .

  "using System.ComponentModel.DataAnnotations;"+Environment.NewLine+

با این کاری که انجام دادیم بالای هر کلاسی که Entity معادل جداولمان در دیتابیس ایجاد کرده است یک صفت متادیتا اضافه شده است .حال در کلاس های متا دیتا که ایجاد کرده ایم به افزودن صفت های مورد نظر می پردازیم

کلاس متا دیتای user به صورت زیر خواهد بود

 class UsersMetadata
    {
        [Key]
        public int UserID { get; set; }
        [Display(Name = "نقش کاربر")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        public int RoleID { get; set; }
        [Display(Name = "نام کاربری")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        public string UserName { get; set; }

        [Display(Name = "کلمه عبور")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        public string Password { get; set; }

        [Display(Name = "ایمیل")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        public string Email { get; set; }

        [Display(Name = "کد فعال سازی")]
        public string ActiveCode { get; set; }

        [Display(Name = "فعال / غیر فعال")]
        public bool IsActive { get; set; }

        [Display(Name = "تاریخ ثبت نام")]
        [DisplayFormat(DataFormatString = "{0: yyyy/MM/dd}")]
        public System.DateTime RegisterDate { get; set; }
    }

حال برای اینکه کاربر را ثبت نام کنیم به تمام اطلاعات موجود در این دو کلاس user و Role احتیاج نداریم .بلکه به فیلد های انتخابی از آنها نیاز داریم .در واقع کلاس های View Model جنبه نمایشی دارند و از آنها برای ساخت view هایی با فیلد های انتخابی ما از کلاس های مختلف استفاده می شود.

مثلا نمونه ضمیمه مقاله از کلاس viewModel به نام های RegisterViewModel، و LoginViewModel استفاده کرده ایم .همان طور که می بینید این کلاس های ترکیبی از کلاس های مختلف می باشند و جنبه صرفا نمایشی دارند.

بعد از این کار یک کنترلر Account از نوع empty ایجاد می کنیم .در داخل این کنترلر یک action به نام Register و LoginUser می نویسیم . ساختار کنتر لر به صورت زیر است

 public class AccountController : Controller
    {
        ViewMEntities db = new ViewMEntities();
        // GET: Account
        public ActionResult Register()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Register(RegisterViewModel register)
        {
            if (this.IsCaptchaValid("Captcha is not valid"))
            {
                if (ModelState.IsValid)
                {
                    if (!db.Users.Any(u => u.Email == register.Email.Trim().ToLower()))
                    {
                        User user = new User()
                        {
                            ActiveCode = Guid.NewGuid().ToString().Replace("-", ""),
                            Email = register.Email.Trim().ToLower(),
                            IsActive = false,
                            Password = FormsAuthentication.HashPasswordForStoringInConfigFile(register.Password, "MD5"),
                            RegisterDate = DateTime.Now,
                            RoleID = 2,
                            UserName = register.UserName
                        };
                        db.Users.Add(user);
                        db.SaveChanges();
                        string body = PartialToStringClass.RenderPartialView("SendMails", "ActiveUser", user);
                        SendEmailGmail.Send(user.Email, "ایمیل فعال سازی", body);
                    }
                    else
                    {
                        ModelState.AddModelError("Email", "ایمیل وارد شده تکراری است");
                    }
                }
                else
                {
                    ModelState.AddModelError("CaptchaInputText", "Captcha is not valid");
                    return PartialView(register);
                }
            }
            return View(register);
        }

        public ActionResult ActiveUser(string id)
        {
            var user = db.Users.FirstOrDefault(u => u.ActiveCode == id);
            if (user != null)
            {
                user.ActiveCode = Guid.NewGuid().ToString().Replace("-", "");
                user.IsActive = true;
                db.SaveChanges();
                ViewBag.IsOk = true;
            }
            else
            {
                ViewBag.IsOk = false;
            }
            return View();
        }


        public ActionResult Login()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Login(LoginViewModel login, string ReturnUrl="/")
        {
            if (ModelState.IsValid)
            {
                string pass = FormsAuthentication.HashPasswordForStoringInConfigFile(login.Password, "MD5");
                var user = db.Users.FirstOrDefault(u => u.UserName == login.UserName && u.Password == pass);
                if (user != null)
                {
                    if (user.IsActive)
                    {
                        FormsAuthentication.SetAuthCookie(login.UserName, login.RememberMe);
                        return Redirect(ReturnUrl);
                    }
                    else
                    {
                        ModelState.AddModelError("Username", "حساب کاربری فوق فعال نشده است");
                    }
                }
                else
                {
                    ModelState.AddModelError("Username", "نام کاربری یا کلمه عبور اشتباه است");
                }

            }

            return View(login);
        }

        public ActionResult SignOut()
        {
            FormsAuthentication.SignOut();
            return Redirect("/");
        }

    }

بر روی action به نام register کلیک راست کرده و یک view با مدل RegisterViewModel که یک ViewModel است ایجاد می کنیم .View مربوط به این Action به صورت زیر است

@using CaptchaMvc.HtmlHelpers
@model ViewModel.Models.RegisterViewModel

@{
    ViewBag.Title = "Register";

    var captcha = Html.Captcha("تصویر جدید", "",4, "عبارت در تصویر را وارد کنید", false);
}

<h2>ثبت نام در سایت</h2>


@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.UserName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.UserName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.UserName, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.RePass, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.RePass, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.RePass, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-2">
                تصویر امنیتی
            </div>
            <div class="col-md-10">
                @captcha
                @Html.ValidationMessage(captcha.BuildInfo.InputElementId, new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="ثبت نام" class="btn btn-success" />
            </div>
        </div>
    </div>
}
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

توجه داشته باشید که برای ثبت نام از captcha هم استفاده کرده ایم برای افزودن آن در داخل nuget همین واژه را جستجو کنید و آن را به پروژه خود اضافه کنید .

همان طور که می بیند در داخل Action به نام Register بعد از اینکه  مدلی که از سمت view  می آید دوباره به صورت یک مدل deseryalize می شود ، ما این viewModel را داخل مدل اصلی خود به نام user قرار می دهیم .به تکه کد زیر توجه کنید

 User user = new User()
                        {
                            ActiveCode = Guid.NewGuid().ToString().Replace("-", ""),
                            Email = register.Email.Trim().ToLower(),
                            IsActive = false,
                            Password = FormsAuthentication.HashPasswordForStoringInConfigFile(register.Password, "MD5"),
                            RegisterDate = DateTime.Now,
                            RoleID = 2,
                            UserName = register.UserName
                        };
                        db.Users.Add(user);

در واقع برای ذخیره در دیتابیس یک شی از اشیای اصلی و نه view Model ایجاد کرده ایم و سپس اطلاعاتی که در داخل ViewModel وجود دارد را به شی اصلی منتقل کرده ایم .

بعد از اجرا شکل زیر را خواهید دید

فایل های ضمیمه
دانلود نسخه ی PDF این مطلب