abp icon indicating copy to clipboard operation
abp copied to clipboard

Cant cast ExtraProperty to the needed class

Open MisterCat100 opened this issue 7 months ago • 9 comments

Is there an existing issue for this?

  • [x] I have searched the existing issues

Description

public static List<Article>? GetFavouriteArticles( this IdentityUser user) { return user.GetProperty( ArthiveConsts.FavouriteArticlesPropertyName).As<List<Article>?>(); }

This is code in the extension file When i call it, appears problem: Unable to cast object of type 'System.Text.Json.JsonElement' to type 'System.Collections.Generic.List1[Arthive.Articles.Article]'. System.InvalidCastException: Unable to cast object of type 'System.Text.Json.JsonElement' to type 'System.Collections.Generic.List1[Arthive.Articles.Article]'.

Reproduction Steps

Cast nonGeneric GetProperty in the extension

Expected behavior

No response

Actual behavior

No response

Regression?

No response

Known Workarounds

No response

Version

8.2.1

User Interface

MVC

Database Provider

EF Core (Default)

Tiered or separate authentication server

None (Default)

Operation System

Windows (Default)

Other information

No response

MisterCat100 avatar May 30 '25 15:05 MisterCat100

hi

Please share some code to reproduce, Thanks.

maliming avatar Jun 01 '25 06:06 maliming

public static List

? GetFavouriteArticles( this IdentityUser user) { return user.GetProperty( ArthiveConsts.FavouriteArticlesPropertyName).As<List?>(); }

when controller calls this method [HttpGet] [Route("{id:guid}/get-favourite-articles")] public Task<List<ArticleDto>?> GetFavouriteArticlesAsync( Guid id) { return _userProfileAppService.GetFavouriteArticlesAsync(id); }

to reproduce Cast nonGeneric GetProperty in the extensionMethod to the needed object

MisterCat100 avatar Jun 01 '25 13:06 MisterCat100

hi

What does your SetProperty code look like?

maliming avatar Jun 02 '25 11:06 maliming

What type did you set for the property?

List? is an open generic type, which is not valid on its own. That’s likely why you're seeing the error. You need to specify the generic argument for List<T>, like this:

return user.GetProperty(ArthiveConsts.FavouriteArticlesPropertyName) .As<List<Article>?>();

Make sure that the type matches whatever you originally stored in the property.

mosindi avatar Jun 02 '25 16:06 mosindi

I'm trying to reproduce this problem. Can you share a simple project?

Thanks.

maliming avatar Jun 03 '25 00:06 maliming

Hello! I changed logic a little, now i using List of Guid, but have the same problem

public static List<Guid>? GetFavouriteArticles(
    this IdentityUser user)
{
    return user.GetProperty(
        ArthiveConsts.FavouriteArticlesPropertyName).As<List<Guid>?>();
}

public static void SetFavouriteArticles(
    this IdentityUser user,
    List<Guid> favouriteArticles)
{
    user.SetProperty(
        ArthiveConsts.FavouriteArticlesPropertyName, favouriteArticles);
}

and the error

Unable to cast object of type 'System.Text.Json.JsonElement' to type 'System.Collections.Generic.List1[System.Guid]'. System.InvalidCastException: Unable to cast object of type 'System.Text.Json.JsonElement' to type 'System.Collections.Generic.List1[System.Guid]'. at Arthive.Profiles.IdentityUserExtension.GetFavouriteArticles(IdentityUser user) in C:\Users\MisterCat100\source\repos\arthive.server\aspnet-core\src\Arthive.Domain\Profiles\IdentityUserExtension.cs:line 44 at Arthive.Profiles.UserProfileAppService.GetFavouriteArticlesAsync(Guid id) in C:\Users\MisterCat100\source\repos\arthive.server\aspnet-core\src\Arthive.Application\Profiles\UserProfileAppService.cs:line 80

MisterCat100 avatar Jun 06 '25 10:06 MisterCat100

What type did you set for the property?

List? is an open generic type, which is not valid on its own. That’s likely why you're seeing the error. You need to specify the generic argument for List, like this:

return user.GetProperty(ArthiveConsts.FavouriteArticlesPropertyName) .As<List<Article>?>();

Make sure that the type matches whatever you originally stored in the property.

Github eaten part of the code, i used .As<List<Article>?>();

MisterCat100 avatar Jun 06 '25 10:06 MisterCat100

i resolved the problem, by serializing JsonElement, but cat you please explain, why returns JsonElement, when writes, that will return object?

Here, how it wrote in the debugger variables Image

MisterCat100 avatar Jun 06 '25 13:06 MisterCat100

hi

Can you share a test project to reproduce it?

Thanks.

maliming avatar Jun 09 '25 01:06 maliming

hi

Can you share a test project to reproduce it?

Thanks.

you dont need test project, so why returns JsonElement, when writes, that will return object?

Image

MisterCat100 avatar Jul 27 '25 18:07 MisterCat100

The ExtraPropertyDictionary lacks Type information. It doesn't know what Type to deserialize.

You can add a custom JsonConverter.

Image
class BarDtoJsonConverter : JsonConverter<BarDto>
{
    private JsonSerializerOptions _readJsonSerializerOptions;

    private JsonSerializerOptions _writeJsonSerializerOptions;


    public override BarDto Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        _readJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, x =>
            x == this ||
            x.GetType() == typeof(BarDtoJsonConverter));
        var barDto = JsonSerializer.Deserialize<BarDto>(ref reader, _readJsonSerializerOptions);

        var extraProperties = barDto.ExtraProperties;
        if (extraProperties.TryGetValue("bar", out var barValue) && barValue is JsonElement jsonElement)
        {
            if (jsonElement.ValueKind == JsonValueKind.Array)
            {
                var barList = new List<string>();
                foreach (var item in jsonElement.EnumerateArray())
                {
                    if (item.ValueKind == JsonValueKind.String)
                    {
                        barList.Add(item.GetString());
                    }
                }
                barDto.SetProperty("bar", barList);
            }
        }

        return barDto;
    }

    public override void Write(Utf8JsonWriter writer, BarDto value, JsonSerializerOptions options)
    {
        _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, x =>
            x == this ||
            x.GetType() == typeof(BarDtoJsonConverter));
        JsonSerializer.Serialize(writer, value, _writeJsonSerializerOptions);
    }
}

maliming avatar Jul 28 '25 03:07 maliming

Thank you very much for explanation! So, if it lacks of type, why writes, that it is JsonElement?

MisterCat100 avatar Aug 04 '25 11:08 MisterCat100

We used the Microsoft recommended way.

Image

https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/converters-how-to#deserialize-inferred-types-to-object-properties

maliming avatar Aug 05 '25 06:08 maliming