简体   繁体   中英

C# Ajax.BeginForm FormValidation Dual Post Issue

When using the formvalidation.io libraries with Ajax.BeginForm the [HttpPost] method is called twice.

I can confirm that I am not referencing jquery.unobtrusive-ajax.js more than once as that is a common mistake, nor am I using wildcards to reference jquery.unobtrusive-ajax.js in my BundleConfig which I believe can also introduce the same issue.

I am also using PartialViewResult and not ActionResult to ensure I am not re-including jquery.unobtrusive-ajax.js via the _Layout.cshtml

From extensive testing, trying to eliminate the issue I have found that removing code that initialises formvalidation removes the dual post issue. The reason for this, is that formvalidation when initialised adds novalidate="novalidate" to the form.

I'd like to however retain the formvalidation functionality to prevent the form from being posted without correct data being entered, but also prevent the unnecessary extra HttpPost call.

Please see my code below, to demonstrate the issue:

RouteConfig.cs

routeCollection.MapRoute("Test", "Home/Test/{id}/{form}", new { controller = "Home", action = "Test", id = UrlParameter.Optional, form = UrlParameter.Optional });

BundleConfig.cs

bundleCollection.Add(new ScriptBundle("~/scriptBundle/_test").Include("~/Scripts/_test.js"));

Test.cs

public class Test
{
    public int Id { get; set; }

    //[Required]
    public string Description { get; set; }
}

HomeController.cs

public PartialViewResult Test(int id, bool form)
{
    var test = new WebApplication1.Models.Test
    {
        Id = id,
        Description = "Blah"
    };

    return PartialView(!form ? "_Test" : "_TestForm", test);
}

[HttpPost]
public PartialViewResult Test(WebApplication1.Models.Test model)
{
    return PartialView(!ModelState.IsValid ? "_TestForm" : "_Test", model);
} 

Index.cshtml

<div class="row">
    <div class="col-sm-6">
        <div class="panel panel-default">
            <div class="panel-heading">Test</div>
            <div class="panel-body" id="TestBody">
                <table class="table table-bordered no-margin-bottom">
                    <tr>
                        <td>@Model.Id</td>
                    </tr>
                    <tr>
                        <td>@Model.Description</td>
                    </tr>
                    <tr>
                        <td colspan="4">@Ajax.ActionLink("Edit Test", "Test", "Home", new { id = Model.Id, form = true }, new AjaxOptions { UpdateTargetId = "TestBody" }, new { title = "Click to Edit Test" })</td>
                    </tr>
                </table>
            </div>
        </div>
    </div>
</div>

_TestForm.cshtml

@using WebApplication1.Helpers
@model WebApplication1.Models.Test
@{
    Layout = null;
}
@using (Ajax.BeginForm("Test", "Home", null, new AjaxOptions { UpdateTargetId = "TestBody" }, new { @class = "form-horizontal", Id = "TestForm" }))
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(model => model.Id)
    <fieldset>
        <div class="col-sm-12">
            <div class="input-group">
                <span class="input-group-addon">Description</span>
                @Html.TextBoxForExt(model => model.Description)
                <p class="help-block">@Html.ValidationMessageFor(model => model.Description)</p>
            </div>
        </div>
        <div class="form-group" style="margin-bottom: -15px">
            <div class="col-sm-12">
                <div style="float: left">
                    <button type="submit" name="submitButton" class="btn btn-primary" title="Click to Update">Update</button>
                </div>
                <div style="float: right">
                    @Ajax.ActionLink("Cancel", "Test", "Home", new { Model.Id, form = false }, new AjaxOptions { UpdateTargetId = "TestBody" }, new { @class = "btn btn-primary", title = "Click to Cancel" })
                </div>
            </div>
        </div>
    </fieldset>
}
@Scripts.Render("~/scriptBundle/_test")

_test.js

$(document).ready(function() {
    $("#TestForm").formValidation({
        framework: "bootstrap",
        fields: {
            'Description': {
                validators: {
                    callback: {
                        callback: function(value) {
                            debugger;
                            var id = parseInt($("#Id").val(), 0) || 0;

                            if (value === "" && id === 0) {
                                return {
                                    valid: false,
                                    message: "Please enter a Description"
                                };
                            }

                            return true;
                        }
                    }
                }
            }
        }
    });
});

_Test.cshtml

@model WebApplication1.Models.Test
<table class="table table-bordered no-margin-bottom">
    <tr>
        <td>@Model.Id</td>
    </tr>
    <tr>
        <td>@Model.Description</td>
    </tr>
    <tr>
        <td colspan="4">@Ajax.ActionLink("Edit Test", "Test", "Home", new { id = Model.Id, form = true }, new AjaxOptions { UpdateTargetId = "TestBody" }, new { title = "Click to Edit Test" })</td>
    </tr>
</table>

After a little more research, great deal of trial and error, it came down to a minor addition of code to prevent the second form post. Please see my revised _test.js below.

$(document).ready(function() {
    $("#TestForm").formValidation({
        framework: "bootstrap",
        fields: {
            'Description': {
                validators: {
                    callback: {
                        callback: function(value) {
                            debugger;
                            var id = parseInt($("#Id").val(), 0) || 0;

                            if (value === "" && id === 0) {
                                return {
                                    valid: false,
                                    message: "Please enter a Description"
                                };
                            }

                            return true;
                        }
                    }
                }
            }
        }
    });
}).on("success.form.fv", function(e) {
    e.preventDefault(); 

    return false;
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM