supabase-community / postgrest-csharp

A C# Client library for Postgrest
https://supabase-community.github.io/postgrest-csharp/api/Postgrest.html
MIT License
114 stars 22 forks source link

Getting System.NotSupportedException on Azure App Service #80

Open Dre-Tas opened 6 months ago

Dre-Tas commented 6 months ago

Bug report

Describe the bug

In supabase have a Recipes table with 2 columns: id (int8 and primary key) and Name (text)

So in my C# code I have a Recipe class:

using Postgrest.Attributes;
using Postgrest.Models;

namespace Planner.Classes
{
    [Table("Recipes")]
    public class Recipe : BaseModel
    {
        [PrimaryKey("id")]
        public int Id { get; set; }
        [Column("Name")]
        public string Name { get; set; }
        [Reference(typeof(Ingredient))]
        public List<Ingredient> Ingredients { get; set; }
    }
}

where Ingredients is coming from a many-to-many join table (which I believe shouldn't be important now...I think)

In a separate project in the same solution I have created a .NET Core 6.0 API with a controller. To make it extremely simple right now for reporting, the controller is this:

using Microsoft.AspNetCore.Mvc;
using WeeklyMealPlanner.Classes;

namespace PlannerApi.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class RecipesController : ControllerBase
    {
        [HttpGet(Name = "GetRecipes")]
        public List<Recipe> GetRecipes()
        {
            return new List<Recipe> { new Recipe { Name = "A" } };
        }
    }
}

When I test this locally with a console app, everything works normally and I get a list of all my recipes stored in supabase, their ingredients, etc. But when I publish this to Azure App Service then I get a 500 error in the browser and if I check Application Insights I see that it's reporting a System.NotSupportedException at System.Text.Json.ThrowHelper.ThrowNotSupportedException_DictionaryKeyTypeNotSupported with this message: "The type 'Postgrest.Attributes.PrimaryKeyAttribute' is not a supported dictionary key using converter of type 'System.Text.Json.Serialization.Converters.SmallObjectWithParameterizedConstructorConverter5[Postgrest.Attributes.PrimaryKeyAttribute,System.String,System.Boolean,System.Object,System.Object]'. Path: $.PrimaryKey. The type 'Postgrest.Attributes.PrimaryKeyAttribute' is not a supported dictionary key using converter of type 'System.Text.Json.Serialization.Converters.SmallObjectWithParameterizedConstructorConverter5[Postgrest.Attributes.PrimaryKeyAttribute,System.String,System.Boolean,System.Object,System.Object]'. "

I have upgraded all packages including supabase-csharp, postgrest-csharp and Newtonsoft.Json

I also tried to modify the Recipe class so that it doesn't use any postgrest or supabase library and my controller returns correctly a recipe of name "A" in Chrome.

namespace WeeklyMealPlanner.Classes
{
    public class Recipe
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List<Ingredient> Ingredients { get; set; }
    }
}

I'm really out of ideas right now.

Am I doing something wrong??

PS. Thanks for supabase!!. I just recently discovered it and it awesome!! Keep up the good work!

System information

wiverson commented 6 months ago

Not sure off the cuff, but a few ideas off the top of my head:

I also popped your Q into an LLM to see what it would suggest and it came back with these two ideas...

To resolve this issue, you can try the following steps:

Use the [JsonProperty] attribute from Newtonsoft.Json: Replace the Postgrest-specific attributes with [JsonProperty] attributes from the Newtonsoft.Json library. This will ensure that the JSON serialization process is consistent across different environments.

Here's an example of how you can modify your Recipe class:

using Newtonsoft.Json;

public class Recipe
{
    [JsonProperty("id")]
    public int Id { get; set; }
    [JsonProperty("Name")]
    public string Name { get; set; }
    public List<Ingredient> Ingredients { get; set; }
}

Check JSON Serialization Settings: Make sure that your JSON serialization settings are consistent between your local environment and Azure App Service. You can configure JSON serialization settings in your Startup.cs or wherever you configure your JSON serialization. Ensure that you are using Newtonsoft.Json as the JSON serializer and that the settings are the same in both places.

// In Startup.cs or your configuration file
services.AddControllers().AddNewtonsoftJson(options =>
{
    options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // This may be needed for your relationships.
});
Dre-Tas commented 6 months ago

Legend!! Thanks @wiverson !

I didn't try using the [JsonProperty] attribute as I first tried adding the Newtonsoft options to Program.cs and that did the trick (also adding the Microsoft.AspNetCore.Mvc.NewtonsoftJson) as required in order to have the AddNewtonsoftJson method).

Would you be able to explain why that fixed it though? I'd be curious to understand.

Thank you so much again!