Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update OC 1.8.0-preview-17858 to 1.9.x latest #15416

Closed
hyzx86 opened this issue Feb 28, 2024 · 47 comments · Fixed by #15422, #15460 or #15480
Closed

Update OC 1.8.0-preview-17858 to 1.9.x latest #15416

hyzx86 opened this issue Feb 28, 2024 · 47 comments · Fixed by #15422, #15460 or #15480
Labels
Milestone

Comments

@hyzx86
Copy link
Contributor

hyzx86 commented Feb 28, 2024

My data works fine under version 1.8.0-preview-17858 , but after upgrading to the latest version 1.9x, I have the following problem when I log in. The admin account looks fine, but this exception is also thrown when I open the user list

InvalidOperationException: Each parameter in the deserialization constructor on type 'Microsoft.AspNetCore.Identity.UserLoginInfo' must bind to an object property or field on deserialization. 
Each parameter name must match with a property or field on the object. Fields are only considered when 
'JsonSerializerOptions.IncludeFields' is enabled. The match can be case-insensitive.

User Document

{
    "Id": 2241,
    "UserId": "4fkpnj0fnawmzy3zdc5kx5pnn1",
    "UserName": "xxxx",
    "NormalizedUserName": "xxxxx",
    "Email": "[email protected]",
    "NormalizedEmail": "[email protected]",
    "PasswordHash": "xxxx",
    "SecurityStamp": "xxxx",
    "EmailConfirmed": false,
    "PhoneNumberConfirmed": false,
    "IsEnabled": true,
    "TwoFactorEnabled": false,
    "IsLockoutEnabled": true,
    "AccessFailedCount": 0,
    "RoleNames": [
        "Administrator"
    ],
    "UserClaims": [],
    "LoginInfos": [
        {
            "LoginProvider": "OpenIdConnect",
            "ProviderKey": "xxxx",
            "ProviderDisplayName": "default"
        }
    ],
    "UserTokens": [],
    "Properties": {
    }
}

Details:

System.InvalidOperationException: Each parameter in the deserialization constructor on type 'Microsoft.AspNetCore.Identity.UserLoginInfo' must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. Fields are only considered when 'JsonSerializerOptions.IncludeFields' is enabled. The match can be case-insensitive.
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_ConstructorParameterIncompleteBinding(Type parentType)
   at System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsObject(Utf8JsonReader& reader, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadFromSpanAsObject(ReadOnlySpan`1 utf8Json, JsonTypeInfo jsonTypeInfo, Nullable`1 actualByteCount)
   at System.Text.Json.JsonSerializer.ReadFromSpanAsObject(ReadOnlySpan`1 json, JsonTypeInfo jsonTypeInfo)
   at System.Text.Json.JsonSerializer.Deserialize(String json, Type returnType, JsonSerializerOptions options)
   at YesSql.Serialization.DefaultJsonContentSerializer.Deserialize(String content, Type type)
   at YesSql.Session.Get[T](IList`1 documents, String collection)
   at YesSql.Services.DefaultQuery.Query`1.FirstOrDefaultImpl()
   at YesSql.Services.DefaultQuery.Query`1.FirstOrDefaultImpl()
   at OrchardCore.Users.Services.UserStore.FindByNameAsync(String normalizedUserName, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Identity.UserManager`1.FindByNameAsync(String userName)
   at OrchardCore.Users.Services.UserService.GetUserAsync(String userName)
   at OrchardCore.Users.Controllers.AccountController.Login(LoginViewModel model, String returnUrl)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ExceptionContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at OrchardCore.Apis.GraphQL.GraphQLMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.InterfaceMiddlewareBinder.<>c__DisplayClass2_0.<<CreateMiddleware>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext httpContext, Boolean retry)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at OrchardCore.Liquid.ScriptsMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.<Invoke>g__AwaitMatch|10_1(EndpointRoutingMiddleware middleware, HttpContext httpContext, Task matchTask)
   at OrchardCore.Diagnostics.DiagnosticsStartupFilter.<>c__DisplayClass3_0.<<Configure>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at OrchardCore.ContentPreview.PreviewStartupFilter.<>c.<<Configure>b__0_1>d.MoveNext()
--- End of stack trace from previous location ---
   at OrchardCore.Modules.ModularTenantRouterMiddleware.Invoke(HttpContext httpContext)
   at OrchardCore.Modules.ModularTenantContainerMiddleware.<>c__DisplayClass4_0.<<Invoke>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func`2 execute, Boolean activateShell)
   at OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func`2 execute, Boolean activateShell)
   at OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func`2 execute, Boolean activateShell)
   at OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func`2 execute, Boolean activateShell)
   at OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func`2 execute, Boolean activateShell)
   at OrchardCore.Modules.ModularTenantContainerMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
@Skrypt
Copy link
Contributor

Skrypt commented Feb 28, 2024

@MikeAlhayek Yeah, see that's what I meant when I said it will probably not all work magically. 🤡

@hyzx86
Copy link
Contributor Author

hyzx86 commented Feb 28, 2024

Strangely, they don't look much different
But the account admin can login, and this happens when another account logsin,
image

Another problem was that there was no menu after the admin account logged in, even if I clicked the Dashboard button in the user menu
image

@hyzx86
Copy link
Contributor Author

hyzx86 commented Feb 28, 2024

Maybe relate of #14572

@hyzx86
Copy link
Contributor Author

hyzx86 commented Feb 28, 2024

Reason is the type of the Microsoft.AspNetCore.Identity.UserLoginInfo has no default constructor
But the User type depend on it

public IList<UserClaim> UserClaims { get; set; } = [];
public IList<UserLoginInfo> LoginInfos { get; set; } = [];
public IList<UserToken> UserTokens { get; set; } = [];

public class UserLoginInfo
{
    /// <summary>
    /// Creates a new instance of <see cref="UserLoginInfo"/>
    /// </summary>
    /// <param name="loginProvider">The provider associated with this login information.</param>
    /// <param name="providerKey">The unique identifier for this user provided by the login provider.</param>
    /// <param name="displayName">The display name for the login provider.</param>
    public UserLoginInfo(string loginProvider, string providerKey, string? displayName)
    {
        LoginProvider = loginProvider;
        ProviderKey = providerKey;
        ProviderDisplayName = displayName;
    }

@hyzx86
Copy link
Contributor Author

hyzx86 commented Feb 28, 2024

Looks like the YesSqlOptions is not support to configure the ContentSerializer , shall we direct use the code below?

           if (!JOptions.Base.Converters.Any(x => x.Type == typeof(LoginInfoConverter)))
           {
               JOptions.Base.Converters.Add(new LoginInfoConverter());
           }
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Identity;

namespace OrchardCore.Users.Json;
public class LoginInfoConverter : JsonConverter<UserLoginInfo>
{
    public override UserLoginInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var loginInfo = new UserLoginInfo(string.Empty, string.Empty, string.Empty);
        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                string propertyName = reader.GetString();
                reader.Read();

                switch (propertyName)
                {
                    case nameof(UserLoginInfo.LoginProvider):
                        loginInfo.LoginProvider = reader.GetString();
                        break;
                    case nameof(UserLoginInfo.ProviderKey):
                        loginInfo.ProviderKey = reader.GetString();
                        break;
                    case nameof(UserLoginInfo.ProviderDisplayName):
                        loginInfo.ProviderDisplayName = reader.GetString();
                        break;
                    default:
                        break;
                }
            }
            else if (reader.TokenType == JsonTokenType.EndObject)
            {
                break;
            }
        }

        return loginInfo;
    }

    public override void Write(Utf8JsonWriter writer,
                            UserLoginInfo objectToWrite,
                            JsonSerializerOptions options) =>
                            JsonSerializer.Serialize(writer, objectToWrite, objectToWrite.GetType(), options);
}

@MikeAlhayek
Copy link
Member

@hyzx86 you'll need a custom converter like you did. Then register it in OC here

Default.Converters.Add(new PathStringJsonConverter());

Also here

options.Converters.Add(PathStringJsonConverter.Instance);

@MikeAlhayek MikeAlhayek added this to the 1.9 milestone Feb 28, 2024
@hyzx86
Copy link
Contributor Author

hyzx86 commented Feb 29, 2024

OrchardCore.Deployment.DeploymentStep

Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized 
constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'OrchardCore.Deployment.DeploymentStep'.
 Path: $.DeploymentSteps[0] | LineNumber: 0 | BytePositionInLine: 173.”
    public class DeploymentPlan
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public List<DeploymentStep> DeploymentSteps { get; init; } = [];
    }
    public abstract class DeploymentStep
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }

image

@hyzx86
Copy link
Contributor Author

hyzx86 commented Feb 29, 2024

OrchardCore.Queries.Query

System.NotSupportedException:“Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'OrchardCore.Queries.Query'. Path: $.Queries.OrderValidation | LineNumber: 0 | BytePositionInLine: 1907.”

@hyzx86
Copy link
Contributor Author

hyzx86 commented Feb 29, 2024

At this point, I was curious, because it's supposed to be impossible to serialize an abstract class or a type without a default constructor.

How does Newtownsoft.Json do this?

@hyzx86

This comment was marked as outdated.

@MikeAlhayek
Copy link
Member

@hyzx86 is OrderValidation something custom you are using that is inherited from Query? If so, you'll need to register it like this

services.AddJsonDerivedTypeInfo<OrderValidation, Query>();

From the migration docs https://docs.orchardcore.net/en/latest/docs/releases/1.9.0/

Any serializable object that contains a polymorphic property (a base type that can contain sub-classes instances) needs to register all possible sub-classes this way:
services.AddJsonDerivedTypeInfo<UrlCondition, Condition>();
In particular, any type introduced in custom modules inheriting from MenuItem, AdminNode, Condition, ConditionOperator, Query, SitemapType will have to use this method.

@sebastienros
Copy link
Member

After looking int UserLoginInfo it happens that it was not due to missing a default constructor, since it has a single one it's fine too. The issue is in the ctor argument not matching the property name. I created this PR to fix it in next aspnet version. dotnet/aspnetcore#54298
When it's merged we can file an issue to track the fact we can remove the custom converter.

@MikeAlhayek
Copy link
Member

So the STJ serialize uses a naming convention to match up properties to constructors? Interesting.

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 4, 2024

Hi @MikeAlhayek , Did we miss the asp.net core api serialization configuration?

the below code will use diffrent serialize option , just like the top line will ignore null property , the last line will include null value.

        public async Task<IActionResult> Query(string name)
        { 
// the below code will use diffrent serialize option  , the top line will ignore null property , the last line will include null value
           return Content(JConvert.SerializeObject(result));
            return new ObjectResult(result);
        }

Please reopen this issue, my test is not finished yet 😁

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 4, 2024

the below code will use diffrent serialize option , just like the top line will ignore null property , the last line will include null value.

I mean, under oc1.8x, the default serialization option ignores empty properties

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 4, 2024

Chinese content will be encoded instead of the original text

1.8x:
"{\"data\":{\"fileName\":\"test-测试.xlsx\",\"testName\":\"gbk\"}

1.9x (JOptions.Default):
"{\"data\":{\"fileName\":\"/test-\\u6D4B\\u8BD5.xlsx\",\"testName\":\"gbk\"}"

need to use JOptions.UnsafeRelaxedJsonEscaping to fix

@sebastienros
Copy link
Member

Before someone changes UnsafeRelaxedJsonEscaping to true by default we should try to understand how unsafe it is, and probably just leave it as a setting if people are bothered by it. The disadvantages of encoding are just that the json might get a little bigger and harder to read. But there is no functional drawback with letting it this way.

@MikeAlhayek
Copy link
Member

Chinese content will be encoded instead of the original text

@hyzx86 at what point are you getting this error?

The DefaultJsonContentSerializer uses JsonSerializerOptions to serialize and de-serialize documents. This should not need UnsafeRelaxedJsonEscaping. If you are serializing and de-serializing custom object, that are not stored in a YesSql document, you'll need to deal with that using your custom configuration.

Did we miss the asp.net core api serialization configuration?

I am not sure what you mean here. API serialization can have different options that the document serialization. Remember that document serialization is only used by YesSql to serialize objects that are stored in the document table. Once the object is save and returned from YesSql, you are free to do anything you want with it like serialize it and print it out in any format you want.

@MikeAlhayek MikeAlhayek reopened this Mar 4, 2024
@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 5, 2024

Chinese content will be encoded instead of the original text

@hyzx86 at what point are you getting this error?

The Query action

        public async Task<IActionResult> Query(string name)
        { 
// the below code will use diffrent serialize option  , the top line will ignore null property , the last line will include null value
           return Content(JConvert.SerializeObject(result));
            return new ObjectResult(result);
        }

@sebastienros
Copy link
Member

Did we miss the asp.net core api serialization configuration

@MikeAlhayek Maybe the question here is that ASP.NET will use STJ to serialize object results from controller/actions, and there must be a way to set the serialization options to use which might be missing right now. c.f. https://www.meziantou.net/configuring-json-options-in-asp-net-core.htm

@MikeAlhayek
Copy link
Member

reading that comment again and seeing the two return statements in the action, tells me you are right.

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 6, 2024 via email

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 6, 2024

Did we miss the asp.net core api serialization configuration

@MikeAlhayek Maybe the question here is that ASP.NET will use STJ to serialize object results from controller/actions, and there must be a way to set the serialization options to use which might be missing right now. c.f. https://www.meziantou.net/configuring-json-options-in-asp-net-core.htm

@sebastienros Yes, that's what I meant . 👍

@MikeAlhayek , I have some unit tests to verify that the client receives the correct results after every upgrade or code change in the OC.
image

Now my client application will break if we don't adjust the code

@MikeAlhayek
Copy link
Member

@hyzx86 try your code with PR #15460.

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 6, 2024

The single quote should be recognized as a valid property name qualifier

At least it can be recognized in STJ before

var parameters = "{'size':1}`";
var para = JConvert.DeserializeObject<Dictionary<string, object>>(parameters)

-- Looks like it won't be supported

https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft?pivots=dotnet-9-0#json-strings-property-names-and-string-values

@sebastienros
Copy link
Member

Where do you have property name with single quotes?

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 8, 2024

Where do you have property name with single quotes?

parameters of query and graphql parameters

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 9, 2024

In the current version, the data type is not checked when creating content through the Api, so the wrong type can be successfully saved to the database.
But STJ does enforce the type requirement

{
  "SalesOrg":{
      "Text":1234
  }
}
2024-03-09 21:10:56.3384|SalesProtalDev|0HN2078JNC0GH||OrchardCore.ContentManagement.DefaultContentManager|ERROR|IContentHandler thrown from OrchardCore.ContentManagement.Handlers.ContentPartHandlerCoordinator by JsonException System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.Text | LineNumber: 0 | BytePositionInLine: 14.
 ---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_ExpectedString(JsonTokenType tokenType)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   --- End of inner exception stack trace ---
   at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, Utf8JsonReader& reader, Exception ex)
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadFromNodeAsObject(JsonNode node, JsonTypeInfo jsonTypeInfo)
   at System.Text.Json.JsonSerializer.Deserialize(JsonNode node, Type returnType, JsonSerializerOptions options)
   at OrchardCore.ContentManagement.ContentExtensions.Get(ContentElement contentElement, Type contentElementType, String name) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.ContentManagement.Abstractions\ContentExtensions.cs:line 77
   at OrchardCore.ContentManagement.Handlers.ContentPartHandlerCoordinator.InvokeHandlers[TContext,TFieldContext](TContext context, TFieldContext fieldContext, Func`4 partHandlerAction, Func`4 fieldHandlerAction, Boolean createPartIfNotExists, Boolean createFieldIfNotExists) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.ContentManagement\Handlers\ContentPartHandlerCoordinator.cs:line 368
   at OrchardCore.Modules.InvokeExtensions.InvokeAsync[TEvents,T1](IEnumerable`1 events, Func`3 dispatch, T1 arg1, ILogger logger) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.Abstractions\Modules\Extensions\InvokeExtensions.cs:line 133    at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, Utf8JsonReader& reader, Exception ex)
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadFromNodeAsObject(JsonNode node, JsonTypeInfo jsonTypeInfo)
   at System.Text.Json.JsonSerializer.Deserialize(JsonNode node, Type returnType, JsonSerializerOptions options)
   at OrchardCore.ContentManagement.ContentExtensions.Get(ContentElement contentElement, Type contentElementType, String name) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.ContentManagement.Abstractions\ContentExtensions.cs:line 77
   at OrchardCore.ContentManagement.Handlers.ContentPartHandlerCoordinator.InvokeHandlers[TContext,TFieldContext](TContext context, TFieldContext fieldContext, Func`4 partHandlerAction, Func`4 fieldHandlerAction, Boolean createPartIfNotExists, Boolean createFieldIfNotExists) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.ContentManagement\Handlers\ContentPartHandlerCoordinator.cs:line 368
   at OrchardCore.Modules.InvokeExtensions.InvokeAsync[TEvents,T1](IEnumerable`1 events, Func`3 dispatch, T1 arg1, ILogger logger) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.Abstractions\Modules\Extensions\InvokeExtensions.cs:line 133

This problem causes the content page to enter an infinite loop

/Admin/Contents/ContentItems?admin=-51136895

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 9, 2024

Hi @MikeAlhayek , What has changed recently, and this problem occurs when I log in after pulling the latest code

System.InvalidOperationException: Each parameter in the deserialization constructor on type 'Microsoft.AspNetCore.Identity.UserLoginInfo' must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. Fields are only considered when 'JsonSerializerOptions.IncludeFields' is enabled. The match can be case-insensitive.

System.InvalidOperationException: Each parameter in the deserialization constructor on type 'Microsoft.AspNetCore.Identity.UserLoginInfo' must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. Fields are only considered when 'JsonSerializerOptions.IncludeFields' is enabled. The match can be case-insensitive.
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_ConstructorParameterIncompleteBinding(Type parentType)
   at System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsObject(Utf8JsonReader& reader, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadFromSpanAsObject(ReadOnlySpan`1 utf8Json, JsonTypeInfo jsonTypeInfo, Nullable`1 actualByteCount)
   at System.Text.Json.JsonSerializer.ReadFromSpanAsObject(ReadOnlySpan`1 json, JsonTypeInfo jsonTypeInfo)
   at System.Text.Json.JsonSerializer.Deserialize(String json, Type returnType, JsonSerializerOptions options)
   at YesSql.Serialization.DefaultJsonContentSerializer.Deserialize(String content, Type type) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.Data.YesSql\DefaultJsonContentSerializer.cs:line 21
   at YesSql.Session.Get[T](IList`1 documents, String collection)
   at YesSql.Services.DefaultQuery.Query`1.FirstOrDefaultImpl()
   at YesSql.Services.DefaultQuery.Query`1.FirstOrDefaultImpl()
   at OrchardCore.Users.Services.UserStore.FindByNameAsync(String normalizedUserName, CancellationToken cancellationToken) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.Users.Core\Services\UserStore.cs:line 167
   at Microsoft.AspNetCore.Identity.UserManager`1.FindByNameAsync(String userName)
   at OrchardCore.Users.Services.UserService.GetUserAsync(String userName) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.Users.Core\Services\UserService.cs:line 244
   at OrchardCore.Users.Controllers.AccountController.Login(LoginViewModel model, String returnUrl) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore.Modules\OrchardCore.Users\Controllers\AccountController.cs:line 170
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext httpContext, Boolean retry)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at OrchardCore.Apis.GraphQL.GraphQLMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore.Modules\OrchardCore.Apis.GraphQL\GraphQLMiddleware.cs:line 50
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.InterfaceMiddlewareBinder.<>c__DisplayClass2_0.<<CreateMiddleware>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at OrchardCore.Liquid.ScriptsMiddleware.Invoke(HttpContext httpContext) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore.Modules\OrchardCore.Liquid\ScriptsMiddleware.cs:line 70
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at OrchardCore.Diagnostics.DiagnosticsStartupFilter.<>c__DisplayClass3_0.<<Configure>b__1>d.MoveNext() in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore.Modules\OrchardCore.Diagnostics\DiagnosticsStartupFilter.cs:line 34
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at OrchardCore.ContentPreview.PreviewStartupFilter.<>c.<<Configure>b__0_1>d.MoveNext() in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore.Modules\OrchardCore.ContentPreview\PreviewStartupFilter.cs:line 16
--- End of stack trace from previous location ---
   at OrchardCore.Modules.ModularTenantRouterMiddleware.Invoke(HttpContext httpContext) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore\Modules\ModularTenantRouterMiddleware.cs:line 47
   at OrchardCore.Modules.ModularTenantContainerMiddleware.<>c__DisplayClass4_0.<<Invoke>b__0>d.MoveNext() in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore\Modules\ModularTenantContainerMiddleware.cs:line 61
--- End of stack trace from previous location ---
   at OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func`2 execute, Boolean activateShell) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.Abstractions\Shell\Scope\ShellScope.cs:line 253
   at OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func`2 execute, Boolean activateShell) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.Abstractions\Shell\Scope\ShellScope.cs:line 258
   at OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func`2 execute, Boolean activateShell) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.Abstractions\Shell\Scope\ShellScope.cs:line 263
   at OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func`2 execute, Boolean activateShell) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.Abstractions\Shell\Scope\ShellScope.cs:line 268
   at OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func`2 execute, Boolean activateShell) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore.Abstractions\Shell\Scope\ShellScope.cs:line 269
   at OrchardCore.Modules.ModularTenantContainerMiddleware.Invoke(HttpContext httpContext) in D:\SourceCodes\JZSoft\OrchardCore\src\OrchardCore\OrchardCore\Modules\ModularTenantContainerMiddleware.cs:line 59
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

@MikeAlhayek
Copy link
Member

If you are injecting IOptions in your prroject, you should change it to inject IOptions instead.

0465891

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 10, 2024

If you are injecting IOptions in your prroject, you should change it to inject IOptions instead.

0465891

Yes, I mean I have this problem in the latest version of the source code.
Prompt at login that this type cannot be serialized.
Microsoft.AspNetCore.Identity.UserLoginInfo

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 10, 2024

@MikeAlhayek I updated the log in the comments above

Because IStore objects have a singleton life cycle, which means that their configuration is not modified once initialized, serialization options configured in subsequent modules are not executed again

services.AddSingleton(sp =>
{
var shellSettings = sp.GetService<ShellSettings>();
// Before the setup, a 'DatabaseProvider' may be configured without a required 'ConnectionString'.
if (shellSettings.IsUninitialized() || shellSettings["DatabaseProvider"] is null)
{
return null;
}
var yesSqlOptions = sp.GetService<IOptions<YesSqlOptions>>().Value;
var databaseTableOptions = shellSettings.GetDatabaseTableOptions();
var storeConfiguration = GetStoreConfiguration(sp, yesSqlOptions, databaseTableOptions);
switch (shellSettings["DatabaseProvider"])

But I wonder why there are no problems in the unit tests.

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 10, 2024

The breakpoint will never be hit on line 212

if (yesSqlOptions.ContentSerializer != null)
{
storeConfiguration.ContentSerializer = yesSqlOptions.ContentSerializer;
}

@MikeAlhayek
Copy link
Member

MikeAlhayek commented Mar 10, 2024

The problem is that I forgot to update the registration of the user converter. I am out of town with no PC to fix this. If you like, submit a PR that updates the following

https://github.com/OrchardCMS/OrchardCore/blob/11dc9712403ace4489ea90aa26d7a4c1a78fe0d7/src/OrchardCore/OrchardCore.Users.Core/Extensions/UsersServiceCollectionExtensions.cs#L60-62

To this

services.Configure<ContentSerializerJsonOptions>(options =>
           {
               options.SerializerOptions.Converters.Add(new LoginInfoJsonConverter());
           });

Request my review on that PR and I'll merge it.

If you have any different issue please open a new issue so we can track it separately and avoid commenting on close issues.

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 11, 2024

The good news is that my program is working, and all of my custom unit tests are passing

However, there is still a problem. I am using react to develop a split client and I am having this problem with openid authorization, but everything works fine with oc1.8 release, I am wondering if this has changed recently?

image

Other apis were successfully called before the authorization logic was called
image

@MikeAlhayek
Copy link
Member

MikeAlhayek commented Mar 11, 2024

Try accessing the .well-knows url in your browser and see if that gives you an error or not. If there is an issue please open up a new issue.

Also I am wondering if the output of the .well-known format changed with the latest changes we made to the global parser. Can you please share the json output you see when you access the .well-known endpoint in your browser?

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 11, 2024

In the current version, the data type is not checked when creating content through the Api, so the wrong type can be successfully saved to the database. But STJ does enforce the type requirement

{
  "SalesOrg":{
      "Text":1234
  }
}

@MikeAlhayek No problem, I've already created an Issue

But let's take a look at this question. Should we update our JSON serialization to be compatible with the wrong data format?

Also, when I used the database statement to fix the data type, I still found some encoding problems, Chinese and special symbols were encoded

UPDATE Document  
SET Content = JSON_MODIFY(Content, '$.SEAQuotationLogics.SalesOrg.Text', REPLACE(CAST(JSON_VALUE(d.content, '$.SEAQuotationLogics.SalesOrg.Text') AS NVARCHAR(MAX)),'.0',''))  
FROM Dindex_SEAQuotationLogics l  
INNER JOIN Document d ON l.DocumentId = d.Id;

image

@MikeAlhayek
Copy link
Member

@sebastienros thoughts on the last comment?

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 11, 2024

It looks like there's no way to read a number as a string in STJ. Maybe we should adjust our code to accommodate this? How about adding a type check when reading TextField?


I checked the code and it feels like it's not easy or expensive, but if we can't do anything, we should document how to handle this change
Otherwise, the existing document will not be opened

@MikeAlhayek
Copy link
Member

Why? Not sure if I fully understand that issue you are having. TextField by definition is for text/string and should always render string even if the value is a numeric format. If you want to capture numeric, then you should use the NumericFiels.

@sebastienros
Copy link
Member

I don't see any issue anywhere:

This is valid json. It's encoded, but this is not a problem, it's normal.

image

And Text Fields should always be serialized as a string.

@hyzx86
Copy link
Contributor Author

hyzx86 commented Mar 11, 2024

Why? Not sure if I fully understand that issue you are having. TextField by definition is for text/string and should always render string even if the value is a numeric format. If you want to capture numeric, then you should use the NumericFiels.

As I mentioned before, they are created using webApi, skipping DisplayDriver , This is because we are not validating the data type of the field when creating the content through the Api.
But t as things stand... The data produced by the new version should not have this problem anymore; it will just throw an error

@MikeAlhayek
Copy link
Member

You can add field handler to do the same validation as the validation done by the driver. But this should not be a STJ related

@chinasqzl
Copy link

@hyzx86 请问一下,2.0.2版本中,中文被转义的问题,现在有办法解决了吗?

@hyzx86
Copy link
Contributor Author

hyzx86 commented Oct 5, 2024

@hyzx86 请问一下,2.0.2版本中,中文被转义的问题,现在有办法解决了吗?

如果是API结果的问题,你可以覆盖MVC 的序列化选项,对应位置修改对应的序列化选项就好了

@MikeAlhayek
Copy link
Member

@hyzx86 can you please look at PR #16837 it reverts the PR that fixed this issue. Can you please confirm that PR #16837 is not going to break what this PR fixed?

@hyzx86
Copy link
Contributor Author

hyzx86 commented Oct 8, 2024

@hyzx86 can you please look at PR #16837 it reverts the PR that fixed this issue. Can you please confirm that PR #16837 is not going to break what this PR fixed?你能看看 PR #16837 吗,它恢复了解决这个问题的 PR。您能否确认 PR #16837 不会破坏此 PR 修复的内容?

Thanks!
I've simply and crudely overwritten the faulty controller. This implementation looks much more complex than mine, and in any case my implementation won't be affected.

return Content(JConvert.SerializeObject(sresult, JOptions.UnsafeRelaxedJsonEscaping));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment