پیاده سازی فرم لاگین و رجیستر دریک ویو بدون استفاده از Ajax در MVC

در این مقاله به شرح پیاده سازی فرم ورود و ثبت نام دریک ویو در MVC خواهیم پرداخت

پیاده سازی فرم لاگین و رجیستر دریک ویو بدون استفاده از Ajax در MVC

نکته مهم این است که هر فرم مستقل از دیگری رفتار کند و مثلا اگر یکی از فرم‌ها ناقص پر شد و دکمه‌ی ارسال آن فشرده شد، پس از Post-back، فقط و فقط اجرای همین فرم Validate شود و فرم دوم بدون تغییر باقی بماند

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

    public class MyLoginViewModel
    {
        [Display(Name = "آدرس ایمیل")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        [MaxLength(150, ErrorMessage = "{0} نمی تواند بیشتر از {1} باشد")]
        [EmailAddress(ErrorMessage = "ایمیل وارد شده معتبر نیست")]
        public string Email { get; set; }
        [Display(Name = "کلمه عبور")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        [MaxLength(150, ErrorMessage = "{0} نمی تواند بیشتر از {1} باشد")]
        [DataType(DataType.Password)]
        public string Password { get; set; }

        [Display(Name = " به یاد داشته باش")]
        public bool RememberMe { get; set; }
    }

سپس نوبت به ساخت مدل برای فرم ثبت نام میرسد همانند بالا یک کلاس به نام RegisterViewModel    بسازید و فیلد لازم برای ثبت نام و صفت های آنهارا وارد کنید:

   public class RegisterViewModel
    {
		[Display(Name = "کلمه عبور")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        [MaxLength(150, ErrorMessage = "{0} نمی تواند بیشتر از {1} باشد")]
        [DataType(DataType.Password)]
        public string UserPassword { get; set; }
        [Display(Name = "تکرار کلمه عبور")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        [MaxLength(150, ErrorMessage = "{0} نمی تواند بیشتر از {1} باشد")]
        [DataType(DataType.Password)]
        [Compare("UserPassword", ErrorMessage = "کلمه عبور وارد شده یکسان نیستند")]
        public string RepeatPassword { get; set; }
        [Display(Name = "آدرس پست الکترونیکی")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        [MaxLength(150, ErrorMessage = "{0} نمی تواند بیشتر از 150 کاراکتر باشد")]
        [EmailAddress(ErrorMessage = "ایمیل وارد شده معتبر نیست")]
        public string UserEmail { get; set; }
        [Display(Name = "نام")]
        [MaxLength(150, ErrorMessage = "{0} نمی تواند بیشتر از 150 باشد")]
        [Required]
        public string FirstName { get; set; }
        [Display(Name = "نام خانوادگی")]
        [MaxLength(150, ErrorMessage = "{0} نمی تواند بیشتر از 150 باشد")]
        [Required]
        public string LastName { get; set; }
	}

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

         public ActionResult Login()
        {
            return PartialView();
        }
		 public ActionResult Register()
        {
            return PartialView();
        }

حالا در کنترلر خود یک اکشن متد به نام index بنویسید و ویو آنرا بسازید:

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

و در ویو خود html زیر را بنویسید:

    <section>
        <div class="container">
            <div class="row">
                <div class="col-sm-6 col-md-6">
                    @Html.Action("Login","Account")
                </div>
                <div class="col-sm-6 col-md-6">
                    @Html.Action("Register", "Account")
                </div>
            </div>
        </div>
    </section>

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

پارشیال ویو مربوط به فرم ورود:

@model LoginAndRegister.Models.MyLoginViewModel


@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>MyLoginViewModel</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <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">
            @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.RememberMe, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                <div class="checkbox">
                    @Html.EditorFor(model => model.RememberMe)
                    @Html.ValidationMessageFor(model => model.RememberMe, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</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>

و پارشیال ویو مربوط به فرم ثبت نام :

@model LoginAndRegister.Models.RegisterViewModel


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

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

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

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

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

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</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>

نکته مهم:

هیچ نوع ورودی برای Html.BeginForm در نظرنگیرید اگر اکشن متدی را برای صدا زدن در این بخش به کار ببرید هنگام Postback به مشکل برخورد خواهید کرد؛ چون آدرس آن اکشن متد به شکل صریح در آدرس مرورگر فراخوانی میشود و پارشال ما پس از Post-back به تنهایی و بدون Layout نمایش داده خواهد شد. اسم بردن از اکشن متد وقتی کارساز است که آن اکشن متد قرار باشد یک Redirect انجام دهد .

نکته دیگر، که مهم ترین نکته در این مثال می باشد این است که اگر  اکشن متد مربوط به Post-back مشخص نشود، بطور اتوماتیک تمامی اکشن متدهایی که ویژگی [HttpPost] دارند اجرا خواهند شد. این یعنی هر دو اکشن متد   Login و Register اجرا می‌شوند و بنابر آنچه در اکشن متدها نوشته‌ایم هر دو ModelState

بررسی میشوند باید برای جدا سازی این مورد  خاصیت name مربوط به دکمه‌ها را به شکل یک ورودی برای اکشن متدها بفرستیم و بر اساس وضعیت آن تنها state مدل مورد نظر خودمان را بررسی کنیم پس در ویوها تغییر زیر را انجام دهید:

برای پارشیال ویو login:

 <button type="submit" class="btn btn-primary" value="ورود" name="submitValue">ورود</button>

و برای پارشیال ویو ثبت نام:

<button type="submit" class="btn btn-success" value="ساخت حساب کاربری" name="submitValue">ساخت حساب کاربری</button>

 در این روش سعی کنید از ViewModel  استفاده کنید و سعی کنید ویو مدل‌ها پراپرتی‌های با نام یکسان نداشته باشند.

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

  [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
 
        public ActionResult Login(MyLoginViewModel login, string submitValue)
        {
            if (submitValue == "ورود")
            {
                if (ModelState.IsValid)
                {
					//Do Something                   
                }
			}   else
                {
                         ModelState.Clear();
                }       
             return PartialView("Login", login); 
        }
 
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Register(RegisterViewModel register, string submitValue)
        {
            if (submitValue == "ساخت حساب کاربری")
            {
                if (ModelState.IsValid)
                {
				//Do Something
                }
			}
            else
            {
                ModelState.Clear();
            }
            return PartialView("Register", register);
        }

این روش نوعی مدیریت میان اکشن متدهای دارای ویژگی HttpPost است و همانطور که گفتیم به علت اینکه پس از Post-Back نیاز به ساختار به هم نخورده‌ی صفحه‌ی قبلی داریم، نمیتوانستیم به شکل صریح، اکشن متد برای Html.BeginForm تعریف کنیم تا این دردسر‌ها را نداشته باشیم.