Blazor WebAssembly GraphClientExtensions 在升级 Microsoft.Graph 到版本 5.0 后出现故障。

huangapple go评论59阅读模式
英文:

Blazor WebAssembly GraphClientExtensions fails after upgrading Microsoft.Graph to version 5.0

问题

Blazor WebAssembly GraphClientExtensions 在升级 Microsoft.Graph 到版本 5.0 后出现故障

框架: .NET 7

错误:

  • 未找到类型或命名空间名称 'IAuthenticationProvider'

  • 未找到类型或命名空间名称 'IHttpProvider'

  • 未找到类型或命名空间名称 'ISerializer'

GraphClientExtensions 代码:

    internal static class GraphClientExtensions
    {
        public static IServiceCollection AddGraphClient(
            this IServiceCollection services, params string[] scopes)
        {
            services.Configure<RemoteAuthenticationOptions<MsalProviderOptions>>(
                options =>
                {
                    foreach (var scope in scopes)
                    {
                        options.ProviderOptions.AdditionalScopesToConsent.Add(scope);
                    }
                });

            services.AddScoped<IAuthenticationProvider,
                NoOpGraphAuthenticationProvider>();
            services.AddScoped<IHttpProvider, HttpClientHttpProvider>(sp =>
                new HttpClientHttpProvider(new HttpClient()));
            services.AddScoped(sp =>
            {
                return new GraphServiceClient(
                    sp.GetRequiredService<IAuthenticationProvider>(),
                    sp.GetRequiredService<IHttpProvider>());
            });

            return services;
        }

        private class NoOpGraphAuthenticationProvider : IAuthenticationProvider
        {
            public NoOpGraphAuthenticationProvider(IAccessTokenProvider tokenProvider)
            {
                TokenProvider = tokenProvider;
            }

            public IAccessTokenProvider TokenProvider { get; }

            public async Task AuthenticateRequestAsync(HttpRequestMessage request)
            {
                var result = await TokenProvider.RequestAccessToken(
                    new AccessTokenRequestOptions()
                    {
                        Scopes = new[] { "https://graph.microsoft.com/User.Read" }
                    });

                if (result.TryGetToken(out var token))
                {
                    request.Headers.Authorization ??= new AuthenticationHeaderValue(
                        "Bearer", token.Value);
                }
            }
        }

        private class HttpClientHttpProvider : IHttpProvider
        {
            private readonly HttpClient http;

            public HttpClientHttpProvider(HttpClient http)
            {
                this.http = http;
            }

            public ISerializer Serializer { get; } = new Serializer();

            public TimeSpan OverallTimeout { get; set; } = TimeSpan.FromSeconds(300);

            public void Dispose()
            {
            }

            public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
            {
                return http.SendAsync(request);
            }

            public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
                HttpCompletionOption completionOption,
                CancellationToken cancellationToken)
            {
                return http.SendAsync(request, completionOption, cancellationToken);
            }
        }
    }

升级以下包导致了错误:

  • 从 4.54.0 升级到 5.0.0 的 Microsoft.Graph

  • 从 2.0.15 升级到 3.0.0 的 Microsoft.Graph.Core

英文:

Blazor WebAssembly GraphClientExtensions fails after upgrading Microsoft.Graph to version 5.0

Framework: Dot NET 7

Errors:

  • The type or namespace name 'IAuthenticationProvider' could not be found

  • The type or namespace name 'IHttpProvider' could not be found

  • The type or namespace name 'ISerializer' could not be found

GraphClientExtensions Code:

    internal static class GraphClientExtensions
{
public static IServiceCollection AddGraphClient(
this IServiceCollection services, params string[] scopes)
{
services.Configure&lt;RemoteAuthenticationOptions&lt;MsalProviderOptions&gt;&gt;(
options =&gt;
{
foreach (var scope in scopes)
{
options.ProviderOptions.AdditionalScopesToConsent.Add(scope);
}
});
services.AddScoped&lt;IAuthenticationProvider,
NoOpGraphAuthenticationProvider&gt;();
services.AddScoped&lt;IHttpProvider, HttpClientHttpProvider&gt;(sp =&gt;
new HttpClientHttpProvider(new HttpClient()));
services.AddScoped(sp =&gt;
{
return new GraphServiceClient(
sp.GetRequiredService&lt;IAuthenticationProvider&gt;(),
sp.GetRequiredService&lt;IHttpProvider&gt;());
});
return services;
}
private class NoOpGraphAuthenticationProvider : IAuthenticationProvider
{
public NoOpGraphAuthenticationProvider(IAccessTokenProvider tokenProvider)
{
TokenProvider = tokenProvider;
}
public IAccessTokenProvider TokenProvider { get; }
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
var result = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions()
{
Scopes = new[] { &quot;https://graph.microsoft.com/User.Read&quot; }
});
if (result.TryGetToken(out var token))
{
request.Headers.Authorization ??= new AuthenticationHeaderValue(
&quot;Bearer&quot;, token.Value);
}
}
}
private class HttpClientHttpProvider : IHttpProvider
{
private readonly HttpClient http;
public HttpClientHttpProvider(HttpClient http)
{
this.http = http;
}
public ISerializer Serializer { get; } = new Serializer();
public TimeSpan OverallTimeout { get; set; } = TimeSpan.FromSeconds(300);
public void Dispose()
{
}
public Task&lt;HttpResponseMessage&gt; SendAsync(HttpRequestMessage request)
{
return http.SendAsync(request);
}
public Task&lt;HttpResponseMessage&gt; SendAsync(HttpRequestMessage request,
HttpCompletionOption completionOption,
CancellationToken cancellationToken)
{
return http.SendAsync(request, completionOption, cancellationToken);
}
}
}

Upgrading the below packages caused the error:

  • Microsoft.Graph from 4.54.0 to 5.0.0

  • Microsoft.Graph.Core from 2.0.15 to 3.0.0

答案1

得分: 2

I see that you've provided a code snippet and some related information. How can I assist you further with this code or any specific questions you have?

英文:

Just attach a guide for migrating to V5 here.

==============================

First, the issue comes from the changes of the package. There's no IHttpProvider and ISerializer in Microsoft.Graph V5.0, and IAuthenticationProvider changed from Microsoft.Graph.IAuthenticationProvider to Microsoft.AspNetCore.Components.WebAssembly.Authentication.IAccessTokenProvider.

To troubleshoot this issue, I think we need to first integrate AAD into blazor wsam app. We just need to create a new application with picking up the authentication.

Blazor WebAssembly GraphClientExtensions 在升级 Microsoft.Graph 到版本 5.0 后出现故障。

Then we add the Graph SDK. But the tutorial in official document hasn't updated. Using code in screenshot below will had issue like what you mentioned.

Blazor WebAssembly GraphClientExtensions 在升级 Microsoft.Graph 到版本 5.0 后出现故障。

Now the construction method for GraphServiceClient is like below:

public GraphServiceClient(IRequestAdapter requestAdapter, string baseUrl = null): base(InitializeRequestAdapterWithBaseUrl(requestAdapter,baseUrl))
{
this.RequestAdapter = requestAdapter;
}
public GraphServiceClient(TokenCredential tokenCredential,IEnumerable&lt;string&gt; scopes = null,string baseUrl = null
):this(new Microsoft.Graph.Authentication.AzureIdentityAuthenticationProvider(tokenCredential, null, null,scopes?.ToArray() ?? Array.Empty&lt;string&gt;()), baseUrl)
{
}
public GraphServiceClient(IAuthenticationProvider authenticationProvider,string baseUrl = null
): this(new BaseGraphRequestAdapter(authenticationProvider, graphClientOptions),baseUrl)
{
}
public GraphServiceClient(HttpClient httpClient, IAuthenticationProvider authenticationProvider = null,
string baseUrl = null):this(new BaseGraphRequestAdapter(authenticationProvider ?? new AnonymousAuthenticationProvider(), graphClientOptions, httpClient: httpClient),baseUrl)
{
}

So we need to re-implement the IAuthenticationProvider so that we can use it to inject new version GraphServiceClient. And below is what I did and it worked for me.

In blazor webassembly, we can change to write code like this:

Program.cs:

using BlazorWsamNet7;
using BlazorWsamNet7.Data;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add&lt;App&gt;(&quot;#app&quot;);
builder.RootComponents.Add&lt;HeadOutlet&gt;(&quot;head::after&quot;);
builder.Services.AddScoped(sp =&gt; new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
var baseUrl = string.Join(&quot;/&quot;,
builder.Configuration.GetSection(&quot;MicrosoftGraph&quot;)[&quot;BaseUrl&quot;],
builder.Configuration.GetSection(&quot;MicrosoftGraph&quot;)[&quot;Version&quot;]);
var scopes = builder.Configuration.GetSection(&quot;MicrosoftGraph:Scopes&quot;)
.Get&lt;List&lt;string&gt;&gt;();
builder.Services.AddGraphClient(baseUrl, scopes);
builder.Services.AddMsalAuthentication(options =&gt;
{
builder.Configuration.Bind(&quot;AzureAd&quot;, options.ProviderOptions.Authentication);
});
await builder.Build().RunAsync();

Then GraphClientExtensions:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Authentication.WebAssembly.Msal.Models;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Graph;
using Microsoft.Kiota.Abstractions;
using Microsoft.Kiota.Abstractions.Authentication;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http;
using System.Net.Http.Headers;
namespace BlazorWsamNet7.Data
{
internal static class GraphClientExtensions
{
public static IServiceCollection AddGraphClient(
this IServiceCollection services, string? baseUrl, List&lt;string&gt;? scopes)
{
services.Configure&lt;RemoteAuthenticationOptions&lt;MsalProviderOptions&gt;&gt;(
options =&gt;
{
scopes?.ForEach((scope) =&gt;
{
options.ProviderOptions.AdditionalScopesToConsent.Add(scope);
});
});
services.AddScoped&lt;IAuthenticationProvider, GraphAuthenticationProvider&gt;();
services.AddScoped(sp =&gt;
{
return new GraphServiceClient(
new HttpClient(),
sp.GetRequiredService&lt;IAuthenticationProvider&gt;(),
baseUrl);
});
return services;
}
private class GraphAuthenticationProvider : IAuthenticationProvider
{
private readonly IConfiguration config;
public GraphAuthenticationProvider(Microsoft.AspNetCore.Components.WebAssembly.Authentication.IAccessTokenProvider tokenProvider,
IConfiguration config)
{
TokenProvider = tokenProvider;
this.config = config;
}
public Microsoft.AspNetCore.Components.WebAssembly.Authentication.IAccessTokenProvider TokenProvider { get; }
public async Task AuthenticateRequestAsync(RequestInformation request, Dictionary&lt;string, object&gt;? additionalAuthenticationContext = null, CancellationToken cancellationToken = default)
{
var result = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions()
{
Scopes = config.GetSection(&quot;MicrosoftGraph:Scopes&quot;).Get&lt;string[]&gt;()
});
if (result.TryGetToken(out var token))
{
//request.Headers.Authorization ??= new AuthenticationHeaderValue(&quot;Bearer&quot;, token.Value);
request.Headers.Add(&quot;Authorization&quot;, &quot;Bearer &quot;+token.Value);
}
}
}
}
}

appsetting.json:

{
&quot;AzureAd&quot;: {
&quot;Authority&quot;: &quot;https://login.microsoftonline.com/tenant_id&quot;,
&quot;ClientId&quot;: &quot;aad_client_id&quot;,
&quot;ValidateAuthority&quot;: true
},
&quot;MicrosoftGraph&quot;: {
&quot;BaseUrl&quot;: &quot;https://graph.microsoft.com&quot;,
&quot;Version&quot;: &quot;v1.0&quot;,
&quot;Scopes&quot;: [
&quot;user.read&quot;
]
}
}

my View razor component:

@page &quot;/profile&quot;
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
@using Microsoft.Graph;
@using Microsoft.Graph.Models;
@inject GraphServiceClient GraphClient
@attribute [Authorize]
&lt;h3&gt;UserProfile&lt;/h3&gt;
@{
&lt;table class=&quot;table&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tr&gt;
&lt;td&gt; DisplayName &lt;/td&gt;
&lt;td&gt; @_user.DisplayName &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt; UserPrincipalName &lt;/td&gt;
&lt;td&gt; @_user.UserPrincipalName &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
}
@code {
protected User _user = new User();
protected override async Task OnInitializedAsync()
{
try
{
_user = await GraphClient.Me.GetAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}

Test result:

Blazor WebAssembly GraphClientExtensions 在升级 Microsoft.Graph 到版本 5.0 后出现故障。
Blazor WebAssembly GraphClientExtensions 在升级 Microsoft.Graph 到版本 5.0 后出现故障。

huangapple
  • 本文由 发表于 2023年3月1日 13:59:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/75600048.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定