1

I have a view that is NOT a form. I am doing an Ajax POST with jQuery to the server without having any form at all. It displays a blog and also it accepts a blog comment. I want to take that blog comment and save it to the database.

I'm getting: The required anti-forgery form field"__RequestVerificationToken" is not present in asp.net mvc

I modified the code to reflect the suggestions from a prior solution.

I have a @Html.AntiForgeryToken() right before the text field (the blog comment) that I want to use to save to the database.

I have the [ValidateAntiForgeryToken] attribute before the controller aciton method.

I pass append the token to the data to be sent to the method: data: AddAntiForgeryToken({ blogComment, userProfileProcessType }),

But it still does not work.


Here is the view:

<h2 class="page-header"><span class="blogtitle">@Session["BlogTitle"]</span></h2>

@{
    Layout = "~/Views/Shared/_LayoutUser.cshtml";
}

@if (ViewBag.errormessage != null)
{
    <p class="alert alert-danger" id="errorMessage">@ViewBag.errormessage</p>
}

<br />

<div>
    <a href="@Url.Action("LoadDropdownBlogCategorysInBlogsPublished", "BlogPublished")">Return To Select a Blog</a>
</div>
<br />

@if (Model != null)
{
<div class="panel panel-default toppanel">
    <div class="panel-body">
        <div class="row">
            <div class="col-md-2">
                @Html.LabelFor(model => model.BlogPublishedByBlogId.CreatedDateTime)
                @Html.TextBoxFor(model => model.BlogPublishedByBlogId.CreatedDateTime, new { @class = "form-control", @disabled = "disabled" })
            </div>
            <div class="col-md-2">
                @Html.LabelFor(model => model.BlogPublishedByBlogId.ModifiedDateTime)
                @Html.TextBoxFor(model => model.BlogPublishedByBlogId.ModifiedDateTime, new { @class = "form-control", @disabled = "disabled" })
            </div>
        </div>
        <br />

        <div class="row">
            <div>
                @Html.DisplayFor(model => model.BlogPublishedByBlogId.BlogContent, new { @class = "form-control blogContent", @disabled = "disabled" })
            </div>
        </div>
        <br />
        <br />

        <div class="panel-footer">
            <button type="button" class="btn btn-primary Comment" data-id="@Model.BlogPublishedByBlogId.BlogId" value="Comment">
                <span class="glyphicon glyphicon-comment" aria-hidden="true"></span> Get Comment(s)
            </button>
        </div>
        <div id="@string.Format("{0}_{1}","commentsBlock", @Model.BlogPublishedByBlogId.BlogId)" style="border: 1px solid #f1eaea; background-color: #eaf2ff;">
            <div class="AddCommentArea" style="margin-left: 30%;  margin-bottom: 5px; margin-top: 8px;">
                @Html.AntiForgeryToken()
                <input type="text" id="@string.Format("{0}_{1}", "comment", @Model.BlogPublishedByBlogId.BlogId)" class="form-control" placeholder="Add a comment..." style="display: inline;" />
                <button type="button" class="btn btn-primary addComment" data-id="@Model.BlogPublishedByBlogId.BlogId"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span></button>
            </div>
        </div>
    </div>
</div>
}

@Scripts.Render("~/bundles/jqueryval")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@Styles.Render("~/Content/css")

@section Scripts
{
<script type="text/javascript">
    $(document).ready(function () {
        $('.Comment').on('click', function () {
            var blogId = $(this).attr("data-id");
            var allCommentsArea = $('<div>').addClass('allComments_' + blogId);

            $.ajax({
                type: 'GET',
                url: '@Url.Action("GetBlogComments", "BlogPublished")',
                data: { blogId: blogId },
                success: function (response) {
                    if ($('div').hasClass('allComments_' + blogId + ''))
                    {
                        $('div[class=allComments_' + blogId + ']').remove();
                    }

                    // Dynamically building the HTML to hold the comments (the list) returned.
                    // The area for the BlogPublished/_Comments.cshtml to be placed.
                    allCommentsArea.html(response);
                    allCommentsArea.prependTo('#commentsBlock_' + blogId);
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    alert("Critical Error: something is wrong in the call to GetBlogComments! Status: " + xhr.status + ". Error: " + thrownError.toString() + ". Response Text: " + xhr.responseText);
                }
            })
        });

        // For when clicking the 'addComment' button.
        $('.addComment').on('click', function () {
            var blogId = $(this).attr('data-id');
            var blogCommentContent = $('#comment_' + blogId).val();
            var dateTimeNow = new Date();
            var userProfileProcessType = "I";

            // An object - the BlogComment model to be passed to the controller method.
            var blogComment = {
                BlogId: blogId,
                BlogCommentContent: blogCommentContent,
                DateTimeOfBlogComment: dateTimeNow.toLocaleString()
            };

            $.ajax({
                type: 'POST',
                url: '@Url.Action("ProcessSaveBlogComment", "BlogPublished")',
                data: AddAntiForgeryToken({ blogComment, userProfileProcessType }),
                success: function (response) {
                    $('div[class=allComments_' + blogId + ']').remove();

                    // Dynamically building the HTML to hold the comments (the list) returned which now includes the added comment.
                    var allCommentsArea = $('<div>').addClass('allComments_' + blogId);

                    allCommentsArea.html(response);
                    allCommentsArea.prependTo('#commentsBlock_' + blogId);

                    $("#comment_" + blogId).val('')
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    alert("Critical Error: something is wrong in the call to ProcessSaveBlogComment! Status: " + xhr.status + ". Error: " + thrownError.toString() + ". Response Text: " + xhr.responseText);
                }
            });
        });

        jQuery(".timeago").timeago();
    });

    AddAntiForgeryToken = function (data) {
        data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
        return data;
    };
</script>
}

Here is the controller:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> ProcessSaveBlogComment(BlogComment blogComment, string userProfileProcessType)
    {
        if (ModelState.IsValid)
        {
            blogComment.UserId = Convert.ToInt32(Session["UserId"]);
            BLL_BlogPublished bll_BlogPublished = new BLL_BlogPublished();
            ProcessSaveBlogCommentResults processSaveBlogCommentResults = new ProcessSaveBlogCommentResults();

            try
            {
                processSaveBlogCommentResults = await bll_BlogPublished.ProcessSaveBlogComment(blogComment, Session["UserName"].ToString(), userProfileProcessType);

                if (processSaveBlogCommentResults.ApiErrorMessage == null)
                {
                    if (processSaveBlogCommentResults.Status == 2)
                    {
                        ViewBag.errormessage = "Process Violation: You are not the 'blog comment' creator so you cannot update the blog comment.";
                    }
                    else if (processSaveBlogCommentResults.Status == 3)
                    {
                        ViewBag.errormessage = "Process Violation: Not the correct 'blog id' so cannot update the blog comment.";
                    }
                }
                else
                {
                    ViewBag.errormessage = processSaveBlogCommentResults.ApiErrorMessage;
                }
            }
            catch (Exception ex1)
            {
                exceptionMessage = "Server error on saving the blog comment. Please contact the administrator.";

                try
                {
                    ClientErrorResult clientErrorResult = new ClientErrorResult();

                    clientErrorResult = await ProcessClientError(Session["UserName"].ToString(), ex1.Message, "Server error on saving the blog comment. User name: " + Session["UserName"] + ". Post method: ProcessSaveBlogComment.");

                    if (clientErrorResult.ApiErrorMessage == null)
                    {
                        ViewBag.errormessage = exceptionMessage;
                    }
                    else
                    {
                        ViewBag.errormessage = clientErrorResult.ApiErrorMessage;
                    }
                }
                catch (Exception ex2)
                {
                    ViewBag.errormessage = "Failure in ProcessClientError. Exception error: " + ex2.Message + ". Original error: " + exceptionMessage;
                }
            }
        }

        return RedirectToAction("GetBlogComments", "BlogPublished", new {blogId = blogComment.BlogId });
    }

Before leaving the AddAntiForgeryToken function - the console log.

enter image description here

The network tab - cookies.

enter image description here

Part 1 of the Network tab - header (has the request verification token in the cookie).

enter image description here

Part 2 of the Network tab - header (has the my data to send to the controller).

enter image description here

Error:

8/13/2020 4:49:56 PM

Controller Name :- BlogPublished Action Method Name :- ProcessSaveBlogComment

System.Web.Mvc.ExceptionContext Message --- {0}The required anti-forgery form field "__RequestVerificationToken" is not present. .Net Error --- {0}Check MVC Ajax Code For Error Source --- {0}System.Web.WebPages StackTrace --- {0} at System.Web.Helpers.AntiXsrf.TokenValidator.ValidateTokens(HttpContextBase httpContext, IIdentity identity, AntiForgeryToken sessionToken, AntiForgeryToken fieldToken) at System.Web.Helpers.AntiXsrf.AntiForgeryWorker.Validate(HttpContextBase httpContext) at System.Web.Helpers.AntiForgery.Validate() at System.Web.Mvc.ValidateAntiForgeryTokenAttribute.OnAuthorization(AuthorizationContext filterContext) at System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor) at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass3_1.b__0(AsyncCallback asyncCallback, Object asyncState) TargetSite --- {0}Void ValidateTokens(System.Web.HttpContextBase, System.Security.Principal.IIdentity, System.Web.Helpers.AntiXsrf.AntiForgeryToken, System.Web.Helpers.AntiXsrf.AntiForgeryToken)

user3020047
  • 868
  • 1
  • 15
  • 45
  • Your POST method is decorated with `[ValidateAntiForgeryToken]` and yet you aren't sending an anti forgery token in your AJAX payload. – devlin carnate Aug 13 '20 at 19:18
  • Does this answer your question? [jQuery Ajax calls and the Html.AntiForgeryToken()](https://stackoverflow.com/questions/4074199/jquery-ajax-calls-and-the-html-antiforgerytoken) – devlin carnate Aug 13 '20 at 19:25
  • Per that link, I modified the code to reflect the suggestions, but I get the same error. I do not however include a header or datatype. I send back an object and a variable so not sure what that datatype would be. – user3020047 Aug 13 '20 at 19:43
  • Did you modify your master page to add a form an token? If yes, then what's the value that's being returned from the AddAntiForgeryToken function? – devlin carnate Aug 13 '20 at 20:03
  • I only added the @Html.AntiForgeryToken() just above the text field in this view as I did not think I needed to add it to the master page (I will reread that link). That function returns [object object] when I issue an alert. – user3020047 Aug 13 '20 at 20:13
  • That's correct -- you don't have to put it on the master page if it's on the "current" page. It just needs to be accessible to JS. Try using console.log() instead of alert, although the fact that you're getting an object is a good sign that it's actually getting a token. Can you see the token in your AJAX payload when you inspect it in F12 Network tab? – devlin carnate Aug 13 '20 at 20:18
  • I added screen shots of the debugging. The token is in a Cookie. – user3020047 Aug 13 '20 at 20:53

0 Answers0