-
Notifications
You must be signed in to change notification settings - Fork 56
Expand file tree
/
Copy pathGraphClientManager.cs
More file actions
210 lines (189 loc) · 8.86 KB
/
Copy pathGraphClientManager.cs
File metadata and controls
210 lines (189 loc) · 8.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
using Azure.Identity;
using Microsoft.Graph;
using Microsoft.Graph.Models;
using Microsoft.Graph.Models.ODataErrors;
using Microsoft.Graph.Drives.Item.Items.Item.CreateUploadSession;
using Microsoft.Kiota.Http.HttpClientLibrary.Middleware.Options;
using System.Net;
namespace MigrateABStoSPE
{
public class GraphClientManager: IGraphClientManager
{
private GraphServiceClient _graphClient;
private string _clientId;
private string _containerId;
string[] _scopes = { "User.Read", "FileStorageContainer.Selected" };
// This is a recommended size as a starting point. You can experiment with different chunk sizes.
// For example, increasing the chunk size might reduce the number of requests but could lead to
// larger data transfers that might be more susceptible to network issues.
private const int _maxChunkSize = 320 * 1024; // 320 KB - Upload the file in chunks
public GraphClientManager(GraphServiceClient graphClient, string tenantId, string clientId, string containerId, string?[] scopes)
{
if (graphClient == null)
{
if (scopes != null)
{
_scopes = scopes;
}
InteractiveBrowserCredentialOptions interactiveBrowserCredentialOptions = new InteractiveBrowserCredentialOptions()
{
TenantId = tenantId,
ClientId = clientId,
RedirectUri = new Uri("http://localhost"),
};
InteractiveBrowserCredential interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveBrowserCredentialOptions);
graphClient = new GraphServiceClient(interactiveBrowserCredential, scopes, null);
}
_graphClient = graphClient;
_clientId = clientId;
_containerId = containerId;
}
public async Task<bool> Authenticate()
{
try
{
var user = await _graphClient.Me.GetAsync();
if (user != null)
{
Utility.ConsoleWriteWithColor($"Graph Authenticated Successfully", ConsoleColor.Magenta);
return true;
}
Utility.ConsoleWriteWithColor($"Graph failed To Authenticate.", ConsoleColor.Red);
return false;
}
catch (Exception ex)
{
Utility.ConsoleWriteWithColor($"Graph failed To Authenticate. Exception: {ex.Message}.", ConsoleColor.Red);
return false;
}
}
public async Task<DriveItem?> CreateFolder(string folderName, string parentFolderId)
{
string functionName = "CreateFolder";
var folder = new DriveItem
{
Name = folderName,
Folder = new Folder(),
AdditionalData = new Dictionary<string, object>()
{
{ "@microsoft.graph.conflictBehavior", "fail" }
}
};
try
{
// Retry has already been implemented in the Graph SDK
var createdFolder = await _graphClient.Drives[_containerId].Items[parentFolderId].Children.PostAsync(folder);
if (createdFolder != null)
{
Utility.ConsoleWriteWithColor($"{functionName}: Folder Created \"{folderName}\". Parent: {parentFolderId}", ConsoleColor.Cyan);
return createdFolder;
}
Utility.ConsoleWriteWithColor($"{functionName}: Failed to create folder \"{folderName}\". Parent: {parentFolderId}", ConsoleColor.Red);
return null;
}
catch (ODataError odataError)
{
HandleUnsuccessfulResponse(odataError, "Create folder request failed", parentFolderId, folderName);
return null;
}
catch (Exception ex)
{
HandleUnsuccessfulResponse(ex, "Failed to create folder", parentFolderId, folderName);
return null;
}
}
public async Task<DriveItem?> CheckIfItemExists(string itemPath, string parentFolderId)
{
string functionName = "CheckIfItemExists";
try
{
var item = await _graphClient.Drives[_containerId].Items[parentFolderId].ItemWithPath(itemPath).GetAsync();
if (item != null)
{
Utility.ConsoleWriteWithColor($"{functionName} - Item name: \"{itemPath}\" exist. Parent: \"{parentFolderId}\"", ConsoleColor.Yellow);
return item;
}
}
catch (ODataError odataError)
{
HandleUnsuccessfulResponse(odataError, "Check item exists request failed", parentFolderId, itemPath);
}
catch (Exception e)
{
HandleUnsuccessfulResponse(e, "Failed to check item exists", parentFolderId, itemPath);
Console.WriteLine($"An exception occurred while checking to see if item exists: {itemPath}: {e.Message}");
}
return null;
}
public async Task<bool> UploadStreamToSharePointAsync(Stream stream, string parentFolderId, string fileName)
{
var uploadSessionRequestBody = new CreateUploadSessionPostRequestBody()
{
AdditionalData = new Dictionary<string, object>
{
{ "@microsoft.graph.conflictBehavior", "fail" }
}
};
try
{
var uploadSession = await _graphClient.Drives[_containerId]
.Items[parentFolderId]
.ItemWithPath(fileName)
.CreateUploadSession
.PostAsync(uploadSessionRequestBody);
var fileUploadTask = new LargeFileUploadTask<DriveItem>(uploadSession, stream, _maxChunkSize, _graphClient.RequestAdapter);
IProgress<long> progress = new Progress<long>(prog => Console.WriteLine($"Uploaded {fileName} {prog} bytes"));
var uploadResult = await fileUploadTask.UploadAsync(progress);
if (uploadResult.UploadSucceeded)
{
Console.WriteLine($"Upload succeeded: {fileName}!");
return true;
}
else
{
Console.WriteLine($"Upload failed: {fileName}.");
return false;
}
}
catch (Exception ex)
{
Utility.ConsoleWriteWithColor($"An error occurred while uploading: {fileName}! Exception: {ex.Message}", ConsoleColor.Red);
throw ex;
}
}
/// <summary>
/// Handles an unsuccessful response from the Graph API.
/// </summary>
/// <param name="error">The ODataError or Exception object representing the error response.</param>
/// <param name="errorString">The error string to display.</param>
/// <param name="parentFolderId">The ID of the parent folder.</param>
/// <param name="item">The name of the item.</param>
private void HandleUnsuccessfulResponse(Object error, string errorString, string parentFolderId, string item)
{
Utility.ConsoleWriteWithColor($"{errorString} - Item name: \"{item}\". Parent: \"{parentFolderId}\"", ConsoleColor.Red);
if (error is ODataError oDataError)
{
switch (oDataError.ResponseStatusCode)
{
case (int)HttpStatusCode.BadRequest:
Utility.ConsoleWriteWithColor($"Error: {oDataError.Error.Message}. Status code: {oDataError.ResponseStatusCode}.", ConsoleColor.Red);
break;
case (int)HttpStatusCode.Conflict:
Utility.ConsoleWriteWithColor($"Warning: {oDataError.Error.Message}. Status code: {oDataError.ResponseStatusCode}.", ConsoleColor.Yellow);
break;
case (int)HttpStatusCode.NotFound:
Utility.ConsoleWriteWithColor($"Warning: Item not found {item}", ConsoleColor.Yellow);
break;
default:
Utility.ConsoleWriteWithColor($"An error occurred. Please try again later. Status code: {oDataError.ResponseStatusCode}. Error message: {oDataError.Error.Message}", ConsoleColor.Red);
break;
}
return;
}
if (error is Exception e)
{
Utility.ConsoleWriteWithColor($"Unexpected exception occurred. Error message: {e.Message}", ConsoleColor.Red);
}
}
}
}