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

اجرای این نوع صفحات کار سختی نیست؛ با کمی جستجو در اینترنت مثلا در اینجا میتوانید چیزهای خوبی پیدا کنید. اما متاسفانه اکثر مثال‌ها چیزی شبیه قرار دادن پارشال "ورود اعضا" در کنار پارشال "ثبت نام" هستند. حتما متوجه شده‌اید که معمولا این دو صفحه پس از  PostBack به صفحه‌ای جدید هدایت میشوند و یا در بهترین حالت به کمک Ajax ، پس از انجام عملیات، پیامی به کاربر نمایش میدهیم.

در این مقاله سعی شده روشی برای ایجاد چند فرم در یک View توضیح داده شود با این شرط که: 

اولا : از Ajax یا هلپر ایجکسی استفاده نکنیم.

ثانیا : پس از post-back، عملیات Redirect را انجام ندهیم و صفحه جاری را حفظ کنیم؛ چه قرار باشد همه چیز درست انجام شده باشد و چه مشکلی پیش آمده باشد و پیام خطایی در کنار فیلد‌ها نمایش داده شود. 

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

ویوی زیر را در نظر بگیرید. در layout، دو پارشال، به کمک اکشن‌متد فراخوانی شده‌اند:

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

ContactVM .cs  

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

              [EmailAddress(ErrorMessage = "آدرس ایمیل صحیح نیست")]
        [DataType(DataType.EmailAddress)]
        [Display(Name = "آدرس ایمیل")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        public string EmailAddress { get; set; }

        [Display(Name = "متن پیام")]
        [Required(ErrorMessage = "حرفی برای گفتن ندارید؟")]
        public string Description { get; set; }

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

SubscriberVM .cs

    public class SubscriberVM
    {   
        /*[RegularExpression("^[a-zA-Z0-9_\\.-]+@([a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$", ErrorMessage = "آدرس ایمیل صحیح نیست")]*/
          [EmailAddress(ErrorMessage = "آدرس ایمیل صحیح نیست")] /*.Net4.5*/
        [Display(Name = "ایمیل")]
        [Required(ErrorMessage = "لطفا {0} را وارد کنید")]
        public string Email { get; set; }

        [Display(Name = "وضعیت")]
        public bool IsActive { get; set; }    
    }

در Layout، دو اکشن متد صدا زده شده‌اند که وظیفه ارسال ویوهای هر کدام به Layout را به عهده دارند :

        <div class="row footerclass">
            <div class="col-md--6">
                @Html.Action("Subscribers", "Home")
            </div>
            <div class="col-md-6">
                @Html.Action("Contact", "Home")
            </div>

        </div>

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

public ActionResult Contact()
        {
            return PartialView("_Contact", model);
        }

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]

        public ActionResult Contact(ContactVM model)
        {
              if (ModelState.IsValid)
                {
//Do Something                    
                }
            return PartialView("_Contact", model);
        }

        public ActionResult Subscribers()
        {
            return PartialView("_Subscribers");
        }

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Subscribers(SubscriberVM model)
        {
                if (ModelState.IsValid)
                {
//Do Something
                }
            }
            return PartialView("_Subscribers",model);
        }

و اما ویوهایی که قرار است نمایش داده شوند:

Contact.Cshtml

@model IrsaShop.Models.ViewModel.ContactVM


<span></span><span>تماس با ما</span>
<hr />

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)
    <div>
        @Html.TextBoxFor(m => m.Name, new { @class = "form-control", @id = "name", @name = "name", placeholder = "نام" })
        @Html.ValidationMessageFor(m => m.Name)
    </div>
    <div>
        @Html.TextBoxFor(m => m.EmailAddress, new { @class = "form-control", @id = "email", @name = "email", placeholder = "ایمیل", @style = "direction: ltr" })
        @Html.ValidationMessageFor(m => m.EmailAddress)
    </div>
    <div>
        @Html.TextAreaFor(model => model.Description, new { @class = "form-control", @id = "message", @name = "message", placeholder = "پیام", @style = "max-width: 100%;height: 90px;" })
    </div>
    <div>
        <input type="button" value="" id="refresh" />
        <img alt="Captcha" id="imgcpatcha" src="@Url.Action("CaptchaImage","Captcha")" />
    </div>
    <div>
        @Html.TextBoxFor(model => model.Captcha, new { @class = "form-control", placeholder = "حاصل جمع؟" })
        @Html.ValidationMessageFor(model => model.Captcha)

    </div>
    <div>
        <input type="submit" value="ارسال" name="submitValue" />
    </div>
}

_Subscriber.Csh tml 

@model IrsaShop.Models.SubscriberVM

<span></span><span>خبرنامه</span>
<hr/>

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
    @Html.ValidationSummary(true)
    <div>

        <div>
            @Html.TextBoxFor(m => m.Email, new { @class = "form-control right-buffer top-buffer pull-right", @id = "email", @name = "email", placeholder = "ایمیل", @style = "direction: ltr;width: 50%", @required = "required" })
       @*     <button type="submit" name="submitValue">ثبت ایمیل</button>*@
            <input type="submit" value="ثبت ایمیل" name="submitValue" />
        </div>
        
    </div>
   @Html.ValidationMessageFor(m => m.Email,"",new { @class = "right-buffer pull-right"})
   
}

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

نکته دوم : نکته اول یک مشکل دارد! اگر به شکل صریح اکشن متد مربوط به Post-back مشخص نشود، بطور اتوماتیک تمامی اکشن متدهایی که ویژگی [HttpPost] دارند اجرا خواهند شد. این یعنی هر دو اکشن متد Contact و Subscriber اجرا می‌شوند و بنابر آنچه در اکشن متدها نوشته‌ایم هر دو ModelState بررسی می‌شود که این هدف ما نیست. مثلا فرم سمت چپ را تکمیل کرده ایم و دکمه "ثبت ایمیل" را فشار داده‌ایم و صفحه Postback می‌شود و با اینکه ایمیل در بانک ثبت شده اما فرم سمت راستی با خطا ظاهر میشود که چرا فیلدها خالی هستند!؟ 

برای حل این مشکل کافیست خاصیت name مربوط به دکمه‌ها را به شکل یک ورودی برای اکشن متدها بفرستیم و بر اساس وضعیت آن تنها state مدل مورد نظر خودمان را بررسی کنیم. پس اصلاح زیر را برای اکشن متدهای دارای ویژگی [HttpPost] انجام میدهیم.

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]

        public ActionResult Contact(ContactVM model, , string submitValue)
        {
   if (submitValue == "ارسال") 
                {
                 if (ModelState.IsValid)
                {
//Do Something                    
                }
}   else
                {
                         ModelState.Clear();
                }        
            return PartialView("_Subscribers", model);
        }

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
public ActionResult Subscribers(SubscriberVM model, string submitValue)
        {
             if (submitValue == "ثبت ایمیل") 
            {
if (ModelState.IsValid)
                {
//Do Something
                }
}
            else
            {
                ModelState.Clear();
            }
            return PartialView("_Subscribers");
        }

نکته سوم : در این روش سعی کنید از ViewModel  استفاده کنید و سعی کنید ویو مدل‌ها پراپرتی‌های با نام یکسان نداشته باشند. مثلا پراپرتی Email  در ویو مدل‌ها نام‌های متفاوتی داشته باشند (مثل EmailAddress  ، Email  ، ContactMail  و ...). با اینکار در زمان Postback  احتمال اینکه فیلدهای مشترک اتوماتیک پر شده به ما نمایش داده باشند صفر خواهد شد.

نکته چهارم : حواستان باشد پس از انجام عملیات مرتبط با هر فرم در اکشن متد مربوط به آن (مثلا ارسال ایمیل، ثبت در بانک یا ...) در صورتی که عملیات با موفقیت انجام شد حتما ModelState  را clear کنید. با اینکار پس از Post-back  فیلدهای پارشال‌ها خالی میشوند.

نکته پنجم : میتوانید به سادگی مدیریت خطا را به کمک جی کوئری انجام دهید؛ مثلا فرض کنید میخواهیم اگر ایمیل کاربر برای دریافت خبرنامه با موفقیت ثبت شد، پیامی مبنی بر موفقیت برای وی بفرستیم؛ اکشن متد HttPost مربوط به  Subscriber  را به شکل زیر تکمیل میکنیم : 

[HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Subscribers(SubscriberVM model, string submitValue)
        {
            if (submitValue == "ثبت ایمیل")
            {                
                if (ModelState.IsValid)
                {
                    Subscriber mail = new Subscriber() { Email = model.EmailSubscriber, IsActive = true };
                    context.Subscribers.Add(mail);
                    context.SaveChanges();
                    ViewBag.info = "ایمیل شما با موفقیت ثبت شد.";
                    ViewBag.color = "alert-success";
                    ModelState.Clear();
                }
            }
            else
            {
                ModelState.Clear();
            }
            
            return PartialView("_Subscribers ");
        }

در انتهای پارشال _Subscriber هم چند خط کد زیر را مینویسیم :

@if (!String.IsNullOrEmpty(ViewBag.info))
{
    <div id="info" style="position: fixed; bottom: 0; right: 0; margin-right: 1%;">

        <div class="alert @ViewBag.color alert-dismissable">
            <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
            <strong> @ViewBag.info</strong>
        </div>

    </div>
    <script>
        $(function () {
            $("#info").fadeOut(15000);
        });
    </script>
}


نتیجه این خواهد بود که پس از PostBack در صورت موفقیت تصویر زیر را خواهیم دید و 15 ثانیه المان سبزرنگ بوت استرپِ زیر نمایش داده خواهد شد.

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

حین نوشتن این مقاله به علت وجود if ‌های تو در تو، امیدوار بودم که روش‌های بهتری برای اینکار موجود باشند و هنوز هم امیدوارم نظرات شما چنین چیزی را نشان دهد. 

  • #
    ‫۱۰ سال و ۳ ماه قبل، پنجشنبه ۲۹ خرداد ۱۳۹۳، ساعت ۰۳:۳۵
    حین نوشتن این مقاله به علت وجود  if   ‌های تو در تو، امیدوار بودم که روش‌های بهتری برای اینکار موجود باشند و هنوز هم امیدوارم نظرات شما چنین چیزی را نشان دهد.   

    • #
      ‫۱۰ سال و ۳ ماه قبل، پنجشنبه ۲۹ خرداد ۱۳۹۳، ساعت ۰۵:۰۳
      مرسی از لینک، اینو دیده بودم بچه‌های اینجا هم مقاله اش رو نوشته بودن، تو اون مقاله یک فرم میسازیم با چند کارکرد ولی داستان اینجا کمی متفاوته. به نظر من یه جاهایی ساختن پارشال یا اکشن هایی که پارشال صدا میزنن خیلی ارزشمند هست و به ما برای رسیدن به یک فریم ورک شخصی کمک میکنه. بیشتر هدف من از این مقاله ساختار دادن به برنامه به کمک پارشال‌ها بود. یک ویویی تصور کنید که دارای پنج پارشال با پنج فرم مختلف باشه، ممکنه الان تصورش مسخره باشه ولی شاید یه روزی به کار اومد. حداقلش یه بازی خوب هست برای فهمیدن ظرفیت‌های MVC 
      • #
        ‫۱۰ سال و ۳ ماه قبل، پنجشنبه ۲۹ خرداد ۱۳۹۳، ساعت ۱۵:۴۳
        مرسی
        من دقیقاً الان دنبال همین موضوع بودم و یه ویو دارم با 9 پارشیال ویو که از همین روش باید استفاده کنن.
  • #
    ‫۱۰ سال و ۳ ماه قبل، جمعه ۳۰ خرداد ۱۳۹۳، ساعت ۱۶:۴۱
    سلام.
    مرسی از مقاله خوبتون.
    من یه مشکلی دارم شاید اگه ممکنه منو هم راهنمایی کنین.
    فرض کنیم یه صفحه داریم که توی اون صفحه چند تا فرم وجود داره و تعداد این فرم‌ها هم نا مشخص هستش و این فرمها به صورت پارشل ایجاد میشن. وهمچنین قصد بر این است که همه این فرم‌ها توسط یک دکمه و به ترتیب سابمیت بشن. من خودم این کار رو به کمک جاوا اسکریپت انجام دادم. حالا می‌ خواستم ببینم پیشنهاد شما چیه. ممنون از همتون. 
  • #
    ‫۱۰ سال و ۱ ماه قبل، جمعه ۳۱ مرداد ۱۳۹۳، ساعت ۰۱:۲۱
    با سلام سپاس؛
    1- اگر لطف کنید کمی در باره Html.Action  توضیح بدید ممنون میشم.  
    2- دو تا partial را با استفاده از Html.Action و return اکشن مربوط, به صفحه اصلی اضافه کردید.
    public ActionResult Contact()
            {
                return PartialView("_Contact", model);
            }
    model هر کدام از partial‌ها رو مشخص کردید
    @model IrsaShop.Models.ViewModel.ContactVM
    @model IrsaShop.Models.SubscriberVM
    
    سوال: در صفحه اصلی مودل ما به چه صورتی خواهد بود؟
    @model IrsaShop.Models.ViewModel.؟
    آیا باید از viewmodel استفاده کنیم که هر دو (SubscriberVM ,  ContactVM )  و موارد مورد نیاز دیگر صفحه را در بر بگیرد؟
    با فرض اینکه مثلا خود صفحه هم از مودل دیگری برای استفاده از helper استفاده می‌کند, 
    آیا مودل برنامه تاثیری بر partial‌ها دارد؟(در این روش)
     @Html.Action مودلی را به partial ارسال نمی‌کنه برخلافه @Html.Partial که model مورد نیاز را ارسال می‌کند.
    (لطفا مودویو مورد نیاز رو شرح بدید)
      • #
        ‫۱۰ سال و ۱ ماه قبل، یکشنبه ۲ شهریور ۱۳۹۳، ساعت ۰۲:۴۸
        سپاس, در لینک گفته شده است:

        حین فراخوانی متد Html.Action، یک متد در یک کنترلر فراخوانی خواهد شد (که شامل ارائه درخواست و طی سیکل کامل پردازشی آن کنترلر نیز خواهد بود). سپس آن متد با بازگشت دادن یک PartialView، اطلاعات پردازش شده یک partial view را به فراخوان بازگشت می‌دهد 
        دقیقا همین مورد در این اموزش اجرا شده است
         return PartialView("_Contact", model);
        ولی اگر بخواهیم بعد انجام عملیات, اکشن دیگری اجرا بشه چه کار باید کرد؟
        من از RedirectToAction استفاده کردم ولی متاسفانه error داد...
         if (this.ModelState.IsValid)
                    {
                        
                        return RedirectToAction(actionName: "show", controllerName:"Posts", routeValues: new { id });
                    }
        پیغام:
        Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'. 
         

        Child actions are not allowed to perform redirect actions. 

        • #
          ‫۱۰ سال و ۱ ماه قبل، یکشنبه ۲ شهریور ۱۳۹۳، ساعت ۰۵:۱۰

          child action قراره فقط محتوای قسمت کوچکی از صفحه رو تامین کنه. در اینجا redirect کل صفحه معنی نداره چون هنوز کار رندر صفحه تموم نشده و وسط کار هست.

          • #
            ‫۱۰ سال و ۱ ماه قبل، یکشنبه ۲ شهریور ۱۳۹۳، ساعت ۱۲:۲۶
            به نظرتون راه حل چیست؟
            در مثال این اموزش, بعد از پایان یافتن عملیات بصورت موفق, فقط "پیام با موفقیت ثبت شد" نمایش داده می‌شه , ولی بنده می‌خواهم بعد از پایان صحیح عملیات اکشن دیگه ای فعال بشه , مثلا بعد از ثبت نظر مربوط به یک خبر در سایت , خبر مورد نظر دوباره نمایش داده بشه تا نظر جدید لود بشه.
            ولی این اتفاق با خطای مذکور همراه,  حتی به صورت دستی هم صفحه را reload می‌کنم عملیات قبلی دوباره انجام می‌گیره(پی اپی نظر قبلی ثبت می‌شود)
            شما فرمودید هنوز وسط کاره,حق با شماست, ایا راه حلی هست؟ یا باید از این شیوه برای اینجور کارها استفاده نکنم؟ در صورت عدم استفاده از این روش پیشنهادتون چیست؟
            • #
              ‫۱۰ سال و ۱ ماه قبل، یکشنبه ۲ شهریور ۱۳۹۳، ساعت ۱۴:۳۸

              در مثال بالا نیازی به استفاده از Html.Action و child action نبوده. از Html.Action زمانی استفاده میشه که قراره چند partial view از پیش مقدار دهی شده در صفحه، از منابع داده مختلفی مقدار دهی بشن. مثلا قراره در کنار صفحه، از یک منبع داده، آمار سایت رو نمایش بدید (اطلاعات از پیش مقدار دهی شده) و از یک منبع دیگه، لیست مطالب و این دو مورد هم قراره در layout سایت قرار بگیرن. اینجا شما ویرایش اطلاعات رو که ندارید (برای مقدار دهی عناصر فرم از قبل). فقط قراره از کاربر اطلاعات بگیرید. بنابراین استفاده از رندر کردن پارشال مثل قبل کار می‌کنه. مهم هم نیست که هر پارشالی مدل مختلفی داره. برای ارسال اطلاعات فرم به سرور، فقط نام کنترل‌ها مهم است و نه نوع مدل شما. پروتکل HTTP چیزی از نوع مدل نمی‌دونه. ASP.NET MVC هست که نام‌ها رو می‌گیره و متصل می‌کنه به خواص یک شیء.

              در کل مثال بالا برای حالت قرار دادن این فرم‌ها در layout سایت برای تمام صفحات طراحی شده. اگر یک صفحه معمولی و view معمولی هست، در ASP.NET MVC مجاز هستید n تا فرم در صفحه قرار بدید. برای اینکار نیازی به Html.Action نیست؛ با رندر پارشال هم کار می‌کنه. برای تامین داده اون‌ها هم از ViewModel استفاده کنید. این ViewModel یک خاصیتش، کل اطلاعات فرم یک هست و خاصیت دومش کل اطلاعات فرم 2 و الی آخر.

    • #
      ‫۱۰ سال و ۱ ماه قبل، یکشنبه ۲ شهریور ۱۳۹۳، ساعت ۲۱:۱۳
      نتیجه استفاده از هلپر پارشال یا اکشن شبیه به هم هست و استفاده از اکشن برای من یک عادت شده، چون اضافات کدی رو میشه از اون طریق به پارشال بازگشتی تزریق کرد 
  • #
    ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۴:۴۵
    سلام ممنون از این مقاله خوبتون.
    فقط من یه مشکلی دارم. سه تا فرم دارم که توی پارشال ساخته شدن و توسط ویومدل هم مقدار دهی میشن.
    ولی در زمان اجرا عمل ذخیره رو که انجام میده بعدش خطای زیر رو میده:
    Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'.

    لطف میکنید راهنمایی کنید.
    • #
      ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۶:۲۱
      بدون دیدن کدهای شما نمیشه نظر داد. آیا در کنترلری که دارید از HttpGet روی اکشن متدها استفاده کردید؟ حذفش کنید بعد دوباره تست کنید. آیا روی اکشن متد از NonAction بجای ChildActionOnly استفاده کردید؟ کلا ویژگی‌های اضافه شده را باید دقیقا بررسی کنید.
      • #
        ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۶:۳۳
        ممنون از اینکه پاسخ دادید.

        خیر از Httpget و NonAction استفاده نکردم ولی از ChildActionOnly بالای اکشنها استفاده کردم
        در کنترلر به صورت زیر اکشنها رو نوشتم:
                [Authorize(Roles = "Administrator")]
                public ActionResult AddUserRole()
                {
                    return View();
                }
               
                 //////////////////////////////////////////////////////////
        
                //اضافه کردن نقش////////////
                [Authorize(Roles = "Administrator")]
                [HttpGet]
                [ChildActionOnly]
                
                public ActionResult AddRole()
                {
                  
                    return PartialView("PartialRole");
                }
        
                [ChildActionOnly]
                [HttpPost]
                //[ValidateAntiForgeryToken]
                public ActionResult AddRole(tblRole rl, string submitValue)
                {
                    if (submitValue == "ذخیره نقش")
                    {
                        //تبدیل تاریخ میلادی به شمسی
                        rl.RoleDateCreate = Utility.ToPersianDate(DateTime.Now);
        
                        UserRepository user = new UserRepository();
                        //برای وارد کردن خودکار شناسه کاربر وارد شده
                        rl.UserIDCreate_FK = Convert.ToInt64(user.FindUserID(User.Identity.Name));
        
                        if (ModelState.IsValid)
                        {
                            RoleRepository acr = new RoleRepository();
                            var model = acr.Add(rl);
                            ViewBag.Message = "نقش با موفقیت ثبت شد";
                            ModelState.Clear();
                        }
                    }
                    else
                    {
                        ModelState.Clear();
                    }
                    return PartialView("PartialRole", rl);
        
                }
                //////////////////////////////////////////////////////////
        
                //اضافه کردن کاربر//////////
                [Authorize(Roles = "Administrator")]
                [HttpGet]
                [ChildActionOnly]
               
                public ActionResult AddUser()
                {
                    return PartialView("PartialUser");
                }
                
                [ChildActionOnly]
                [HttpPost]
             
                public ActionResult AddUser(tblUser rl, string submitValue)
                {
                    if (submitValue == "ثبت نام")
                    {
                        if (ur.ExistUserName(rl.UserName))//برای اینکه نام کاربری تکراری نباشد
                        {
                            ViewBag.Warning = "این نام کاربری تکراری میباشد";
                         
                        }
                        else
                        {
                           
                            //برای وارد کردن خودکار شناسه کاربر وارد شده
                            rl.UserIDCreate = Convert.ToInt64(ur.FindUserID(User.Identity.Name));
                           
                            //تبدیل میلادی به شمسی
                            rl.UserDateCreate = Utility.ToPersianDate(DateTime.Now);
        
                            if (ModelState.IsValid)
                            {
                                UserRepository acr = new UserRepository();
                                var model = acr.Add(rl);
                                ViewBag.Message = "کاربر با موفقیت ثبت شد";
                                ModelState.Clear();
                            }
                        }
                    }
                    else
                    {
                        ModelState.Clear();
                    }
                    return PartialView("PartialUser", rl);
        
                }
        
                //////////////////////////////////////////////////////////
        
                // دادن نقش به کاربر///////
        
                [ChildActionOnly]
                
                [HttpGet]
                [Authorize(Roles = "Administrator")]
                public ActionResult RoleOfUser()
                {
                    var blUser = new UserRepository();
                    var blRole = new RoleRepository();
                    var model = new RoleUserViewModel();
        
                    model.username = blUser.Select().ToList();
                    model.rolename = blRole.Select().ToList();
                   
                    return PartialView("PartialRoleOfUser", model);
                }
        
                [ChildActionOnly]
                [HttpPost]      
                public ActionResult RoleOfUser(tblRoleUser rl, string submitValue)
                {
                    if (submitValue == "ذخیره نقش کاربر")
                    {
                        //برای وارد کردن خودکار شناسه کاربر وارد شده
                        rl.UserIDCreate_FK = Convert.ToInt64(ur.FindUserID(User.Identity.Name));
        
                        //تبدیل میلادی به شمسی
                        rl.RoleUserDateCreate = Utility.ToPersianDate(DateTime.Now);
        
                        if (ModelState.IsValid)
                        {
                            RoleUserRepository acr = new RoleUserRepository();
                            var model = acr.Add(rl);
                            ViewBag.Message = "نقش کاربر با موفقیت ثبت شد";
        
                            ModelState.Clear();
                        }
                    }
                    else
                    {
                        ModelState.Clear();
                    }
                    return PartialView("PartialRoleOfUser", rl);
        
                }
        در پارشیال ویو Role
        @model MeterControl.ViewModels.RoleUserViewModel
        <script src="~/Scripts/jquery-1.8.2.min.js"></script>
        <script src="~/Scripts/jquery.validate.min.js"></script>
        <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
        
        @using (Ajax.BeginForm("AddUserRole", "Home", new AjaxOptions { HttpMethod = "Post", Url = "/Home/AddUserRole" })){ 
            <fieldset>
                <legend>tblRole</legend>
        
                
        
                <div>
                    @Html.LabelFor(model => model.role.RoleName)
                </div>
                <div>
                    @Html.EditorFor(model => model.role.RoleName)
                    @Html.ValidationMessageFor(model => model.role.RoleName)
                </div>
        
               
        
                @ViewBag.Message
                <p>
                    <input type="submit" value="ذخیره نقش" name="submitValue" />
                </p>
            </fieldset>
        }

        و در ویو کلی هم به صورت زیر اکشنها صدا زده شده اند:
        @{
            ViewBag.Title = "AddUserRole";
        }
        
        <h2>AddUserRole</h2>
        <div>
            <div>
                @Html.Action("AddRole", "Home")
            </div>
            <div>
                @Html.Action("AddUser", "Home")
                @Html.Partial("PartialUser")
            </div>
            <div>
                @Html.Action("RoleOfUser","Home")
            </div>
        </div>

        به خط زیر خطا میدهد
        @Html.Action("AddRole", "Home")
        • #
          ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۶:۴۵

          [HttpGet] را از روی AddRole اول حذف کنید.

          ضمنا زمانیکه فقط قصد نمایش یک Partial view را دارید، نیازی نیست حتما از Html.Action استفاده کنید؛ چون سربار بالایی دارد. هر بار فراخوانی Html.Action سبب راه اندازی مجدد سیکل پردازشی کنترلر جاری میشه. اگر فقط قصد نمایش ساده این‌ها است (بدون پاس دادن اطلاعات اضافه‌تری به آن‌ها)، از همان Html.Partial استفاده کنید. برای مثال در کدهای فوق سه مورد AddRole ، AddUser و RoleOfUser اضافی هستند. حذفشون کنید و این‌ها را با RenderPartial داخل View تعویض کنید. اون مورد RoleOfUser که پارامتر دریافت می‌کنه رو با یک ViewModel اطلاعاتش رو به View برای رندر ارسال کنید.

          • #
            ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۶:۴۹
            حذف کردم ولی هنوز همون خطا رو میده
            • #
              ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۶:۵۴
              برای دیباگ بهتر، زمانیکه صفحه‌ی exception در ویژوال استودیو ظاهر شد، روی دکمه‌ی continue کلیک کنید. بعد صفحه‌ی زرد رنگ ASP.NET ظاهر میشه. اینجا خطای کاملتری نمایش داده میشه با جزئیات بیشتری.
              • #
                ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۶:۵۸
                بعد از زدن دکمه continue خطایی توی صفحه نمیده و همون صفحه سایت رو نشون میده بدون خطایی
            • #
              ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۶:۵۶
                public class RoleUserViewModel
                  {
                      public tblRole role { get; set; }
                      public tblUser user { get; set; }
              
                      public tblRoleUser roleuser { get; set; }
              
                      //برای اینکه در صفحه برای نام کاربری و نام نقش دراپ دان لیست بگذاریم
                      public IEnumerable<tblUser> username { get; set; }
                      public IEnumerable<tblRole> rolename { get; set; }
              
                  }
              این هم کد ویومدل هست. که هر سه پارشیال رو با این ویومدل مقدارهی شدن
              • #
                ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۷:۰۳
                به جای Html.Action هم نوشتم Html.RenderPartial ولی خطای زیر رو میده:

                • #
                  ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۷:۰۶

                  مشکل syntax داره. یکی از دو حالت زیر را استفاده کنید:

                  @{ Html.RenderPartial("......."); }
                  or
                   @{ Html.RenderPartial(".......", Model); }
                  • #
                    ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۷:۱۳
                    با هر دو مورد خطا میده:

                    • #
                      ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۷:۱۷
                      اینبار می‌گه مدل رو در این متد جدید استفاده کردی اما بالای صفحه مدلی تعیین نشده و به صورت پیش فرض dynamic هست. بالای صفحه‌ی View، با model MyViewModel@ باید مدلی را که قصد دارید پاس بدید، دقیقا مشخص کنید.
                      • #
                        ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۷:۳۰
                        ممنون از راهنمایی بسیار خوبتون. خیلی کمکم کرد

                        فقط اینکه الان به کمبوباکس ایراد گرفته و میگه مقداری نداره در صورتیکه پر شده.
                      • #
                        ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۷:۳۱

                        • #
                          ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۸:۳۸
                          ببخشید یه سوال دیگه هم داشتم اینکه این RenderPartial  هیچ اکشنی رو فراخوانی نمیکنه و با این دستور من هیچ داده ای رو نمیتونم توی دیتابیس ذخیره کنم.

                          ممنون میشم راهنماییم کنید.
                          • #
                            ‫۹ سال و ۷ ماه قبل، دوشنبه ۲۰ بهمن ۱۳۹۳، ساعت ۱۸:۵۰

                            «هیچ اکشنی رو فراخوانی نمیکنه»

                            فرقش با قبل فقط همین یک مورد هست. مابقیش فرقی نمی‌کنه. RenderAction کارش فقط رندر هست و نه ثبت چیزی در دیتابیس. من فقط عنوان کردم ()ActionResult AddUser اضافی هست و ساده‌تر هم میشه مدیریتش کرد. متد (ActionResult AddUser(tblUser rl, string submitValue بدیهی هست که باید مانند قبل برای مدیریت Postها باشد.