ASP.NET Core 6集成Microsoft Graph遇System.String实例创建错误求助
我用Microsoft Identity实现了ASP.NET Core 6应用的AAD认证,功能正常。现在要添加Microsoft Graph访问权限,修改认证代码如下:
builder.Services .AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd")) .EnableTokenAcquisitionToCallDownstreamApi() .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi")) .AddInMemoryTokenCaches();
这是多数开发者推荐的实现方式。DownstreamApi配置在appsettings.json中,包含BaseUrl和设为user.read的Scopes。
但无论尝试多种代码变体,始终抛出以下错误:
An unhandled exception occurred while processing the request.
InvalidOperationException: Cannot create instance of type 'System.String' because it is missing a public parameterless constructor.Microsoft.Extensions.Configuration.ConfigurationBinder.CreateInstance(Type type)
Stack Query Cookies Headers Routing
InvalidOperationException: Cannot create instance of type 'System.String' because it is missing a public parameterless constructor.
Microsoft.Extensions.Configuration.ConfigurationBinder.CreateInstance(Type type)
Microsoft.Extensions.Configuration.ConfigurationBinder.BindInstance(Type type, object instance, IConfiguration config, BinderOptions options)
Microsoft.Extensions.Configuration.ConfigurationBinder.GetPropertyValue(PropertyInfo property, object instance, IConfiguration config, BinderOptions options)
Microsoft.Extensions.Configuration.ConfigurationBinder.BindProperty(PropertyInfo property, object instance, IConfiguration config, BinderOptions options)
Microsoft.Extensions.Configuration.ConfigurationBinder.BindNonScalar(IConfiguration configuration, object instance, BinderOptions options)
Microsoft.Extensions.Configuration.ConfigurationBinder.BindInstance(Type type, object instance, IConfiguration config, BinderOptions options)
Microsoft.Extensions.Configuration.ConfigurationBinder.Bind(IConfiguration configuration, object instance, Action configureOptions)
Microsoft.Extensions.Configuration.ConfigurationBinder.Bind(IConfiguration configuration, object instance)
Microsoft.Identity.Web.MicrosoftIdentityWebAppAuthenticationBuilderWithConfiguration.b__1_0(ConfidentialClientApplicationOptions options)
Microsoft.Extensions.Options.ConfigureNamedOptions.Configure(string name, TOptions options)
Microsoft.Extensions.Options.OptionsFactory.Create(string name)
Microsoft.Extensions.Options.OptionsMonitor+<>c__DisplayClass10_0.b__0()
System.Lazy.ViaFactory(LazyThreadSafetyMode mode)
System.Lazy.ExecutionAndPublication(LazyHelper executionAndPublication, bool useDefaultConstructor)
System.Lazy.CreateValue()
System.Lazy.get_Value()
Microsoft.Extensions.Options.OptionsCache.GetOrAdd(string name, Func createOptions)
Microsoft.Extensions.Options.OptionsMonitor.Get(string name)
Microsoft.Identity.Web.MicrosoftIdentityWebAppAuthenticationBuilder+<>c__DisplayClass11_0.b__0(OpenIdConnectOptions options, IMergedOptionsStore mergedOptionsMonitor, IOptionsMonitor ccaOptionsMonitor, IOptions ccaOptions)
Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions, TDep1, TDep2, TDep3>.Configure(string name, TOptions options)
Microsoft.Extensions.Options.OptionsFactory.Create(string name)
Microsoft.Extensions.Options.OptionsMonitor+ <>c__DisplayClass10_0.b__0()
System.Lazy.ViaFactory(LazyThreadSafetyMode mode)
System.Lazy.ExecutionAndPublication(LazyHelper executionAndPublication, bool useDefaultConstructor)
System.Lazy.CreateValue()
System.Lazy.get_Value()Microsoft.Extensions.Options.OptionsCache.GetOrAdd(string name, Func createOptions)
Microsoft.Extensions.Options.OptionsMonitor.Get(string name)
Microsoft.AspNetCore.Authentication.AuthenticationHandler.InitializeAsync(AuthenticationScheme scheme, HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationHandlerProvider.GetHandlerAsync(HttpContext context, string authenticationScheme)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
我尝试了多种代码组合,始终得到相同错误。应用已在Azure中注册并添加Microsoft Graph权限,appsettings.json配置如下:
{ "AzureAd": { "Instance": "https://login.microsoftonline.com/", "Domain": "AAA", "ClientId": "BBB", "TenantId": "CCC", "ClientSecret": "DDD", "CallbackPath": "/signin-oidc", "SignedOutCallbackPath": "/signout-oidc", "RedirectUri": [ "https://localhost:7069", "https://localhost:7069/signin-oidc" ], "PostLogoutRedirectUri": "https://localhost:7069/Home/Index" }, "DownstreamApi": { "BaseUrl": "https://graph.microsoft.com/v1.0", "Scopes": "User.Read" } }
解决方案
问题根源在于DownstreamApi配置中的Scopes格式不符合要求:Microsoft Identity Web要求Scopes必须是数组类型,而非单个字符串。配置绑定过程中,尝试将字符串绑定到数组类型属性时,会触发反射创建System.String实例的操作,而字符串没有无参构造函数,因此抛出错误。
方法1:修改appsettings.json配置
将Scopes改为数组格式:
"DownstreamApi": { "BaseUrl": "https://graph.microsoft.com/v1.0", "Scopes": [ "User.Read" ] }
方法2:代码中手动指定作用域
如果不想修改配置文件,也可以在代码中直接传入作用域参数,跳过配置绑定:
builder.Services .AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd")) .EnableTokenAcquisitionToCallDownstreamApi(new[] { "User.Read" }) .AddMicrosoftGraph("https://graph.microsoft.com/v1.0", "User.Read") .AddInMemoryTokenCaches();
内容的提问来源于stack exchange,提问作者TMC

