Skip to content

Commit df675c9

Browse files
authored
Merge pull request #3 from atc-net/feature/init_services
Init Services and ServiceCollectionExtensions
2 parents 3ce48f0 + de37df1 commit df675c9

22 files changed

+2046
-2
lines changed

.editorconfig

+16-1
Original file line numberDiff line numberDiff line change
@@ -519,4 +519,19 @@ dotnet_diagnostic.S6605.severity = none # Collection-specific "Exist
519519
##########################################
520520
# Custom - Code Analyzers Rules
521521
##########################################
522-
[*.{cs,csx,cake}]
522+
[*.{cs,csx,cake}]
523+
524+
MA0051.maximum_lines_per_method = 100
525+
526+
dotnet_diagnostic.SA1010.severity = none #
527+
dotnet_diagnostic.SA1402.severity = none #
528+
dotnet_diagnostic.SA1615.severity = none #
529+
530+
dotnet_diagnostic.CA1002.severity = none #
531+
dotnet_diagnostic.CA1031.severity = none #
532+
dotnet_diagnostic.CA2007.severity = none # Consider calling ConfigureAwait on the awaited task
533+
534+
dotnet_diagnostic.MA0004.severity = none # Use Task.ConfigureAwait(false) as the current SynchronizationContext is not needed
535+
dotnet_diagnostic.MA0016.severity = none # Prefer returning collection abstraction instead of implementation
536+
537+
dotnet_diagnostic.S3267.severity = none #
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2+
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sharepoint/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

src/.editorconfig

+3-1
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,6 @@
4444

4545
##########################################
4646
# Custom - Code Analyzers Rules
47-
##########################################
47+
##########################################
48+
49+
dotnet_diagnostic.IDE0039.severity = none #

src/Atc.Microsoft.Graph.Client/Atc.Microsoft.Graph.Client.csproj

+8
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,12 @@
1212
<None Include="..\..\README.md" Link="README.md" Pack="true" PackagePath="\" />
1313
</ItemGroup>
1414

15+
<ItemGroup>
16+
<PackageReference Include="Atc" Version="2.0.472" />
17+
<PackageReference Include="Azure.Identity" Version="1.11.3" />
18+
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.5.0" />
19+
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
20+
<PackageReference Include="Microsoft.Graph" Version="5.53.0" />
21+
</ItemGroup>
22+
1523
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// ReSharper disable ConvertToLocalFunction
2+
namespace Atc.Microsoft.Graph.Client.Extensions;
3+
4+
public static class ServiceCollectionExtensions
5+
{
6+
private static readonly string[] DefaultScopes = { "https://graph.microsoft.com/.default" };
7+
8+
/// <summary>
9+
/// Adds the <see cref="GraphServiceClient"/> to the service collection.
10+
/// </summary>
11+
/// <param name="services">The <see cref="IServiceCollection"/> instance to augment.</param>
12+
/// <param name="graphServiceClient"><see cref="GraphServiceClient"/> to use for the service. If null, one must be available in the service provider when this service is resolved.</param>
13+
/// <returns>The same instance as <paramref name="services"/>.</returns>
14+
public static IServiceCollection AddMicrosoftGraphServices(
15+
this IServiceCollection services,
16+
GraphServiceClient? graphServiceClient = null)
17+
{
18+
Func<IServiceProvider, GraphServiceClient> factory = (serviceProvider)
19+
=> graphServiceClient ?? serviceProvider.GetRequiredService<GraphServiceClient>();
20+
21+
services.AddSingleton(factory);
22+
23+
RegisterGraphServices(services);
24+
25+
return services;
26+
}
27+
28+
/// <summary>
29+
/// Adds the <see cref="GraphServiceClient"/> to the service collection using the provided <see cref="TokenCredential"/> and optional scopes.
30+
/// </summary>
31+
/// <param name="services">The <see cref="IServiceCollection"/> instance to augment.</param>
32+
/// <param name="tokenCredential">The <see cref="TokenCredential"/> to use for authentication.</param>
33+
/// <param name="scopes">Optional array of scopes for the <see cref="GraphServiceClient"/>.</param>
34+
/// <returns>The same instance as <paramref name="services"/>.</returns>
35+
public static IServiceCollection AddMicrosoftGraphServices(
36+
this IServiceCollection services,
37+
TokenCredential tokenCredential,
38+
string[]? scopes = null)
39+
{
40+
services.AddSingleton(_ => new GraphServiceClient(tokenCredential, scopes ?? DefaultScopes));
41+
42+
RegisterGraphServices(services);
43+
44+
return services;
45+
}
46+
47+
/// <summary>
48+
/// Adds the <see cref="GraphServiceClient"/> to the service collection using the provided <see cref="GraphServiceOptions"/> and optional scopes.
49+
/// </summary>
50+
/// <param name="services">The <see cref="IServiceCollection"/> instance to augment.</param>
51+
/// <param name="graphServiceOptions">The <see cref="GraphServiceOptions"/> containing configuration for the service.</param>
52+
/// <param name="scopes">Optional array of scopes for the <see cref="GraphServiceClient"/>.</param>
53+
/// <returns>The same instance as <paramref name="services"/>.</returns>
54+
/// <exception cref="InvalidOperationException">Thrown if the <paramref name="graphServiceOptions"/> are invalid.</exception>
55+
public static IServiceCollection AddMicrosoftGraphServices(
56+
this IServiceCollection services,
57+
GraphServiceOptions graphServiceOptions,
58+
string[]? scopes = null)
59+
{
60+
ArgumentNullException.ThrowIfNull(graphServiceOptions);
61+
62+
if (!graphServiceOptions.IsValid())
63+
{
64+
throw new InvalidOperationException($"Required service '{nameof(GraphServiceOptions)}' is not registered");
65+
}
66+
67+
services.AddSingleton(_ =>
68+
{
69+
var options = new TokenCredentialOptions
70+
{
71+
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
72+
};
73+
74+
var clientSecretCredential = new ClientSecretCredential(
75+
graphServiceOptions.TenantId,
76+
graphServiceOptions.ClientId,
77+
graphServiceOptions.ClientSecret,
78+
options);
79+
80+
return new GraphServiceClient(clientSecretCredential, scopes ?? DefaultScopes);
81+
});
82+
83+
RegisterGraphServices(services);
84+
85+
return services;
86+
}
87+
88+
private static void RegisterGraphServices(
89+
IServiceCollection services)
90+
{
91+
services.AddGraphService<IOneDriveGraphService, OneDriveGraphService>();
92+
services.AddGraphService<IOutlookGraphService, OutlookGraphService>();
93+
services.AddGraphService<ISharepointGraphService, SharepointGraphService>();
94+
services.AddGraphService<ITeamsGraphService, TeamsGraphService>();
95+
services.AddGraphService<IUsersGraphService, UsersGraphService>();
96+
}
97+
98+
private static void AddGraphService<TService, TImplementation>(
99+
this IServiceCollection services)
100+
where TService : class
101+
where TImplementation : GraphServiceClientWrapper, TService
102+
{
103+
services.AddSingleton<TService, TImplementation>(s => (TImplementation)Activator.CreateInstance(
104+
typeof(TImplementation),
105+
s.GetRequiredService<ILoggerFactory>(),
106+
s.GetRequiredService<GraphServiceClient>())!);
107+
}
108+
}

0 commit comments

Comments
 (0)