繁体   English   中英

如何避免ASP.NET MVC中的多个表单提交?

[英]How to avoid multiple submit of form in ASP.NET MVC?

我尝试使用ASP.NET MVC 5编写代码和脚本。是否使用模态来执行创建,更新和删除功能,该功能正常工作,但是在创建和更新中,因为我启用了远程验证,因此可以在首先但突然之间,当您再次单击提交按钮时,它将提交或发布数据。 简而言之,我的验证无效。 拜托,我需要帮助。

模型:

[Key]
[Display(Name = "ID")]
[Column("LAND_TYPE_CAT_ID", Order = 0, TypeName = "bigint")]
public long CategoryId { get; set; }

[Display(Name = "Category Name")]
[StringLength(100)]
[Column("LAND_TYPE_CAT", Order = 1, TypeName = "nvarchar")]
public string CategoryName { get; set; }

[Display(Name = "Description")]
[StringLength(255)]
[Column("LAND_TYPE_CAT_DESC", Order = 2, TypeName = "nvarchar")]
public string CategoryDescription { get; set; }

[Display(Name = "Created Date")]
[Column("CREATE_DATE", Order = 3, TypeName = "datetime")]
public DateTime? CreateDate { get; set; }

[Display(Name = "Modified Date")]
[Column("MODIFIED_DATE", Order = 4, TypeName = "datetime")]
public DateTime? ModifiedDate { get; set; }

[Display(Name = "Last Modified By")]
[StringLength(255)]
[Column("LAST_MODIFIED_BY", Order = 5, TypeName = "nvarchar")]
public string LastModifiedBy { get; set; }

ViewModels:用于创建:

[Display(Name = "Category Name")]
[Required(ErrorMessage = "This field is required.")]
[Remote("ValidateCreate", "Category", ErrorMessage = "This type already exists.")]
public string CategoryName { get; set; }

更新:

[Display(Name = "Category Name")]
[Required(ErrorMessage = "This field is required.")]
[Remote("ValidateEdit", "Category", AdditionalFields = "CategoryId, CategoryName",
    ErrorMessage = "This type already exists.")]
public string CategoryName { get; set; }

控制器:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(LandTypeCategoryCreateViewModels viewModel)
{
    if (ModelState.IsValid)
    {
        var vm = new LandTypeCategory
        {
            CategoryName = viewModel.CategoryName,
            CategoryDescription = viewModel.CategoryDescription,
            CreateDate = DateTime.Now,
            LastModifiedBy = "Tester"
        };

        _context.LandTypeCategories.Add(vm);
        await _context.SaveChangesAsync();

        TempData["Created"] = "New category type added.";
        var url = Url.Action("Index", "Category", new {id = viewModel.CategoryId});
        return Json(new {success = true, url});
    }

    return PartialView("_Create", viewModel);
}

public async Task<ActionResult> Edit(long? id)
{
    if (id == null)
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);

    var vm = await _context.LandTypeCategories.FindAsync(id);

    if (vm == null)
        return HttpNotFound();

    var viewModel = new LandTypeCategoryEditViewModels
    {
        CategoryId = vm.CategoryId,
        CategoryName = vm.CategoryName,
        CategoryDescription = vm.CategoryDescription
    };

    return PartialView("_Edit", viewModel);
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(LandTypeCategoryEditViewModels viewModel)
{
    if (ModelState.IsValid)
    {
        var vm =
            await _context.LandTypeCategories.SingleAsync(x => x.CategoryId == viewModel.CategoryId);

        vm.CategoryName = viewModel.CategoryName;
        vm.CategoryDescription = viewModel.CategoryDescription;
        vm.ModifiedDate = DateTime.Now;
        vm.LastModifiedBy = "Modify Tester";

        _context.Entry(vm).State = EntityState.Modified;
        await _context.SaveChangesAsync();

        TempData["Updated"] = "Category type updated.";
        var url = Url.Action("Index", "Category", new {id = viewModel.CategoryId});
        return Json(new {success = true, url});
    }

    return PartialView("_Edit", viewModel);
}

远程验证:

public async Task<JsonResult> ValidateCreate(string CategoryName)
{
    return
        Json(
            await _context.LandTypeCategories.AllAsync(
                c => c.CategoryName.ToLower() != CategoryName.ToLower()), JsonRequestBehavior.AllowGet);
}

public async Task<JsonResult> ValidateEdit(int CategoryId, string CategoryName)
{
    var category = await _context.LandTypeCategories.FindAsync(CategoryId);
    var result = true;

    if (category.CategoryName.ToLower() != CategoryName.ToLower())
        result =
            await _context.LandTypeCategories.AllAsync(
                c => c.CategoryName.ToLower() != CategoryName.ToLower());

    return Json(result, JsonRequestBehavior.AllowGet);
}

Index.cshtml

@model IEnumerable<MvcPPT.Models.LandTypeCategory>

@{
    ViewBag.Title = "Category";
}

<div class="container">
    <br />
    <br />
    <br />
    @Html.ActionLink("Add New", "Create", "Category", new { ViewBag.CategoryId }, new { data_modal = "", @class = "btn btn-primary", style = "position: absolute;background-color: #3498db; border-color: #3498db;" })
    <table class="table table-hover table-bordered" id="same-datatable" style="font-size: smaller; width: 100%;">
        <thead>
            <tr>
                <th>@Html.DisplayNameFor(model => model.CategoryId)</th>
                <th>@Html.DisplayNameFor(model => model.CategoryName)</th>
                <th>@Html.DisplayNameFor(model => model.CategoryDescription)</th>
                <th>@Html.DisplayNameFor(model => model.CreateDate)</th>
                <th>@Html.DisplayNameFor(model => model.ModifiedDate)</th>
                <th>@Html.DisplayNameFor(model => model.LastModifiedBy)</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model)
            {
                <tr>
                    <td>@Html.DisplayFor(modelItem => item.CategoryId)</td>
                    <td>@Html.DisplayFor(modelItem => item.CategoryName)</td>
                    <td>@Html.DisplayFor(modelItem => item.CategoryDescription)</td>
                    <td>@Html.DisplayFor(modelItem => item.CreateDate)</td>
                    <td>@Html.DisplayFor(modelItem => item.ModifiedDate)</td>
                    <td>@Html.DisplayFor(modelItem => item.LastModifiedBy)</td>
                    <td>
                        @Html.ActionLink("Edit", "Edit", "Category", new { id = item.CategoryId }, new { data_modal = "", @class = "btn btn-warning btn-xs" })
                        &nbsp;
                        @Html.ActionLink("Delete", "Delete", "Category", new { id = item.CategoryId }, new { data_modal = "", @class = "btn btn-danger btn-xs" })
                    </td>
                </tr>
            }
        </tbody>
    </table>
</div>

<div id="myModal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div id="myModalContent"></div>
        </div>
    </div>
</div>

_Create.cshtml

@model MvcPPT.ViewModels.LandTypeCategoryCreateViewModels

<div class="modal-header" style="background-color: #3498db; color: #fff;">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
    <h4 class="modal-title" id="myModalLabel">Add New Category Type</h4>
</div>

@using (Html.BeginForm())
{
    <div class="modal-body">
        @Html.AntiForgeryToken()

        <div class="form-horizontal">
            @Html.ValidationSummary(true, "", new {@class = "text-danger"})
            <div class="form-group">
                @Html.LabelFor(model => model.CategoryName, new {@class = "control-label col-md-4"})
                <div class="col-md-8">
                    @Html.EditorFor(model => model.CategoryName, new {htmlAttributes = new {@class = "form-control"}})
                    @Html.ValidationMessageFor(model => model.CategoryName, "", new {@class = "text-danger"})
                </div>
            </div>
            <div class="form-group">
                @Html.LabelFor(model => model.CategoryDescription, new {@class = "control-label col-md-4"})
                <div class="col-md-8">
                    @Html.EditorFor(model => model.CategoryDescription, new {htmlAttributes = new {@class = "form-control"}})
                    @Html.ValidationMessageFor(model => model.CategoryDescription, "", new {@class = "text-danger"})
                </div>
            </div>
            <div class="modal-footer" style="padding-right: 0px;">
                <input class="btn btn-success" type="submit" value="Save"/>
                <button class="btn btn-default" type="button" data-dismiss="modal">Cancel</button>
            </div>
        </div>
    </div>
}

@Scripts.Render("~/bundles/jqueryval")

_Edit.cshtml

@model MvcPPT.ViewModels.LandTypeCategoryCreateViewModels

<div class="modal-header" style="background-color: #3498db; color: #fff;">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
    <h4 class="modal-title" id="myModalLabel">Add New Category Type</h4>
</div>

@using (Html.BeginForm())
{
    <div class="modal-body">
        @Html.AntiForgeryToken()

        <div class="form-horizontal">
            @Html.ValidationSummary(true, "", new {@class = "text-danger"})
            <div class="form-group">
                @Html.LabelFor(model => model.CategoryName, new {@class = "control-label col-md-4"})
                <div class="col-md-8">
                    @Html.EditorFor(model => model.CategoryName, new {htmlAttributes = new {@class = "form-control"}})
                    @Html.ValidationMessageFor(model => model.CategoryName, "", new {@class = "text-danger"})
                </div>
            </div>
            <div class="form-group">
                @Html.LabelFor(model => model.CategoryDescription, new {@class = "control-label col-md-4"})
                <div class="col-md-8">
                    @Html.EditorFor(model => model.CategoryDescription, new {htmlAttributes = new {@class = "form-control"}})
                    @Html.ValidationMessageFor(model => model.CategoryDescription, "", new {@class = "text-danger"})
                </div>
            </div>
            <div class="modal-footer" style="padding-right: 0px;">
                <input class="btn btn-success" type="submit" value="Save"/>
                <button class="btn btn-default" type="button" data-dismiss="modal">Cancel</button>
            </div>
        </div>
    </div>
}

@Scripts.Render("~/bundles/jqueryval")

jQuery方式调用:

// Add new
    $.ajaxSetup({ cache: false });
    $("a[data-modal]").on("click",
        function (e) {
            $("#myModalContent").load(this.href,
                function () {
                    $("#myModal").modal({
                        keyboard: true
                    },
                        "show");
                    bindForm(this);
                });
            return false;
        });

function bindForm(dialog) {
    $("form", dialog).submit(function () {
        $.ajax({
            url: this.action,
            type: this.method,
            data: $(this).serialize(),
            success: function (result) {
                if (result.success) {
                    $("#myModal").modal("hide");
                    window.location.reload();
                } else {
                    $("#myModalContent").html(result);
                    bindForm(dialog);
                }
            }
        });
        return false;
    });
}

由于创建和编辑表单都是局部视图,我猜这将在同一主视图上呈现,因此我建议您删除

  @Scripts.Render("~/bundles/jqueryval")

从两个部分页面开始,并在主页顶部添加该行,因为当您单击创建按钮时,它将加载脚本包;再次单击您的编辑时,它将第二次加载脚本包

接下来是正确编写@ gtml.begin表单标签,例如

  @using (Html.BeginForm(ActionName , ControllerName, FormMethod.Post))

我不确定您的表格发布方式现在如何运作

选项1:

您可以在按钮提交后将其禁用。

$('form').submit(function() {
    $(this).find(':submit').attr('disabled', 'disabled');
});

选项2:

通过创建动作过滤器。 (因此,您可以在此处验证防伪令牌的重复。)

如何在不使用Javascript的情况下防止在.NET MVC中提交多种表单?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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