From a9a7feae734042bd23cbce3e6608c128affefa6e Mon Sep 17 00:00:00 2001 From: Mark Szabo Date: Sat, 7 Apr 2018 20:29:46 +0200 Subject: [PATCH] #12 using beta endpoint where MSA account needs picture --- .vscode/launch.json | 46 +++++++ .vscode/tasks.json | 15 +++ .../Helpers/GraphService.cs | 120 +++++++++++++++--- 3 files changed, 163 insertions(+), 18 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..85b255f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,46 @@ +{ + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (web)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/MicrosoftGraphAspNetCoreConnectSample/bin/Debug/netcoreapp2.0/MicrosoftGraphAspNetCoreConnectSample.dll", + "args": [], + "cwd": "${workspaceFolder}/MicrosoftGraphAspNetCoreConnectSample", + "stopAtEntry": false, + "internalConsoleOptions": "openOnSessionStart", + "launchBrowser": { + "enabled": true, + "args": "${auto-detect-url}", + "windows": { + "command": "cmd.exe", + "args": "/C start ${auto-detect-url}" + }, + "osx": { + "command": "open" + }, + "linux": { + "command": "xdg-open" + } + }, + "env": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "sourceFileMap": { + "/Views": "${workspaceFolder}/Views" + } + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..a825e2d --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,15 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "taskName": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/MicrosoftGraphAspNetCoreConnectSample/MicrosoftGraphAspNetCoreConnectSample.csproj" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/MicrosoftGraphAspNetCoreConnectSample/Helpers/GraphService.cs b/MicrosoftGraphAspNetCoreConnectSample/Helpers/GraphService.cs index 355b341..8f6a0a3 100644 --- a/MicrosoftGraphAspNetCoreConnectSample/Helpers/GraphService.cs +++ b/MicrosoftGraphAspNetCoreConnectSample/Helpers/GraphService.cs @@ -40,12 +40,12 @@ public static async Task GetUserJson(GraphServiceClient graphClient, str case "ErrorInvalidUser": return JsonConvert.SerializeObject(new { Message = $"The requested user '{email}' is invalid." }, Formatting.Indented); case "AuthenticationFailure": - return JsonConvert.SerializeObject(new {e.Error.Message}, Formatting.Indented); + return JsonConvert.SerializeObject(new { e.Error.Message }, Formatting.Indented); case "TokenNotFound": await httpContext.ChallengeAsync(); - return JsonConvert.SerializeObject(new {e.Error.Message}, Formatting.Indented); + return JsonConvert.SerializeObject(new { e.Error.Message }, Formatting.Indented); default: - return JsonConvert.SerializeObject(new { Message = "An unknown error has occured." }, Formatting.Indented); + return JsonConvert.SerializeObject(new { Message = "An unknown error has occurred." }, Formatting.Indented); } } } @@ -53,12 +53,10 @@ public static async Task GetUserJson(GraphServiceClient graphClient, str // Load user's profile picture in base64 string. public static async Task GetPictureBase64(GraphServiceClient graphClient, string email, HttpContext httpContext) { - if (email == null) return JsonConvert.SerializeObject(new { Message = "Email address cannot be null." }, Formatting.Indented); - try { // Load user's profile picture. - var pictureStream = await graphClient.Users[email].Photo.Content.Request().GetAsync(); + var pictureStream = await GetPictureStream(graphClient, email, httpContext); // Copy stream to MemoryStream object so that it can be converted to byte array. var pictureMemoryStream = new MemoryStream(); @@ -72,6 +70,49 @@ public static async Task GetPictureBase64(GraphServiceClient graphClient return "data:image/jpeg;base64," + pictureBase64; } + catch (Exception e) + { + switch (e.Message) + { + case "ResourceNotFound": + // If picture not found, return the default image. + return "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz4NCjxzdmcgd2lkdGg9IjQwMXB4IiBoZWlnaHQ9IjQwMXB4IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDMxMi44MDkgMCA0MDEgNDAxIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjMxMi44MDkgMCA0MDEgNDAxIiB4bWw6c3BhY2U9InByZXNlcnZlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KPGcgdHJhbnNmb3JtPSJtYXRyaXgoMS4yMjMgMCAwIDEuMjIzIC00NjcuNSAtODQzLjQ0KSI+DQoJPHJlY3QgeD0iNjAxLjQ1IiB5PSI2NTMuMDciIHdpZHRoPSI0MDEiIGhlaWdodD0iNDAxIiBmaWxsPSIjRTRFNkU3Ii8+DQoJPHBhdGggZD0ibTgwMi4zOCA5MDguMDhjLTg0LjUxNSAwLTE1My41MiA0OC4xODUtMTU3LjM4IDEwOC42MmgzMTQuNzljLTMuODctNjAuNDQtNzIuOS0xMDguNjItMTU3LjQxLTEwOC42MnoiIGZpbGw9IiNBRUI0QjciLz4NCgk8cGF0aCBkPSJtODgxLjM3IDgxOC44NmMwIDQ2Ljc0Ni0zNS4xMDYgODQuNjQxLTc4LjQxIDg0LjY0MXMtNzguNDEtMzcuODk1LTc4LjQxLTg0LjY0MSAzNS4xMDYtODQuNjQxIDc4LjQxLTg0LjY0MWM0My4zMSAwIDc4LjQxIDM3LjkgNzguNDEgODQuNjR6IiBmaWxsPSIjQUVCNEI3Ii8+DQo8L2c+DQo8L3N2Zz4NCg=="; + case "EmailIsNull": + return JsonConvert.SerializeObject(new { Message = "Email address cannot be null." }, Formatting.Indented); + default: + return null; + } + } + } + + public static async Task GetPictureStream(GraphServiceClient graphClient, string email, HttpContext httpContext) + { + if (email == null) throw new Exception("EmailIsNull"); + + Stream pictureStream = null; + + try + { + try + { + // Load user's profile picture. + pictureStream = await graphClient.Users[email].Photo.Content.Request().GetAsync(); + } + catch (ServiceException e) + { + if (e.Error.Code == "GetUserPhoto") // User is using MSA, we need to use beta endpoint + { + // Set Microsoft Graph endpoint to beta, to be able to get profile picture for MSAs + graphClient.BaseUrl = "https://graph.microsoft.com/beta"; + + // Get profile picture from Microsoft Graph + pictureStream = await graphClient.Users[email].Photo.Content.Request().GetAsync(); + + // Reset Microsoft Graph endpoint to v1.0 + graphClient.BaseUrl = "https://graph.microsoft.com/v1.0"; + } + } + } catch (ServiceException e) { switch (e.Error.Code) @@ -82,7 +123,54 @@ public static async Task GetPictureBase64(GraphServiceClient graphClient case "itemNotFound": case "ErrorInvalidUser": // If picture not found, return the default image. - return "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz4NCjxzdmcgd2lkdGg9IjQwMXB4IiBoZWlnaHQ9IjQwMXB4IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDMxMi44MDkgMCA0MDEgNDAxIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjMxMi44MDkgMCA0MDEgNDAxIiB4bWw6c3BhY2U9InByZXNlcnZlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KPGcgdHJhbnNmb3JtPSJtYXRyaXgoMS4yMjMgMCAwIDEuMjIzIC00NjcuNSAtODQzLjQ0KSI+DQoJPHJlY3QgeD0iNjAxLjQ1IiB5PSI2NTMuMDciIHdpZHRoPSI0MDEiIGhlaWdodD0iNDAxIiBmaWxsPSIjRTRFNkU3Ii8+DQoJPHBhdGggZD0ibTgwMi4zOCA5MDguMDhjLTg0LjUxNSAwLTE1My41MiA0OC4xODUtMTU3LjM4IDEwOC42MmgzMTQuNzljLTMuODctNjAuNDQtNzIuOS0xMDguNjItMTU3LjQxLTEwOC42MnoiIGZpbGw9IiNBRUI0QjciLz4NCgk8cGF0aCBkPSJtODgxLjM3IDgxOC44NmMwIDQ2Ljc0Ni0zNS4xMDYgODQuNjQxLTc4LjQxIDg0LjY0MXMtNzguNDEtMzcuODk1LTc4LjQxLTg0LjY0MSAzNS4xMDYtODQuNjQxIDc4LjQxLTg0LjY0MWM0My4zMSAwIDc4LjQxIDM3LjkgNzguNDEgODQuNjR6IiBmaWxsPSIjQUVCNEI3Ii8+DQo8L2c+DQo8L3N2Zz4NCg=="; + throw new Exception("ResourceNotFound"); + case "TokenNotFound": + await httpContext.ChallengeAsync(); + return null; + default: + return null; + } + } + + return pictureStream; + } + public static async Task GetMyPictureStream(GraphServiceClient graphClient, HttpContext httpContext) + { + Stream pictureStream = null; + + try + { + try + { + // Load user's profile picture. + pictureStream = await graphClient.Me.Photo.Content.Request().GetAsync(); + } + catch (ServiceException e) + { + if (e.Error.Code == "GetUserPhoto") // User is using MSA, we need to use beta endpoint + { + // Set Microsoft Graph endpoint to beta, to be able to get profile picture for MSAs + graphClient.BaseUrl = "https://graph.microsoft.com/beta"; + + // Get profile picture from Microsoft Graph + pictureStream = await graphClient.Me.Photo.Content.Request().GetAsync(); + + // Reset Microsoft Graph endpoint to v1.0 + graphClient.BaseUrl = "https://graph.microsoft.com/v1.0"; + } + } + } + catch (ServiceException e) + { + switch (e.Error.Code) + { + case "Request_ResourceNotFound": + case "ResourceNotFound": + case "ErrorItemNotFound": + case "itemNotFound": + case "ErrorInvalidUser": + // If picture not found, return the default image. + throw new Exception("ResourceNotFound"); case "TokenNotFound": await httpContext.ChallengeAsync(); return null; @@ -90,19 +178,21 @@ public static async Task GetPictureBase64(GraphServiceClient graphClient return null; } } + + return pictureStream; } // Send an email message from the current user. public static async Task SendEmail(GraphServiceClient graphClient, IHostingEnvironment hostingEnvironment, string recipients, HttpContext httpContext) { if (recipients == null) return; - + var attachments = new MessageAttachmentsCollectionPage(); try { // Load user's profile picture. - var pictureStream = await graphClient.Me.Photo.Content.Request().GetAsync(); + var pictureStream = await GetMyPictureStream(graphClient, httpContext); // Copy stream to MemoryStream object so that it can be converted to byte array. var pictureMemoryStream = new MemoryStream(); @@ -117,17 +207,11 @@ public static async Task SendEmail(GraphServiceClient graphClient, IHostingEnvir Name = "me.png" }); } - catch (ServiceException e) + catch (Exception e) { - switch (e.Error.Code) + switch (e.Message) { - case "Request_ResourceNotFound": case "ResourceNotFound": - case "ErrorItemNotFound": - case "itemNotFound": - break; - case "TokenNotFound": - await httpContext.ChallengeAsync(); break; default: throw; @@ -135,7 +219,7 @@ public static async Task SendEmail(GraphServiceClient graphClient, IHostingEnvir } // Prepare the recipient list. - var splitRecipientsString = recipients.Split(new[]{ ";" }, StringSplitOptions.RemoveEmptyEntries); + var splitRecipientsString = recipients.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries); var recipientList = splitRecipientsString.Select(recipient => new Recipient { EmailAddress = new EmailAddress