ASP.NET MVC 3: Generate unobtrusive validation when BeginForm is on the layout

前端 未结 5 1615
一个人的身影
一个人的身影 2020-12-09 13:31

I just realized that when I place a form tag on my layout page, surrounding the RenderBody section, the unobtrusive validation is not being generated. Something like this:

相关标签:
5条回答
  • 2020-12-09 13:37

    While putting @using (Html.BeginForm()) into the content page fixes the validation problem it also puts an extra set of <form> tags into the output. I created a small extension that fixes the problem without writing anything to the output.

    Use it as @using (Html.BeginSubForm())

    public static class FormExtensions
    {
        public static MvcSubForm BeginSubForm(this HtmlHelper html)
        {
            return new MvcSubForm(html.ViewContext);
        }
    }
    
    
    public sealed class MvcSubForm : IDisposable
    {
        private readonly ViewContext _viewContext;
        private readonly FormContext _originalFormContext;
    
        public MvcSubForm(ViewContext viewContext)
        {
            _viewContext = viewContext;
            _originalFormContext = viewContext.FormContext;
    
            viewContext.FormContext = new FormContext();
        }
    
    
        public void Dispose()
        {
            if (_viewContext != null)
            {
                _viewContext.FormContext = _originalFormContext;
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-09 13:46

    I've just run into the same problem, but possibly a better solution based on Darin Dimitrov's answer.

    The trick is to create a page base type, based on the WebViewPage<T> class, the default base class for views and do the FormContext swap there.

    abstract public class FormFixWebViewPage : FormFixWebViewPage<object>
    {
    }
    
    abstract public class FormFixWebViewPage<T> : WebViewPage<T>
    {
        override public void Write(System.Web.WebPages.HelperResult result)
        {
            var originalFormContext = ViewContext.FormContext;
            ViewContext.FormContext = new FormContext();
    
            base.Write(result);
    
            ViewContext.FormContext = originalFormContext;
        }
    }
    

    And then in the Web.config file under the ~/Views/ folder, alter the pageBaseType attribute under pages element, which can be found in the system.web.webPages.razor section:

    <system.web.webPages.razor>
        <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <pages pageBaseType="<YOUR-NAMESPACE>.FormFixWebViewPage">
        <!--pages pageBaseType="System.Web.Mvc.WebViewPage"-->
            <namespaces>
                <add namespace="System.Web.Mvc" />
                <add namespace="System.Web.Mvc.Ajax" />
                <add namespace="System.Web.Mvc.Html" />
                <add namespace="System.Web.Helpers" />
                <add namespace="System.Web.Routing" />
            </namespaces>
        </pages>
    </system.web.webPages.razor>
    
    0 讨论(0)
  • 2020-12-09 13:49

    Thanks for your help, I tried it but I found a solution not as "grotesque" (as you said) as you suggested :D

    I simply put a BeginForm method inside my page and also a BeginForm method on the layout:

    @* On the layout page *@
    @using (Html.BeginForm())
    {
        <input type="submit" value="save" />
    
        <div>
            @RenderBody()
        </div>
    }
    
    
    @* On the content page *@
    @using(Html.BeginForm())
    {
      @* Content *@
    }
    

    so, at the end I have two BeginForm methods: ASP.NET MVC engine is using the one located on the layout page, so the data-val* attributes are being rendered correctly and the form is placed just where I wanted so any submit button on the layout can submit my particular page with the validations rendered

    It works pretty well

    Thanks a lot

    regards, Rodrigo

    0 讨论(0)
  • 2020-12-09 13:59

    Just add below code at top of the child view file...

    @{
       Layout = "~/Views/Shared/_Layout.cshtml";
       this.ViewContext.FormContext = new FormContext();
    }
    

    its working fine for me.

    i hope this will help you....

    0 讨论(0)
  • 2020-12-09 14:02

    You could apply a grotesque hack inside your view:

    @{
        var originalContext = ViewContext.FormContext;
        ViewContext.FormContext = new FormContext();
    }
    
    <!-- This will generate proper HTML5 data-* validation attributes -->
    @Html.TextBoxFor(x => x.Prop1)
    @Html.ValidationMessageFor(x => x.Prop1)
    
    @Html.TextBoxFor(x => x.Prop2)
    @Html.ValidationMessageFor(x => x.Prop2)
    
    @{
        ViewContext.FormContext = originalContext;
    }
    
    0 讨论(0)
提交回复
热议问题