Umbraco 12 Surface Controller POST Method - unable to hit controller action

259 views Asked by At

I am pretty new to Umbraco and am using Umbraco 12. I have a surface controller that has a couple of Get endpoints which when sending requests to via Postman work, and a Post endpoint that I continually get a 400 Bad Request from.

The code below is a cut down version of the controller

[Controller]
public class EventsController : SurfaceController
{
    private readonly IPublishedContentQuery _contentQuery;

    public EventsController(
        IUmbracoContextAccessor umbracoContextAccessor,
        IUmbracoDatabaseFactory databaseFactory,
        ServiceContext services, AppCaches appCaches,
        IProfilingLogger profilingLogger,
        IPublishedUrlProvider publishedUrlProvider,
        IPublishedContentQuery contentQuery)
        : base(umbracoContextAccessor,
            databaseFactory,
            services,
            appCaches,
            profilingLogger,
            publishedUrlProvider)
    {
        _contentQuery = contentQuery;
    }

    [HttpGet]
    public IActionResult GetPlacements(int year, string titleEvent)
    {
        // Redacted - Can hit when going to its url
        https://localhost:44322/umbraco/surface/events/GetPlacements
    }

    [HttpPost]
    public IActionResult PostPlacement(string teamName, string iso3, string finalPlacement, string titleEvent, string eventYear)
    {
        var rootContent = _contentQuery.ContentAtRoot().ToList();
        var placementItems = rootContent.FirstOrDefault(x => x.Name == "Data")!.Children.FirstOrDefault(x => x.Name == "Event Placements");

        // redacted - Cannot hit when going to its url
        // https://localhost:44322/umbraco/surface/events/PostPlacement 

        return Ok();
    }
}

I have looked around and see that I need to send it as either form-data or x-www-form-urlencoded

The problems as I see it

enter image description here

  1. I dont have a lot of experience with Umbraco so its possible I have missed something pretty obvious.
  2. I havent added a validator so not sure why I am getting a 400 bad request
  3. I have tried adding [FromForm] in the method to the parameters and still not working
  4. I have not yet tried binding it to a model
  5. I have tried adding a route but then I get a 404
  6. I have also seen this Umbraco surface controller not submitting to backend with POST and am trying this at the same time, but still no luck.

The need for this is that this endpoint will be send data from external systems and then I have a View that is being hit, that will then present the data (That bit does work).

1

There are 1 answers

1
Michaël LEBRETON On

Different points to consider

  1. Direct answer : Decorate your action's method with [Http, IgnoreAntiforgeryToken] attributes and it should work (keep me posted).

WHY

  1. SurfaceControllers are very special controllers deeply linked to Umbraco's behaviors. Therefore, they have special behaviors. A lot of things are done for you behind the scene. And in this case, by default, SurfaceControllers are designed to work with an HTML FORM containg an Antiforgery Token.

In Umbraco documentation (https://docs.umbraco.com/umbraco-cms/reference/routing/surface-controllers/) when you read :

Is used for interacting with the front-end of Umbraco (not the backoffice)

You must anderstand : "Is used for interacting with A PAGE (CONTENT) THAT HAS BEEN GENERATED BY UMBRACO AND USE SOME UMBRACO'S FEATURES (not the backoffice)"

In that context, your controller has a this.UmbracoContext.PublishedRequest property containing the IPublishedContent of the calling page.

  1. Regarding your need

The need for this is that this endpoint will be send data from external systems

The documentation should contains SurfaceControllers are not designed to create API (Application 2 Application). They are designed for Page (content) 2 SurfaceController API.

When you use a surface controller for A2A API, then this.UmbracoContext.PublishedRequest property is null (and many other things are not working).

To create real A2A API (REST or not) :

  • create a basic ASP Net controller
  • Use dependency injection to get your services (not all the services are available : you are not in the context of a page's call).
  • depending of your version of Umbraco, you may have to set a custom route.