0

I have following jQuery code which posts data with JSON.stringify to ASP.NET MVC controller class. Everything works fine without the introduction of the AntiForgeryToken. Now when I start implementing the AntiForgeryToken within the code base it is not working and throwing an error: The required anti-forgery form field "__RequestVerificationToken" is not present.

HTML

<form action="javascript: void(0)" id="frmMain">
    @Html.AntiForgeryToken()
    ....
</form>

jQuery Code:

function saveDetails() {              
    var testViewModel = {};
    testViewModel.ArticleType = $("#SubType").val()
    testViewModel.PublishedDate = $("#publishDate").val();
    var token = $('#frmMain input[name=__RequestVerificationToken]').val();

    var languages = [];
    $.each($('#language').val(), function (index, value) {
        var languageContent = {};
        languageContent.Language = value;
        languageContent.Author = $("#author-" + value).val();
        languageContent.TeaserText = $("#teaser-" + value).val();
        languageContent.body = $("#content-" + value).val();
        languageContent.Title = $("#title-" + value).val();
        languages.push(languageContent);
    });
    testViewModel.LanguageContent = languages;
    testViewModel.Author = testViewModel.LanguageContent[0].Author;
    testViewModel.ArticleId = aId;

    $.ajax({
        type: "POST",
        url: "@Url.Action("SaveDetails", "Test")",
        data: JSON.stringify({ articleViewModel: articleViewModel, __RequestVerificationToken: token  }),
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        cache: false,
        success: function (data) {
            var url = "@Url.Action("SiteDetails", "Test")";
            window.location.href = url + "?ArticleId=" + aId;
        }
    });
}

TestController.cs

[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult SaveDetails([Bind(Include = "ArticleId,PublishedDate,Author,ArticleType,LanguageContent")]TestObject testViewModel)
{
  if (!ModelState.IsValid)
  {
        return Json(new { success = false });
  }
}

Can any one help me here by providing their guidance to fix this issue

Nkosi
  • 235,767
  • 35
  • 427
  • 472
santosh kumar patro
  • 7,231
  • 22
  • 71
  • 143
  • remove json and stringify and just post the data as is – Nkosi Aug 24 '17 at 16:01
  • Refer [this answer](https://stackoverflow.com/questions/45773645/the-required-anti-forgery-form-field-requestverificationtoken-is-not-present/45777177#45777177). But the fact your generating form controls for a collection with those `id` attributes suggest your doing this all wrong. –  Aug 24 '17 at 22:32
  • And the fact your using ajax to submit a for and then redirect is pointless. Just generate your view correctly (refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943) for generating form controls for a collection, or [this one](http://stackoverflow.com/questions/28019793/submit-same-partial-view-called-multiple-times-data-to-controller/28081308#28081308) if dynamically adding controls) and make a normal submit and redirect in the POST method –  Aug 24 '17 at 22:39
  • Thanks Stephen for your solution. I agree with you and will definitely implement the approach suggested in the links provided by you. – santosh kumar patro Aug 25 '17 at 07:20

1 Answers1

1

I added another filter:

namespace TestDetails.Controllers
{
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public sealed class ValidateHeaderAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            var httpContext = filterContext.HttpContext;
            var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
            AntiForgery.Validate(cookie != null ? cookie.Value : null, httpContext.Request.Headers["__RequestVerificationToken"]);
        }
    }
}

TestController.cs

[HttpPost]
[ValidateHeaderAntiForgeryToken]
public JsonResult SaveDetails([Bind(Include = "ArticleId,PublishedDate,Author,ArticleType,LanguageContent")]TestObject testViewModel)
{
  if (!ModelState.IsValid)
  {
        return Json(new { success = false });
  }
}

function saveDetails() {              
    var testViewModel = {};
    testViewModel.ArticleType = $("#SubType").val()
    testViewModel.PublishedDate = $("#publishDate").val();
    var token = $('#frmMain input[name=__RequestVerificationToken]').val();

    var languages = [];
    $.each($('#language').val(), function (index, value) {
        var languageContent = {};
        languageContent.Language = value;
        languageContent.Author = $("#author-" + value).val();
        languageContent.TeaserText = $("#teaser-" + value).val();
        languageContent.body = $("#content-" + value).val();
        languageContent.Title = $("#title-" + value).val();
        languages.push(languageContent);
    });
    testViewModel.LanguageContent = languages;
    testViewModel.Author = testViewModel.LanguageContent[0].Author;
    testViewModel.ArticleId = aId;


    $.ajax({
        type: "POST",
        url: "@Url.Action("SaveDetails", "Test")",        
        headers: {
                "__RequestVerificationToken": token
        },
        data: JSON.stringify(testViewModel),
        cache: false,
        success: function (data) {
            var url = "@Url.Action("SiteDetails", "Test")";
            window.location.href = url + "?ArticleId=" + aId;
        }
    });
}

It is working fine now.

santosh kumar patro
  • 7,231
  • 22
  • 71
  • 143