如何在 Microsoft Graph 中使用 DI

How to use DI with Microsoft Graph

我有一个 .net web api 核心项目,我将调用 microsoft graph

所以我创建了一个配置class:

public class GraphConfiguration
    {
        public static void Configure(IServiceCollection services, IConfiguration configuration)
        {
            //Look at appsettings.Development.json | https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.1
            var graphConfig = new AppSettingsSection();
            configuration.GetSection("AzureAD").Bind(graphConfig);

            IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
                .Create(graphConfig.ClientId)
                .WithTenantId(graphConfig.TenantId)
                .WithClientSecret(graphConfig.ClientSecret)
                .Build();
                
            ClientCredentialProvider authenticationProvider = new ClientCredentialProvider(confidentialClientApplication);
            GraphServiceClient graphServiceClient = new GraphServiceClient(authenticationProvider);     

        }
    }

在我的控制器中我有这个:

 public class UserController : ControllerBase
    {
        private TelemetryClient telemetry;
        private readonly ICosmosStore<Partner> _partnerCosmosStore;
        private readonly GraphServiceClient _graphServiceClient;


        // Use constructor injection to get a TelemetryClient instance.
        public UserController(TelemetryClient telemetry,ICosmosStore<Partner> partnerCosmosStore, GraphServiceClient graphServiceClient)
        {
            this.telemetry = telemetry;
             _partnerCosmosStore = partnerCosmosStore; 
             _graphServiceClient = graphServiceClient;          
        }

        /// <summary>
        /// Gets all partners
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<ActionResult> GetUsers()
        {
            this.telemetry.TrackEvent("GetPartners");
        
            try
            {
                var me = await _graphServiceClient.Me.Request().WithForceRefresh(true).GetAsync();
                return Ok(me);
            }
            catch (Exception ex)
            {
                string guid = Guid.NewGuid().ToString();
                var dt = new Dictionary<string, string>
                {
                    { "Error Lulo: ", guid }
                };
                telemetry.TrackException(ex, dt);
                return BadRequest("Error Lulo: " + guid);
            }
        }      
    }

但我想我在 Startupcs 中漏掉了一步。我如何在所有控制器中实际注入它?

我认为你应该让你的方法 return 成为一个 IServiceCollection 然后在你的 startup.cs.

中调用它
    public class GraphConfiguration
        {
            public static IServiceCollection AddGraphComponent(this IServiceCollection services, IConfiguration configuration)
            {
                //your code

                services.AddSingleton<ClientCredentialProvider>(x =>
                {
                     return new GraphServiceClient(authenticationProvider);
                });

                services.AddSingleton<GraphServiceClient>(x =>
                {
                     return new ClientCredentialProvider(confidentialClientApplication);
                });    

                return services    
            }
        }

然后在你的startup.cs中的ConfigureServices方法中调用这个方法。

 services.AddGraphComponent(yourConfiguration);

我建议用 DI 容器注册 GraphServiceClient

public static class GraphConfiguration {
    //Called in Startup - services.ConfigureGraphComponent(configuration)
    public static IServiceCollection ConfigureGraphComponent(this IServiceCollection services, IConfiguration configuration) {
        //Look at appsettings.Development.json | https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.1
        
        AppSettingsSection graphConfig = configuration.GetSection("AzureAD").Get<AppSettingsSection>();

        IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
            .Create(graphConfig.ClientId)
            .WithTenantId(graphConfig.TenantId)
            .WithClientSecret(graphConfig.ClientSecret)
            .Build();
            
        ClientCredentialProvider authenticationProvider = new ClientCredentialProvider(confidentialClientApplication);

        services.AddScoped<GraphServiceClient>(sp => {
            return new GraphServiceClient(authenticationProvider);
        });

        return services;
    }
}

这样容器就会知道如何在解析控制器时注入所需的依赖项

我想用 .NET 6.0 中对我有用的内容扩展@Nkosi 的回答

需要的包:

Microsoft.Graph 4.x.x
Microsoft.Graph.Auth 1.0.0-preview (not production-ready if that's an issue)

我的 GraphConfiguration class 略有不同,因为 AppSettingsSection 没有公开 .ClientId.TenantId

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Graph;
using Microsoft.Graph.Auth;
using Microsoft.Identity.Client;

namespace EMF.Events.Business.Providers.Graph
{
    public static class GraphConfiguration
    {
        public static IServiceCollection ConfigureGraphClient( this IServiceCollection services, IConfiguration configuration )
        {
            var graphConfig = configuration.GetSection( "AzureAd" );

            var confidentialClientApplication = ConfidentialClientApplicationBuilder
                .Create( graphConfig["ClientId"] )
                .WithTenantId( graphConfig["TenantId"] )
                .WithClientSecret( graphConfig["ClientSecret"] )
                .Build();

            ClientCredentialProvider authenticationProvider = new ClientCredentialProvider( confidentialClientApplication );

            services.AddScoped( sp =>
            {
                return new GraphServiceClient( authenticationProvider );
            } );

            return services;
        }
    }
}

然后在我的 Program.cs...

builder.Services.ConfigureGraphClient( builder.Configuration );

你的 appsettings.json 应该有以下内容(可能还有一些你应该 不删除的其他键 :

"AzureAd": {
    ...
    "TenantId": "<TENANT_ID>",
    "ClientId": "<CLIENT_ID>",
    "ClientSecret": "<CLIENT_SECRET>",
  },

该部分的另一个注意事项是 case-sensitive 因此,如果您的是“AzureAD”而不是“AzureAd”,请相应地进行调整。