Learn how to initialize, configure, and use the GraphServiceClient for Microsoft Graph API requests
The GraphServiceClient is the main entry point for all Microsoft Graph SDK operations. It manages authentication, HTTP communication, and provides access to all API endpoints through strongly-typed request builders.
The GraphServiceClient class is defined in the Microsoft.Graph namespace and inherits from BaseGraphServiceClient. It implements IBaseClient and IDisposable, making it suitable for dependency injection and proper resource management.
GraphServiceClient.cs:21-22
using Microsoft.Graph;public class GraphServiceClient : BaseGraphServiceClient, IBaseClient, IDisposable
For advanced scenarios with full control over request processing:
using Microsoft.Graph;using Microsoft.Kiota.Abstractions;var requestAdapter = new CustomRequestAdapter(authProvider);var graphClient = new GraphServiceClient(requestAdapter);
Constructor signature from GraphServiceClient.cs:33-38:
public GraphServiceClient( IRequestAdapter requestAdapter, string baseUrl = null)
// List all usersvar users = await graphClient.Users.GetAsync();// Get specific user by IDvar user = await graphClient.Users["user-id"].GetAsync();// Get user by user principal namevar user = await graphClient.Users["[email protected]"].GetAsync();
// List all groupsvar groups = await graphClient.Groups.GetAsync();// Get specific groupvar group = await graphClient.Groups["group-id"].GetAsync();// Get group membersvar members = await graphClient.Groups["group-id"].Members.GetAsync();
The client provides access to batch request functionality:
using Microsoft.Graph;var graphClient = new GraphServiceClient(credential, scopes);// Access batch request buildervar batchBuilder = graphClient.Batch;// Batch requests allow multiple operations in a single HTTP call// See batch documentation for detailed examples
Property definition from GraphServiceClient.cs:104-110:
public BatchRequestBuilder Batch{ get { return new CustomBatchRequestBuilder(this.RequestAdapter); }}
The underlying request adapter for advanced customization:
var graphClient = new GraphServiceClient(credential, scopes);// Access the request adaptervar requestAdapter = graphClient.RequestAdapter;// Modify base URL dynamicallyrequestAdapter.BaseUrl = "https://graph.microsoft.com/beta";
Property definition from GraphServiceClient.cs:99:
public new IRequestAdapter RequestAdapter { get; set; }
The client implements IDisposable for proper resource cleanup:
using (var graphClient = new GraphServiceClient(credential, scopes)){ var user = await graphClient.Me.GetAsync(); // Client automatically disposed}// Or manuallyvar graphClient = new GraphServiceClient(credential, scopes);try{ var user = await graphClient.Me.GetAsync();}finally{ graphClient.Dispose();}
Implementation from GraphServiceClient.cs:115-121:
public void Dispose(){ if (this.RequestAdapter is IDisposable disposable) { disposable.Dispose(); }}
Only dispose the client when you’re done with it for the lifetime of your application. Don’t dispose between requests.
Create one GraphServiceClient instance and reuse it throughout your application:
// Good - reuse instanceprivate static GraphServiceClient _graphClient = new GraphServiceClient(credential, scopes);public async Task Method1(){ var user = await _graphClient.Me.GetAsync();}public async Task Method2(){ var messages = await _graphClient.Me.Messages.GetAsync();}
// Bad - creates new instance every callpublic async Task Method1(){ var client = new GraphServiceClient(credential, scopes); var user = await client.Me.GetAsync();}
Use dependency injection
Register the client in your DI container as a singleton:
services.AddSingleton<GraphServiceClient>(sp => new GraphServiceClient(credential, scopes));
This ensures:
Single instance across application
Proper lifecycle management
Easy testing with mocks
Consistent configuration
Handle authentication errors
Wrap client operations in try-catch blocks:
try{ var user = await graphClient.Me.GetAsync();}catch (ODataError ex) when (ex.ResponseStatusCode == 401){ // Handle authentication failure Console.WriteLine("Authentication failed. Token may be expired.");}catch (ODataError ex){ Console.WriteLine($"Graph API error: {ex.Error?.Code}");}
Configure timeouts appropriately
Set reasonable timeouts for your scenarios:
// For long-running operationsvar httpClient = new HttpClient{ Timeout = TimeSpan.FromMinutes(5)};var graphClient = new GraphServiceClient( httpClient, credential, scopes);
Use specific scopes
Request only the permissions you need:
// Good - specific permissionsstring[] scopes = { "User.Read", "Mail.Send" };// Avoid - overly broadstring[] scopes = { "https://graph.microsoft.com/.default" };
// Error: 401 Unauthorized// Cause: Invalid credentials or expired tokentry{ var user = await graphClient.Me.GetAsync();}catch (ODataError ex) when (ex.ResponseStatusCode == 401){ // Token may be expired or invalid // TokenCredential implementations handle refresh automatically // If this fails, check credential configuration}
// Error: 404 Not Found// Cause: Wrong base URL or endpoint not available in v1.0// Solution: Check if endpoint is beta-onlyvar graphClient = new GraphServiceClient( credential, scopes, "https://graph.microsoft.com/beta" // Use beta for preview features);