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].
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;
}
}
}
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:
[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; }
}
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...
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:
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.
I have tried the following, but failed:
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
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
// c#
where PostDataModel looks something like this (will need JsonProperty attributes on the fields, to match the names in the JSON data):
Hi Natham, Thank you for your reply, put me in the right direction. Here is my code in the Plugin JS Controller:
API Controller code:
and, as you suggested, with the JsonProperty attributes, a test model:
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
is working on a reply...