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

InvalidOperationException when accessing property from dynamically generated class-type in Blazor WASM .NET 8 #106469

Open
StefH opened this issue Aug 15, 2024 · 2 comments

Comments

@StefH
Copy link

StefH commented Aug 15, 2024

Description

When a type is dynamically created using System.Reflection.Emit code, accessing a field or property throws InvalidOperationException.

Reproduction Steps

Create a .NET 8 WASM Blazor project.

Include System.Linq.Dynamic.Core

Add this code to the default Counter.cs code which creates dynamically a type and a instance of that type:

var props = new DynamicProperty[] { new("Name", typeof(string)), new("Birthday", typeof(DateTime)) };
var type = DynamicClassFactory.CreateType(props);
var dynamicClass = (DynamicClass)Activator.CreateInstance(type, false)!;
dynamicClass.SetDynamicPropertyValue("Name", "Albert");
dynamicClass.SetDynamicPropertyValue("Birthday", new DateTime(1879, 3, 14));

Now when casting this to dynamic and accessing the "Name" property throws exception:

Console.WriteLine(((dynamic)dynamicClass).Name);

Not that accessing the properties using reflection works fine:

var nameReflection = dynamicClass.GetType().GetProperty("Name")!.GetValue(dynamicClass);
Console.WriteLine("Reflection = " + nameReflection);

See this issue + fully working example project to show this error:
zzzprojects/System.Linq.Dynamic.Core#836

Expected behavior

The "Name" property should be accessible.

Actual behavior

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Operation is not valid due to the current state of the object.
System.InvalidOperationException: Operation is not valid due to the current state of the object.
   at System.Reflection.Emit.RuntimeGenericTypeParameterBuilder.GetGenericParameterConstraints()
   at Microsoft.CSharp.RuntimeBinder.SymbolTable.AddAggregateToSymbolTable(NamespaceOrAggregateSymbol parent, Type type)
   at Microsoft.CSharp.RuntimeBinder.SymbolTable.LoadSymbolsFromType(Type type)
   at Microsoft.CSharp.RuntimeBinder.SymbolTable.GetCTypeFromType(Type type)
   at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.GetArgumentType(ICSharpBinder p, CSharpArgumentInfo argInfo, Expression param, DynamicMetaObject arg, Int32 index)
   at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.CreateArgumentArray(ICSharpBinder payload, Expression[] parameters, DynamicMetaObject[] args)
   at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindCore(ICSharpBinder payload, Expression[] parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding)
   at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.Bind(ICSharpBinder payload, Expression[] parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding)
   at Microsoft.CSharp.RuntimeBinder.BinderHelper.Bind(ICSharpBinder action, RuntimeBinder binder, DynamicMetaObject[] args, IEnumerable`1 arginfos, DynamicMetaObject onBindingError)
   at Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder.FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
   at System.Dynamic.GetMemberBinder.FallbackGetMember(DynamicMetaObject target)
   at System.Dynamic.DynamicMetaObject.BindGetMember(GetMemberBinder binder)
   at System.Dynamic.GetMemberBinder.Bind(DynamicMetaObject target, DynamicMetaObject[] args)
   at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel)
   at System.Runtime.CompilerServices.CallSiteBinder.BindCore[Func`3](CallSite`1 site, Object[] args)
   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[Object,Object](CallSite site, Object arg0)
   at WasmDynamicLinq.Pages.Home.OnInitialized() in C:\Dev\GitHub\System.Linq.Dynamic.Core\src-blazor\WasmDynamicLinq\Pages\Home.razor.cs:line 142
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
Dt @ blazor.webassembly.js:1
(anonymous) @ invoke-js.ts:176
Tl @ invoke-js.ts:276
$func349 @ 00b21cf6:0x1fafb
$func245 @ 00b21cf6:0x1bf9f
$func238 @ 00b21cf6:0xf16c
$func272 @ 00b21cf6:0x1d1bd
$func3185 @ 00b21cf6:0xe8756
$func2505 @ 00b21cf6:0xbe4ac
$func2511 @ 00b21cf6:0xbecd0
$func2535 @ 00b21cf6:0xc1327
$mono_wasm_invoke_method_bound @ 00b21cf6:0xa4fa
Module._mono_wasm_invoke_method_bound @ dotnet.native.8.0.7.37dkch2d2y.js:8
kr @ invoke-cs.ts:273
l.javaScriptExports.complete_task @ managed-exports.ts:142
(anonymous) @ marshal-to-cs.ts:335
Promise.then
mo @ marshal-to-cs.ts:329
(anonymous) @ marshal-to-cs.ts:83
(anonymous) @ invoke-js.ts:177
Tl @ invoke-js.ts:276
$func349 @ 00b21cf6:0x1fafb
$func245 @ 00b21cf6:0x1bf9f
$func238 @ 00b21cf6:0xf16c
$func272 @ 00b21cf6:0x1d1bd
$func3185 @ 00b21cf6:0xe8756
$func2505 @ 00b21cf6:0xbe4ac
$func2504 @ 00b21cf6:0xbe43c
$func1874 @ 00b21cf6:0x9a502
$func349 @ 00b21cf6:0x1fb7f
$func245 @ 00b21cf6:0x1bf9f
$func238 @ 00b21cf6:0xf16c
$func272 @ 00b21cf6:0x1d1bd
$func3185 @ 00b21cf6:0xe8756
$func2505 @ 00b21cf6:0xbe4ac
$func2511 @ 00b21cf6:0xbecd0
$func2535 @ 00b21cf6:0xc1327
$mono_wasm_invoke_method_bound @ 00b21cf6:0xa4fa
Module._mono_wasm_invoke_method_bound @ dotnet.native.8.0.7.37dkch2d2y.js:8
kr @ invoke-cs.ts:273
l.javaScriptExports.call_entry_point @ managed-exports.ts:60
Oc @ run.ts:44
callEntryPoint @ blazor.webassembly.js:1
mn @ blazor.webassembly.js:1
await in mn
fn @ blazor.webassembly.js:1
An @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1

Regression?

No response

Known Workarounds

No response

Configuration

.NET 8

Blazor WAM

<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">

Other information

No response

@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Aug 15, 2024
@StefH StefH changed the title InvalidOperationException when accessing field or properties from dynamically generated class-type in Blazor WASM .NET 8 InvalidOperationException when accessing property from dynamically generated class-type in Blazor WASM .NET 8 Aug 15, 2024
Copy link
Contributor

Tagging subscribers to this area: @cston
See info in area-owners.md if you want to be subscribed.

@StefH
Copy link
Author

StefH commented Aug 17, 2024

@cston
I was able to trim down the issue to the part when I make the type a generic type:

This code works:

// Define a dynamic assembly and module
AssemblyName assemblyName = new AssemblyName("DynamicAssembly");
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");

// Define a public class named "DynamicType"
TypeBuilder typeBuilder = moduleBuilder.DefineType("DynamicType", TypeAttributes.Public);

// Define a public field of type string named "MyField"
typeBuilder.DefineField("MyField", typeof(string), FieldAttributes.Public);

// Create the type
Type dynamicType = typeBuilder.CreateType();

// Create an instance of the dynamic type
dynamic dynamicObject = Activator.CreateInstance(dynamicType)!;

// Set the value of the field using reflection
FieldInfo fieldInfo = dynamicType.GetField("MyField", BindingFlags.Public | BindingFlags.Instance)!;
fieldInfo.SetValue(dynamicObject, "Hello, World!");

// Output the value
Console.WriteLine("Test Field Value: " + (string)fieldInfo.GetValue(dynamicObject));
Console.WriteLine("Test Field Value Dynamic: " + dynamicObject.MyField);

This code does not work

// Define a dynamic assembly and module
AssemblyName assemblyName = new AssemblyName("DynamicAssembly");
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");

// Define a public class named "DynamicType"
TypeBuilder typeBuilder = moduleBuilder.DefineType("DynamicType", TypeAttributes.Public);

// Define a public field of type string named "MyField"
typeBuilder.DefineField("MyField", typeof(string), FieldAttributes.Public);

// ▶️ Define Generic Parameter
typeBuilder.DefineGenericParameters("T0");

// Create the type
Type dynamicType = typeBuilder.CreateType();

// ▶️ Make it generic
dynamicType = dynamicType.MakeGenericType(typeof(string));

// Create an instance of the dynamic type
dynamic dynamicObject = Activator.CreateInstance(dynamicType)!;

// Set the value of the field using reflection
FieldInfo fieldInfo = dynamicType.GetField("MyField", BindingFlags.Public | BindingFlags.Instance)!;
fieldInfo.SetValue(dynamicObject, "Hello, World!"); // ▶️ this throws exception

// Output the value
Console.WriteLine("Test Field Value: " + (string)fieldInfo.GetValue(dynamicObject));
Console.WriteLine("Test Field Value Dynamic: " + dynamicObject.MyField);

Can you explain this?

@cston cston added this to the 10.0.0 milestone Aug 21, 2024
@cston cston removed the untriaged New issue has not been triaged by the area owner label Aug 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants