【问题标题】:Send post ajax request with antiforgery token in asp.net core do not access controller method在asp.net核心中发送带有防伪令牌的post ajax请求不要访问控制器方法
【发布时间】:2020-03-29 12:08:28
【问题描述】:

不确定我的请求有什么问题,但控制器操作显然没有收到我的帖子。我想使用防伪令牌发布此表单,并且我还想使用 ajax 请求。出于这个原因,我没有使用包含防伪令牌的默认 aspnet 核心表单,而是使用了 html 助手@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; }
    }

【问题讨论】:

    标签: c# jquery asp.net-core asp.net-core-mvc asp.net-core-webapi


    【解决方案1】:
    1. jqXHR.success()、jqXHR.error() 和 jqXHR.complete() 回调将在 jQuery 1.8 中被弃用。要为最终删除准备代码,请改用 jqXHR.done()、jqXHR.fail() 和 jqXHR.always()。

    2. 使用 ModelState Validation 验证您的模型

    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; }
    }
    

    控制器:-

    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;
        }
    }
    

    保存.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>
    }
    

    (已测试)

    【讨论】:

    • 嗨阿什库扎曼!谢谢您的回答。它看起来不错,但是我尝试过,并且有一个 get 请求发送到控制器而不是 post。我认为这与stackoverflow.com/questions/12195883/… 是同一个问题。另外,我有消息框“发生错误 2!”出现了。
    • @Hans 是的,你是对的。那是个问题。但是根据我的测试(.net core 3.1),这段代码是可以的。
    • Ashiquzzaman 我发现了我的问题。我在“form”标签上添加了method="post"。
    猜你喜欢
    • 2020-06-22
    • 2018-02-25
    • 2019-12-04
    • 2019-06-13
    • 2023-04-09
    • 2013-11-16
    • 2021-08-09
    • 1970-01-01
    • 2023-03-15
    相关资源
    最近更新 更多