aspnetcore: Using an out parameter in a controller leads to Could not load type 'System.Char&' from assembly 'System.Private.CoreLib, Version=7.0.0.0 ...'

I am upgrading a web project to .NET 7 Preview 7 and Visual Studio 2022 Preview 17.4. On startup, I receive the following exception:

TypeLoadException: Could not load type ‘System.Char&’ from assembly ‘System.Private.CoreLib, Version=7.0.0.0 …’

It seems like I’ve set up .NET 7 incorrectly, but how?

dotnet --list-sdks shows the following row:

7.0.100-preview.7.22377.5 [C:\Program Files\dotnet\sdk]

The “Framework” for my project shows the proper version:

image

The full exception is shown here:

System.TypeLoadException: Could not load type 'System.Char&' from assembly 'System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e'.
   at System.RuntimeTypeHandle.MakeByRef()
   at System.RuntimeType.MakeByRefType()
   at Microsoft.AspNetCore.Http.ParameterBindingMethodCache.<FindTryParseMethod>g__Finder|15_0(Type type)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.AspNetCore.Mvc.ModelBinding.ModelMetadata.InitializeTypeInformation()
   at Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.DefaultModelMetadata..ctor(IModelMetadataProvider provider, ICompositeMetadataDetailsProvider detailsProvider, DefaultMetadataDetails details, DefaultModelBindingMessageProvider modelBindingMessageProvider)
   at Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.DefaultModelMetadataProvider.CreateModelMetadata(DefaultMetadataDetails entry)
   at Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.DefaultModelMetadataProvider.CreateCacheEntry(ModelMetadataIdentity key)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.DefaultModelMetadataProvider.GetMetadataForParameter(ParameterInfo parameter, Type modelType)
   at Microsoft.AspNetCore.Mvc.ApplicationModels.DefaultApplicationModelProvider.CreateParameterModel(ParameterInfo parameterInfo)
   at Microsoft.AspNetCore.Mvc.ApplicationModels.DefaultApplicationModelProvider.OnProvidersExecuting(ApplicationModelProviderContext context)
   at Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModelFactory.CreateApplicationModel(IEnumerable`1 controllerTypes)
   at Microsoft.AspNetCore.Mvc.ApplicationModels.ControllerActionDescriptorProvider.GetDescriptors()
   at Microsoft.AspNetCore.Mvc.ApplicationModels.ControllerActionDescriptorProvider.OnProvidersExecuting(ActionDescriptorProviderContext context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.DefaultActionDescriptorCollectionProvider.UpdateCollection()
   at Microsoft.AspNetCore.Mvc.Infrastructure.DefaultActionDescriptorCollectionProvider.Initialize()
   at Microsoft.AspNetCore.Mvc.Routing.ActionEndpointDataSourceBase.<>c__DisplayClass11_0.<Subscribe>b__0()
   at Microsoft.Extensions.Primitives.ChangeToken.OnChange(Func`1 changeTokenProducer, Action changeTokenConsumer)
   at Microsoft.AspNetCore.Mvc.Routing.ActionEndpointDataSourceBase.Subscribe()
   at Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.GetOrCreateDataSource(IEndpointRouteBuilder endpoints)
   at Microsoft.AspNetCore.Builder.ControllerEndpointRouteBuilderExtensions.MapControllers(IEndpointRouteBuilder endpoints)
   at MyApp.Startup.<>c.<Configure>b__7_0(IEndpointRouteBuilder endpoints) in C:\Source\MyApp\Startup.cs:line 81
   at Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseEndpoints(IApplicationBuilder builder, Action`1 configure)
   at MyApp.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env) in C:\Source\MyApp\Startup.cs:line 79
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
   at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)

This occurs in some very boilerplate web startup code:

public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
   app.UseRouting();
   app.UseMiddleware<AddHostHeader>();
   app.UseEndpoints(endpoints =>
   {
       endpoints.MapControllers();      // <-- Exception occurs in here.
       endpoints.MapBlazorHub();
       endpoints.MapFallbackToPage("/_Host");
   });
   // .. snip ..
}

What am I doing wrong?

Okay, this does seem to be a bug. (And the behavior is definitely different from .NET 5 and 6.)

Reproduction steps are actually really simple:

  1. Create new .NET 7 Preview web project. (eg. dotnet new blazorserver)
  2. Add the following code anywhere:
public class TestController
{
    public void OutMethod(out char tone) => tone = default;
}
  1. Run the project.

image

The problem appears to be the out variable in a controller method. It is not particular to char, either. It seems to occur with any type, simple or complex.

Note that my original project, above, has many “Controller” classes that are not part of the web project proper (ie. they are not intended to be mapped by ASP.NET). I probably should find a way to disable the scanning for “Controller” classes (help?), but in the meantime this a breaking change for my particular code.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 19 (9 by maintainers)

Most upvoted comments

@ladenedge If I understood correctly, these classes with the Controller suffix are not expected to be MVC Controllers, right? If so, while we are investigating, probably you are already aware of, you can work around the issue adding the [NonController] attribute or just changing the suffix and maybe that could be a long-term change for you to avoid those classes to be registered.

This doc describes the basic rules for discovering a controller: https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/actions?view=aspnetcore-6.0#what-is-a-controller

I was able to repro the issue and looks like it is failing during a check for try/parse, introduced in .Net 7. Specifically when we call MakeByRefType().

https://github.com/dotnet/aspnetcore/blob/ca2238e75173d1f04ff0664c53dc443716a01b9d/src/Shared/ParameterBindingMethodCache.cs#L152

I will take a further look.

I updated the name & original issue description to reflect the root cause - @rafikiassumani-msft can you have someone from your team take a look since this appears to be a bug in controllers?