Deserializing Media field fails in Piranha CMS

  Kiến thức lập trình

Modifying Piranha for ‘headless’ scenario: I separated the api into its own REST API, and the MVC into its own UI that calls the REST API. Mostly it works well, but now an obstacle. My REST API serializes the result from the Piranha api, and my MVC web deserializes it into a Piranha StandardPage type. This works for all fields except Media, which is always null. Using newtonsoft.Json.

The Media property is defined in Piranha.Extend.Fields.MediaFieldBase with internal set, which explains why I can’t deserialize into it. So I added a [JsonProperty] attribute to the Media property. Once I did this, then the Media field was correctly deserialized by the MVC, and images appeared.

But then I found this broke something else: in the manager, when I try to save a page with a Hero image, the Save buttons spins, stops as though it succeeded, but the toast never appears saying success. I set Debug logging for Microsoft.AspNetCore.Mvc.Infrastructure, and see there’s a model state error when this happens:

dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2]
      Executed controller factory for controller Piranha.JA.Manager.Controllers.PageApiController (Piranha.JA.Manager)
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilter[1]
      The request has model state errors, returning an error response.
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[3]
      Request was short circuited at action filter 'Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilter'.

I can debug into the PageApiController for most operations, but when Save executes none of the breakpoints are hit.

I also tried just removing the internal accessor from set (and removing [JsonProperty]) and got the same behavior: can deserialize Media ok but trying to save page with a Hero from manager gives model state error.

Would love to write up some documentation on how to go headless if we can solve this.

We’ve been debugging this one for a few days, can anyone help?

In the branch I pushed I actually changed the accessor to public, so you shouldn’t need the additional attribute. This is also merged to master and will be released in 8.3.

Regards

I posted this on the Piranha CMS github and one of its authors, Hakan Edling, answered in just a few hours:

“The root issue is that when a new item is selected in the manager in the media picker, the media model that is assigned contains a formatted string size “xxx kb”. When ASP.NET tries to deserialize this into a long it fails.
So changing the following line in the .vue components for the media-based fields:

this.model.media = media;

to

this.model.media = {
    id: media.id,
    folderId: media.folderId,
    type: media.type,
    filename: media.filename,
    contentType: media.contentType,
    publicUrl: media.publicUrl,
};

Resolves the serialization error in the manager when the Media property is public.. I’ll push this fix to a new branch so you can test it.”

And soon after,
“Please test with the branch https://github.com/PiranhaCMS/piranha.core/tree/features/make-mediafield-media-public”

I still must add the [JsonProperty] attribute to the Media field in MediaFieldBase class, so my deserializer can access the internal set method. Hakan’s fix makes it so this attribute doesn’t break the manager.

Thank you for your quick response Hakan, you rock!

LEAVE A COMMENT