Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Lukaz 44 posts 202 karma points
    Jul 06, 2022 @ 12:42
    Lukaz
    0

    V10 - Need help, Can't get ajax fetch post working using SurfaceController

    I'm having trouble to get this work. I'm trying to do ajax post using javascript fetch, and always get status error 400. It works with ApiController but not with SurfaceController.

    Here is the code, please help. Kind regards.

    Home.chstml

        @using Umbraco.Cms.Web.Common.PublishedModels;
        @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ContentModels.Home>
        @using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
        @{
            Layout = "Main.cshtml";
        }
        <div id="container"></div>
    
    
    
    
    
    <script>
            function LoadPartialView() {
                fetch('/umbraco/surface/test/getpartialview')
                .then(response => response.ok ? response.text() : console.log('error', response))
                .then(content => document.getElementById('container').innerHTML = content)
                .catch(error => console.log('Request Failed:', error));    
            }
    
            LoadPartialView(); // Works
    
            function PostDummyData() {
    
                var data = {
                    title: 'foo',
                    body: 'bar',
                    userId: 1,
                };
    
                fetch('/umbraco/surface/test/postdummydata', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify(data),
                })
                .then(response => response.ok ? response.json() : console.log('error', response))
                .then(json => console.log('Json Response:', json))
                .catch(error => console.log('Request failed:', error)); 
            }
    
            PostDummyData(); // Doesn't work
    
     function PostDummyDataApi() {
    
                var data = {
                    title: 'foo',
                    body: 'bar',
                    userId: 1,
                };
    
                fetch('/umbraco/api/testo/postdummydata', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify(data),
                })
                .then(response => response.ok ? response.json() : console.log('error', response))
                .then(json => console.log('Json Response:', json))
                .catch(error => console.log('Request failed:', error)); 
            }
    
            PostDummyDataApi(); // works
        </script>
    

    TestController.cs

    using Microsoft.AspNetCore.Mvc;
    using umb10.Models;
    using Umbraco.Cms.Core.Cache;
    using Umbraco.Cms.Core.Logging;
    using Umbraco.Cms.Core.Routing;
    using Umbraco.Cms.Core.Services;
    using Umbraco.Cms.Core.Web;
    using Umbraco.Cms.Infrastructure.Persistence;
    using Umbraco.Cms.Web.Website.Controllers;
    
    namespace umb10.Controllers
    {
        public class TestController : SurfaceController
        {
            private readonly IUmbracoContextAccessor umbracoContextAccessor;
            private readonly IUmbracoDatabaseFactory databaseFactory;
            private readonly ServiceContext services;
            private readonly AppCaches appCaches;
            private readonly IProfilingLogger profilingLogger;
            private readonly IPublishedUrlProvider publishedUrlProvider;
    
            public TestController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider) : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider)
            {
                this.umbracoContextAccessor = umbracoContextAccessor;
                this.databaseFactory = databaseFactory;
                this.services = services;
                this.appCaches = appCaches;
                this.profilingLogger = profilingLogger;
                this.publishedUrlProvider = publishedUrlProvider;
    
            }
    
            public IActionResult GetPartialView()
            {
                return PartialView("~/Views/Partials/Test.cshtml");
            }
    
            [HttpPost]
            public IActionResult PostDummyData(PostModel postModel)
            {            
                return Ok(postModel);
            }
        }
    
    }
    

    PostModel.cs

    namespace umb10.Models
    {
        public class PostModel
        {
            public string Title { get; set; }
            public string Body { get; set; }
            public int UserId { get; set; }
        }
    }
    

    Testo Api Controller

    using Microsoft.AspNetCore.Mvc;
    using umb10.Models;
    using Umbraco.Cms.Web.Common.Controllers;
    
    namespace umb10.Controllers
    {
        public class TestoController : UmbracoApiController
        {
            public IActionResult GetPartialView()
            {
                return Content("~/Views/Partials/Test.cshtml");
            }
    
            [HttpPost]
            public IActionResult PostDummyData(PostModel postModel)
            {
                return Ok(postModel);
            }
        }
    }
    
  • Andrey Karandashov 23 posts 215 karma points c-trib
    Jul 06, 2022 @ 12:47
    Andrey Karandashov
    100

    Validation of Anti forgery token is enabled by default for v9/v10 now, so it returns 400 cuz you don't have anti forgery token in your request. You can disable it if you will add the ignore attribute: [IgnoreAntiforgeryToken]

    You can read a details here: https://our.umbraco.com/documentation/reference/routing/surface-controllers

  • Lukaz 44 posts 202 karma points
    Jul 06, 2022 @ 13:02
    Lukaz
    0

    @Andrey I added [IgnoreAntiforgeryToken] as you mentioned, and now hits the function on the server end, but my postModel is null. Something isn't working as it should. The passed data looks fine, and the data is the same as I send for api controller example which are passed fine.

  • Lukaz 44 posts 202 karma points
    Jul 06, 2022 @ 13:12
    Lukaz
    1

    I managed to get it working.

    Here is the working solution if you choose to Ignore AntiforgeryToken: Added extra [FromBody]

    [HttpPost, IgnoreAntiforgeryToken]
    public IActionResult PostDummyData([FromBody]PostModel postModel)
    {            
         return Ok(postModel);
    }
    

    I'll also add link to this thread: https://github.com/umbraco/UmbracoDocs/issues/3242

    If you want to pass AntiforgeryToken with your ajax post request:

    In Home.cshtml add:

    @Html.AntiForgeryToken() 
    

    In fetch pass new header RequestVerificationToken like this:

    <script>
    function PostDummyData() {
    
            var data = {
                title: 'foo',
                body: 'bar',
                userId: 1,
            };
    
            fetch('/umbraco/surface/test/postdummydata', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'RequestVerificationToken': document.getElementsByName('__RequestVerificationToken')[0].value
                },
                body: JSON.stringify(data),
            })
            .then(response => response.ok ? response.json() : console.log('error', response))
            .then(json => console.log('Json Response:', json))
            .catch(error => console.log('Request failed:', error)); 
        }
    
        PostDummyData();
    </script>
    

    In TestController.cs (surface controller as of v9 SurfaceControllers now by default have the anti-forgery check)

    [HttpPost]
    public IActionResult PostDummyData([FromBody]PostModel postModel)
    {            
        return Ok(postModel);
    }
    
  • Huw Reddick 1737 posts 6098 karma points MVP c-trib
    Jul 06, 2022 @ 13:31
    Huw Reddick
    0

    I have alse needed to do the following, depending how your model is created/used

    public IActionResult PostDummyData([Bind(Prefix="Page")]PostModel postModel)
    
Please Sign in or register to post replies

Write your reply to:

Draft