Hi All,
I have created and admin menu with this item:
{
"$type": "OrchardCore.AdminMenu.AdminNodes.LinkAdminNode, OrchardCore.AdminMenu",
"LinkText": "Libreria Multimediale",
"LinkUrl": "Admin/Media",
"IconClass": "far fa-images",
"UniqueId": "[js:uuid()]",
"Enabled": true,
"Text": null,
"Id": "media-first-level",
"Href": null,
"Url": null,
"Position": null,
"LinkToFirstChild": true,
"LocalNav": false,
"Culture": null,
"Resource": null,
"Items": [],
"RouteValues": null,
"Permissions": [{ "name": "ManageMediaContent" }],
"Classes": ["media-first-level"]
}
but when I run my recipe I receive this error:
2020-10-15 19:09:54.6967|Default||1b4aa20d-49cd3a81eecc7d6b.||Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware|ERROR|An unhandled exception has occurred while executing the request. Newtonsoft.Json.JsonSerializationException: Unable to find a constructor to use for type OrchardCore.Security.Permissions.Permission. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path '[0].MenuItems[9].Permissions[0].name'.
Can repro. This is not a regression as it was not working.
We should allow to select CommonPermissions from the UI too if we want to implement this correctly.
Here is full stack trace :
An unhandled exception occurred while processing the request.
JsonSerializationException: Unable to find a constructor to use for type OrchardCore.Security.Permissions.Permission. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path '[0].MenuItems[0].Permissions[0].name'.
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, string id, out bool createdFromNonDefaultCreator)
Stack Query Cookies Headers Routing
JsonSerializationException: Unable to find a constructor to use for type OrchardCore.Security.Permissions.Permission. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path '[0].MenuItems[0].Permissions[0].name'.
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, string id, out bool createdFromNonDefaultCreator)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue, string id)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, string id)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue, string id)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, string id)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, bool checkAdditionalContent)
Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
Newtonsoft.Json.Linq.JToken.ToObject<T>(JsonSerializer jsonSerializer)
OrchardCore.AdminMenu.Recipes.AdminMenuStep.ExecuteAsync(RecipeExecutionContext context) in AdminMenuStep.cs
+
var adminMenu = token.ToObject<Models.AdminMenu>(serializer);
OrchardCore.Recipes.Services.RecipeExecutor+<>c__DisplayClass7_0+<<ExecuteStepAsync>b__0>d.MoveNext() in RecipeExecutor.cs
+
await recipeStepHandler.ExecuteAsync(recipeStep);
OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func<ShellScope, Task> execute) in ShellScope.cs
+
await execute(this);
OrchardCore.Recipes.Services.RecipeExecutor.ExecuteStepAsync(RecipeExecutionContext recipeStep) in RecipeExecutor.cs
+
await shellScope.UsingAsync(async scope =>
OrchardCore.Recipes.Services.RecipeExecutor.ExecuteAsync(string executionId, RecipeDescriptor recipeDescriptor, object environment, CancellationToken cancellationToken) in RecipeExecutor.cs
+
await ExecuteStepAsync(recipeStep);
OrchardCore.Recipes.Services.RecipeExecutor.ExecuteAsync(string executionId, RecipeDescriptor recipeDescriptor, object environment, CancellationToken cancellationToken) in RecipeExecutor.cs
+
capturedException.Throw();
OrchardCore.Recipes.Services.RecipeExecutor.ExecuteAsync(string executionId, RecipeDescriptor recipeDescriptor, object environment, CancellationToken cancellationToken) in RecipeExecutor.cs
+
throw;
OrchardCore.Recipes.Services.RecipeDeploymentTargetHandler.ImportFromFileAsync(IFileProvider fileProvider) in RecipeDeploymentTargetHandler.cs
+
await _recipeExecutor.ExecuteAsync(executionId, recipeDescriptor, new object(), CancellationToken.None);
OrchardCore.Deployment.Core.Services.DeploymentManager.ImportDeploymentPackageAsync(IFileProvider deploymentPackage) in DeploymentManager.cs
+
await deploymentTargetHandler.ImportFromFileAsync(deploymentPackage);
OrchardCore.Deployment.Controllers.ImportController.Import(IFormFile importedPackage) in ImportController.cs
+
await _deploymentManager.ImportDeploymentPackageAsync(new PhysicalFileProvider(tempArchiveFolder));
Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor+TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)
System.Threading.Tasks.ValueTask<TResult>.get_Result()
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask<IActionResult> actionResultValueTask)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
OrchardCore.Diagnostics.DiagnosticsStartupFilter+<>c__DisplayClass3_0+<<Configure>b__1>d.MoveNext() in DiagnosticsStartupFilter.cs
+
await next();
Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
OrchardCore.ContentPreview.PreviewStartupFilter+<>c+<<Configure>b__1_1>d.MoveNext() in PreviewStartupFilter.cs
+
await next();
OrchardCore.Modules.ModularTenantRouterMiddleware.Invoke(HttpContext httpContext) in ModularTenantRouterMiddleware.cs
+
await shellContext.Pipeline.Invoke(httpContext);
OrchardCore.Environment.Shell.Scope.ShellScope.UsingAsync(Func<ShellScope, Task> execute) in ShellScope.cs
+
await execute(this);
OrchardCore.Modules.ModularTenantContainerMiddleware.Invoke(HttpContext httpContext) in ModularTenantContainerMiddleware.cs
+
await shellScope.UsingAsync(scope => _next.Invoke(httpContext));
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Show raw exception details
Hi @Skrypt,
about the issue I think the solution could be mark a constructor in the Permission class with the JsonConstructor attribute of Newtonsoft.Json.
About the admin UI, if you want, I could try improve the Admin Menu link creation/edit interface for add an item that list all the permissions: a user could select one or more of this permissions and use a checkbox to select if this selected permissions have to be evalueted in AND or OR mode.
I hope to be useful in future.
Thank you.
PS. this week I'm a little busy but I could try to find some time here an there...more probably I can do this the next week.
Feel free to contribute.
These kind of admin menus are created by code. The ones that can be created dynamically don't support permissions as of today, so this feature would need to be implemented first.
I would have suggested to use roles, but @deanmarcussen reminded me that you might want to hide a link if you don't have a specific permissions, like a link to Media if you don't have the ManageMedia permission.
I would have suggested to use roles, but @deanmarcussen reminded me that you might want to hide a link if you don't have a specific permissions, like a link to Media if you don't have the ManageMedia permission.
Yes, my needs start from this necessity. My boss ask me to hide default Media library link and create a new ones in the first level of the admin menu. I want try to maintain the permission applied to the original Media library link and when I try to do this from recipe I have received the error above.
the Permission Name field is unique or not? Could be used as an identifier?
Thank you
Ok I will take a look at this today as it seems logical to have this working from recipes and admin UI.
@Skrypt I have created a branch to do this from admin UI and recipe...but I'm not sure to do the right things...
Link?
WIP don't be too rough with me 馃槄 https://github.com/PiemP/OrchardCore/tree/adminmenu_link_permission
Can you create a Pull Request?
OK, give me some other time to fix the code
Nevermind I will do it.
You can now fix it on top of https://github.com/OrchardCMS/OrchardCore/tree/skrypt/admin-menu-permissions
Looks good to me. Maybe some renaming.
mmm I have made some mistake...how can I commit some changes to the pull request? I believe that I can't write on this pull request.
You can checkout this branch on your fork then create a PR targetting this branch instead of the dev branch. I will close this PR afterward.
I hope to have do all well with this PR over a PR 馃槄
Well it's a branch so I can close my PR and work on yours so that your get attributed your contributions.
can I push other code modifications to the PR in the same way used yesterday? Thank you