在asp.net核心中发送带有防伪令牌的post ajax请求不能访问控制器方法

问题描述 投票:0回答:1

[不确定我的请求出了什么问题,但显然控制器操作未收到我的帖子。我想使用防伪令牌发布此表单,我也想使用ajax请求。因此,我没有使用包含防伪令牌的默认aspnet核心形式,而是使用了html helper @Html.AntiforgeryToken()。知道问题出在哪里吗?

@model RunViewModel
@{
        ViewData["Title"] = "Run";
    }
    <h1 class="text-info">@ViewData["Title"]</h1>

    <form id="run-form">
        @Html.AntiForgeryToken()
        <div class="form-group">
            <label asp-for="InstanceName"></label>
            <input asp-for="InstanceName" class="form-control" placeholder="Enter an instance name here..." />
        </div>
        <div class="form-group">
            <label asp-for="DatabaseName"></label>
            <input asp-for="DatabaseName" class="form-control" placeholder="Enter a database name here..." />
        </div>
        <div class="form-group">
            <label asp-for="FolderPath"></label>
            <input asp-for="FolderPath" class="form-control" />
        </div>
        <div class="col-3 offset-4">
            <button type="submit" class="btn btn-primary">Run!</button>
        </div>
    </form>
@section Scripts {
    <script>

        $("#run-form").submit(function () {

            var data = $('#run-form').serializeArray();
            console.log(data);

            alert($('input:hidden[name="__RequestVerificationToken"]').val());

            $.ajax({
                type: 'POST',
                url: '/Run/Run',
                contentType: 'application/json',
                headers: { RequestVerificationToken: $('input:hidden[name="__RequestVerificationToken"]').val() },
                data: JSON.stringify(data),
                success: function (data) {
                    if (data.status = "success") {
                        alert("Database has been updated !"); //TODO : Mettre un div vert avec un message à la place.
                    }
                },
                error: function () {
                    alert("An error occured 2!"); //TODO : Mettre un div rouge avec un message à la place.
                }
            });

            //event.preventDefault();
        });
    </script>
}

和控制器部分是:

        [HttpPost]
    [ValidateAntiForgeryToken]
    public JsonResult Run(string jsonObj)
    {
        //TODO : CHECK JSONOBJ
        RunViewModel model = JsonSerializer.Deserialize<RunViewModel>(jsonObj);

        try
        {
            //Call a service here...
        }
        catch (Exception ex)
        {

            //Renvoyer un message
        }

        return Json(model);
    }

并且视图模型为:

public class RunViewModel
    {
        [Required]
        [Display(Name="Instance name : ")]
        public string InstanceName { get; set; }

        [Required]
        [Display(Name="Database name : ")]
        public string DatabaseName { get; set; }

        [Required]
        [Display(Name="SQL folder path : ")]
        public string FolderPath { get; set; }

        /// <summary>
        /// Liste ordonnée des fichiers, regroupés par version, à lancer sur la base de données suivant la version actuelle de la base de données.
        /// </summary>
        public IOrderedEnumerable<IGrouping<Version, string>> SqlFilesGroupedByVersion { get; set; }
    }
ajax asp.net-core asp.net-core-mvc asp.net-core-webapi antiforgerytoken
1个回答
0
投票
  1. jqXHR.success(),jqXHR.error()和jqXHR.complete()回调在jQuery 1.8中将被弃用。要准备将其最终删除的代码,请改用jqXHR.done(),jqXHR.fail()和jqXHR.always()。

  2. 使用ModelState验证来验证模型

  3. [使用OnClick方法提交表单以避免e.reeventDefault()。

我根据您的要求在下面提供了一个完整的示例(请阅读所有内联注释-

型号:-

public class RunViewModel
{
    [Required]
    [Display(Name = "Instance name : ")]
    public string InstanceName { get; set; }

    [Required]
    [Display(Name = "Database name : ")]
    public string DatabaseName { get; set; }

    [Required]
    [Display(Name = "SQL folder path : ")]
    public string FolderPath { get; set; }

    /// <summary>
    /// Liste ordonnée des fichiers, regroupés par version, à lancer sur la base de données suivant la version actuelle de la base de données.
    /// </summary>
    public IOrderedEnumerable<IGrouping<Version, string>> SqlFilesGroupedByVersion { get; set; }
}

public class ValidationError
{

    public string PropertyName { get; set; }
    public string[] ErrorList { get; set; }
}

Controller:-

public class RunController : Controller
{
    [HttpGet]
    // GET: Run/Save
    public ActionResult Save()
    {
        var model = new RunViewModel();
        return View(model);
    }

    // POST: Run/Save
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Save(RunViewModel model)
    {
        var status = "Failed";
        var massage = "";
        try
        {
            //If modelstate validation need

            if (!ModelState.IsValid)
            {
                return Json(new
                {
                    status,
                    massage,
                    model,
                    errorList = GetModelStateErrors(ModelState).ToList()
                });
            }
            else
            {
                //Write your code

                status = "success";
                massage = "Database has been updated !";

            }

        }
        catch (Exception ex)
        {

            massage = ex.Message;
        }
        return Json(new
        {
            status,
            massage,
        });

    }

    public IEnumerable<ValidationError> GetModelStateErrors(ModelStateDictionary modelState)
    {
        var errors = (from m in modelState
                      where m.Value.Errors.Count() > 0
                      select
                         new ValidationError
                         {
                             PropertyName = m.Key,
                             ErrorList = (from msg in m.Value.Errors
                                          select msg.ErrorMessage).ToArray()
                         })
                            .AsEnumerable();
        return errors;
    }
}

Save.cshtml:-

@model RunViewModel
@{
    ViewData["Title"] = "Run";
}
<h1 class="text-info">@ViewData["Title"]</h1>
<style>
    .field-validation-valid{
        color:#FF0000;
    }
</style>
<form id="run-form">
    @Html.AntiForgeryToken()
    <div class="form-group">
        <label asp-for="InstanceName"></label>
        <input asp-for="InstanceName" class="form-control" placeholder="Enter an instance name here..." />
        <span asp-validation-for="InstanceName"></span>
    </div>
    <div class="form-group">
        <label asp-for="DatabaseName"></label>
        <input asp-for="DatabaseName" class="form-control" placeholder="Enter a database name here..." />
        <span asp-validation-for="DatabaseName"></span>
    </div>
    <div class="form-group">
        <label asp-for="FolderPath"></label>
        <input asp-for="FolderPath" class="form-control" />
        <span asp-validation-for="FolderPath"></span>

    </div>
    <div class="col-3 offset-4">
        <button type="button" id="btnSubmin" class="btn btn-primary">Run!</button>
    </div>
</form>
@section Scripts {
    <script>

        $("#btnSubmin").on("click", function () {
            var valToken = $('input:hidden[name="__RequestVerificationToken"]').val();
            var model = getFormData('run-form');
            $.ajax({
                type: 'POST',
                url: '/Run/Save',
                contentType: 'application/x-www-form-urlencoded',//set a Content-Type of application/json; charset=UTF-8 When Call API,application/x-www-form-urlencoded is the default contentType
                headers: { RequestVerificationToken: valToken },
                dataType: 'json',
                data: model,//you need to pass json string
            }).done(function (data) {
                if (data.status === "success") {
                    alert("Database has been updated !"); //TODO : Mettre un div vert avec un message à la place.
                } else {
                    displayValidationErrors(data.errorList);
                }
            }).fail(function (data) {

                    alert("An error occured 2!"); //TODO : Mettre un div rouge avec un message à la place.

            });
            /*

             The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks will be deprecated in jQuery 1.8. To prepare your code for their eventual removal, use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.

             */

        });

        //Show Validation Message
        function displayValidationErrors(errors) {
            $.each(errors, function (idx, validationError) {
                $("span[data-valmsg-for='" + validationError.propertyName + "']").text(validationError.errorList[0]);// if not working then captilized ex: errorList to ErrorList,propertyName to PropertyName
            });
        }

        //Convert to Json From InputForm
        function getFormData(formId) {
            var $form = $("#" + formId);
            var unindexed_array = $form.serializeArray();
            var indexed_array = {};

            $.map(unindexed_array, function (n, i) {
                indexed_array[n['name']] = n['value'];
            });
            return indexed_array;
        }

    </script>
}

(已测试)

© www.soinside.com 2019 - 2024. All rights reserved.