Copied to clipboard

Flag this post as spam?

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


  • Peter Laurie 42 posts 116 karma points
    Dec 03, 2019 @ 22:44
    Peter Laurie
    0

    Passing complex object to Umbraco 8 Api Controller

    HI, I am looking at how to pass a complex object to an Umbraco 8 API Controller. I have managed Get (but with no value passed in), Also managed to pass a single string value to a controller. But so far all attempts at passing a complex object, such as the following JSON seems to have failed, with the normal response being a 404 error, where the url that is trying to be found is [object, object].

    I am trying to build upon the following post, which was excellent at getting me started: https://our.umbraco.com/forum/using-umbraco-and-getting-started/96824-custom-apicontroller-in-umbraco-8-cannot-be-reached

    This is the Plugin JS Controller code that connects to the ApiController:

    angular.module("umbraco").controller("SucuriCacheController", function (userService) {
      var vm = this;
      vm.UserName = "guest";
    
      var user = userService.getCurrentUser().then(function (user) {
        vm.UserName = user.name;
      });
    
      vm.clearSiteCache = clearSiteCache;
      vm.clearSelectedCache = clearSelectedCache;
    
      function clearSiteCache() {
        var nsurl = "/umb/api/sucuricacheapi/clearsitecache";
    
        axios.post(nsurl)
          .then(function (response) {
            if (response.data) {
              $('#confirm-site-cleared').text(response.data).removeClass('hidden');
              hideMsg('confirm-site-cleared');
              return
            }
          })
          .catch(function (error) {
            console.warn(error);
            $('#confirm-site-cleared').text(error).removeClass('hidden');
            hideMsg('confirm-site-cleared');
            return
          });
      }
    
      function clearSelectedCache(Path) {
        let _Path = Path.replace(new RegExp('/', 'g'), '--');
        let __Path = _Path.replace(".", "---");
        var nsurl = "/umb/api/sucuricacheapi/clearpathcache/" + __Path;
    
        axios.post(nsurl)
            .then(function (response) {
              if (response.data) {
                $('#confirm-url-file-cleared').text(response.data).removeClass('hidden');
                hideMsg('confirm-url-file-cleared');
                return
              }
            })
            .catch(function (error) {
              console.warn(error);
              $('#confirm-url-file-cleared').text(error).removeClass('hidden');
              hideMsg('confirm-url-file-cleared');
              return
            });
      }
    
      function hideMsg(element) {
        setTimeout(function () {
          $('#' + element).text('').addClass('hidden');
        }, 4000)
      }
    
    });
    

    So far, here is my API controller with the two functions I have manged to get working so far. We use Sucuri as a CDN and firewall, and the following functions connect to a class which links to Sucuri API to clear cache.

    using Umbraco8.Utils;
    using Umbraco8.Utils.Services;
    using Umbraco8.Utils.Sucuri;
    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Web.Http;
    using Umbraco.Web.WebApi;
    using static Umbraco8.ViewModel.UniversalViewModel;
    
    namespace Umbraco8.Controllers
    {
    
      public class SucuriCacheApiController : UmbracoApiController
     {
    private readonly ISiteService _siteService;
    public SucuriCacheApiController(ISiteService siteService)
    {
      _siteService = siteService ?? throw new ArgumentNullException(nameof(siteService));
    }
    
    
    #region test api
    
    //[HttpGet]
    //[Route("fish/api/members")]
    //public IEnumerable<string> GetAllMembers()
    //{
    //  return new[] { "Table", "Chair", "Desk", "Computer", "Beer fridge" };
    //}
    //[HttpGet]
    //public IEnumerable<string> GetAllMembers2()
    //{
    
    //  return new[] { "Table", "Chair", "Desk", "Computer", "Beer fridge" };
    //}
    
    #endregion
    
    
    //[GZipOrDeflate]
    [HttpGet]
    [Route("umb/api/sucuricacheapi/clearsitecache")]
    public async Task<string> ClearSiteCacheAsync()
    {
      string CacheCleared = "Cache clear failed";
    
      SucuriResponse cResponse = await ClearCache.ClearSiteCacheAsync().ConfigureAwait(true);
    
      if (cResponse.status == 1)
      {
        return cResponse.messages[0];
      }
      return CacheCleared;
    }
    
    
    [HttpGet]
    [Route("umb/api/sucuricacheapi/clearpathcache/{Path}")]
    public async Task<string> Post(string Path)
    {
      SucuriResponse cResponse = new SucuriResponse();
    
      string CacheCleared = "Cache clear failed";
      //string Path = "";
      if (!String.IsNullOrEmpty(Path))
      {
        cResponse = await ClearCache.ClearPathCacheAsync(Path).ConfigureAwait(true);
      }
    
      if (cResponse.status == 1)
      {
        return cResponse.messages[0];
      }
      return CacheCleared;
    }
    }
    }
    

    I have tried the following, but failed:

    axios.post(nsurl, {
    firstName: firstName,
    LastName : LastName,
    Email: EmailAddress}
    )
    .then(function (response) {
            if (response.data) {
              // do something
              return
            }
          })
          .catch(function (error) {
            console.warn(error);
            return
          });
    

    I have tried JSON.stringify etc. I am sure someone else would of encountered this problem, and hopefully can help with a solution.

    Kind regards,

    Pete

  • Nathan Woulfe 447 posts 1664 karma points MVP 5x hq c-trib
    Dec 03, 2019 @ 23:56
    Nathan Woulfe
    0

    Hi Pete

    Your post example sends data (the js object with firstName, LastName, Email) but your API method doesn't accept that as a param, it's expecting a string (Path). The Post method is also decorated with [HttpGet] attribute.

    I'd try adding the path parameter into the JS object, then creating a C# model for the method param:

    // js

    axios.post(nsurl, {
        firstName: firstName,
        lastName : LastName,
        email: EmailAddress
        path: __Path
    ).then(...)
    

    // c#

    [Route("umb/api/sucuricacheapi/clearpathcache")]
    public async Task<string> Post(PostDataModel model) {
        // do work
    }
    

    where PostDataModel looks something like this (will need JsonProperty attributes on the fields, to match the names in the JSON data):

    public class PostDataModel {
        [JsonProperty("firstName")]
        public string FirstName {get; set; }
    
        public string LirstName {get; set; }
    
        public string Email {get; set; }
    
        public string Path {get; set; }
    }
    
  • Peter Laurie 42 posts 116 karma points
    Dec 04, 2019 @ 21:55
    Peter Laurie
    0

    Hi Natham, Thank you for your reply, put me in the right direction. Here is my code in the Plugin JS Controller:

    function testComplexObject(FirstName, LastName, Email) {
    
        var nsurl = "/umb/api/sucuricacheapi/testcomplexobject";
    
        var postData = {
          firstName: FirstName,
          lastName: LastName,
          email: Email
        };
    
        let axiosConfig = {
          headers: {
            'Accept-Version': 1,
            'Accept': 'application/json',
            'Access-Control-Allow-Origin': '*',
            'Content-Type': 'application/json; charset=utf-8',
          }
        };
    
        axios.post(nsurl, postData, axiosConfig)
          .then(function (response) {
            if (console){
              console.log('response is: ', response.data)
            }
            if (response.data) {
              // do something
              return
            }
          })
          .catch(function (error) {
            console.warn(error);
            // do something
            return
          });
      }
    

    API Controller code:

    [AcceptVerbs("POST")]
        [HttpPost]
        [Route("umb/api/sucuricacheapi/testcomplexobject")]
        public async Task<Person> Post(Person model)
        {
          SucuriResponse cResponse = new SucuriResponse();
    
          model.status = true;
    
          return model;
        }
    

    and, as you suggested, with the JsonProperty attributes, a test model:

    public class Person
        {
          [JsonProperty("firstName")]
          public string firstName { get; set; }
          [JsonProperty("lastName")]
          public string lastName { get; set; }
          [JsonProperty("email")]
          public string email { get; set; }
          [JsonProperty("status")]
          public bool status { get; set; }
        }
    

    Thanks again, hope this is also useful for others: This could be a good start as well for creating a headless CMS. Now we can pass in complex models and query the Umbraco model and get back page values, add in some authentication...

    Kind regards,

    Pete

Please Sign in or register to post replies

Write your reply to:

Draft