使用 Hangfire 进行 Microsoft Graph API 调用

Making Microsoft Graph API call with Hangfire

我正在努力使用 Hangfire 后台作业延迟进行图形 API 调用,因为我认为在进行调用时 HttpContext 为空,我不确定如何解决此问题。

// 将作业设置为延迟触发

BackgroundJob.Schedule(() => this.HangfireTest("test@gmail.com", false), TimeSpan.FromSeconds(20));

// 调用图 api,返回结果为 'Not yet computed'

var userInfo = this.graphServiceClient.Me.Request().Select(Info.Fields).GetAsync();

我试过传入上下文,但这不起作用。不知道如何解决这个问题。谢谢!

这是为我工作的 ASP.Net Core 3.1 MVC 原型实现。我在寻找解决方案时也遇到了很多问题,因此将其发布在这里。我已经编辑了一些代码以使其更易于阅读并删除了解决此问题不需要的膨胀。

请注意,该方法是从 GraphAPI 检索访问令牌并将其传递给后台作业,创建一个新的 stand-alone GraphClient 实例并添加包含访问令牌的所需承载 header。

在 startup.cs 中,EnableTokenAcquisition 允许在控制器中检索访问令牌。

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(this.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
    .AddMicrosoftGraph(this.Configuration.GetSection("DownstreamApi"))
    .AddInMemoryTokenCaches();

控制器初始化...

using Microsoft.Graph;
using Microsoft.Identity.Web;

private readonly GraphServiceClient graphServiceClient;
private readonly ITokenAcquisition tokenAcquisition = null;

public HomeController(ILogger<HomeController> logger, IConfiguration iconfiguration, GraphServiceClient graphServiceClient, ITokenAcquisition tokenAcquisition)
{
    this.graphServiceClient = graphServiceClient;
    this.tokenAcquisition = tokenAcquisition;
}

安排作业控制器操作

public IActionResult ScheduleJob(BackgroundJobsViewModel model)
{
    try
    {
        string accessToken = string.Empty;

        try
        {
            accessToken = Task.Run(async () => await this.tokenAcquisition.GetAccessTokenForUserAsync(scopeList)).Result;
        }
        catch (MicrosoftIdentityWebChallengeUserException ex)
        {
            Task.Run(async () => await this.tokenAcquisition.ReplyForbiddenWithWwwAuthenticateHeaderAsync(scopeList, ex.MsalUiRequiredException));
        }
        catch (Microsoft.Identity.Client.MsalUiRequiredException ex)
        {
            Task.Run(async () => await this.tokenAcquisition.ReplyForbiddenWithWwwAuthenticateHeaderAsync(scopeList, ex));
        }

        if (!string.IsNullOrEmpty(accessToken))
        {

            // Recurring Job.
            RecurringJob.AddOrUpdate(job.JobName, () => UpdateUsersBackroundJob.UpdateUsers(this.currentUser.Account, accessToken), $"{seconds} {minutes} {hours} {day} {month} {week}");
        }
        else
        {
            return this.View("BackgroundJobs", model);
        }
    }
    catch (Exception ex)
    {
        var errorModel = this.HandleException(ex);
        return this.View("Error", errorModel);
    }
}

后台工作class和方法...注意Info.Fields我没有显示。

using Microsoft.Graph;
using Microsoft.Identity.Web;

/// <summary>
/// Class to encapsulate the background job to update users.
/// </summary>
public class UpdateUsersBackroundJob
{
    /// <summary>
    /// Gets or sets the Graph Client.
    /// </summary>
    private static GraphServiceClient GraphClient { get; set; }

    public static void UpdateUsers(string upnName, string graphApiAccessToken)
    {
        if (string.IsNullOrEmpty(graphApiAccessToken))
        {
            throw new ApplicationException("Cannot run the update users background job without specifying an access token first.");
        }

        // Create our own new graph client using the provided token.
        GraphClient = new GraphServiceClient(new DelegateAuthenticationProvider((requestMessage) =>
        {
            requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", graphApiAccessToken);
            return Task.FromResult(0);
        }));
        
        try
        {

                // Update DB User data from GraphAPI Azure AD
                var userInfo = Task.Run(async () => await GraphClient.Me.Request().Select(Info.Fields).GetAsync()).Result;
                
                ...do something with userInfo in application.
            }
            catch
            {
                ...Handle exception.
            }
        }
    }
}