- Part 1 - Introduction to creating a multi-tenant Office 365 add-in using VS2015
- Part 2 - Creating the initial project and add-in registrations in Azure AD
- Part 3 - What did the wizard leave behind?
- Part 4 - Connecting Office 365 services to the project
- Part 5 - Adding code to send e-mails
- Part 6 - Switching to the Office 365 unified API (preview)
- Part 7 - Publishing the App to Azure
- Part 8 - Troubleshooting and tips
Before reading on I’ll tell you that I reverted this route myself as the Unified API client was unable to let me send an e-mail, bombing out with and OData class mapping error. This seems to be a bug on the Microsoft side of things, but if you do pure REST it will work. Using multiple clients is not that much of a hassle when you have the authentication part figured out anyways, and what is a few more server side calls behind the scenes between friends anyway? :-)
Still up for it…. continue reading.
Add a nuget package for the Office 365 unified API (preview)
Open up the nuget package manager, check the Include prerelease box and search for Microsoft.Graph.Click Install to bring down the code.
Add application manifest settings for the Unified API
Once the nuget package is installed the application manifest in AAD has to be updated with settings for the Unified API. This is not yet available via the connected service wizard in Visual Studio, so instead head over to the Azure management portal, pick your AAD, then the application registration and configure it there.Click Add application, pick Office 365 unified API (preview), and configure the delegated permissions to be able to Send mail as signed-in user and Sign in and read user profile. As we’re using OWIN for login it seems you have to keep the Windows Azure Active Directory delegated permissions for login. If not, your application will fail on sign-in.
When a user consents to the application the dual permissions looks a bit weird as allow sign-in and reading the profile appears twice.
Authorization code
Next up is adding the authorization call to StartupAuth.cs for the Unified API endpoint - https://graph.microsoft.com. Replace the two existing ones with:public const string UnifiedResourceId = "https://graph.microsoft.com"; AuthorizationCodeReceived = (context) => { var code = context.Code; ClientCredential credential = new ClientCredential(clientId, appKey); string tenantID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value; string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value; AuthenticationContext authContext = new AuthenticationContext(aadInstance + tenantID, new ADALTokenCache(signedInUserID)); AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, UnifiedResourceId); return Task.FromResult(0); }
Switch out ActiveDirectoryClient and OutlookServicesClient with GraphService
Open up UserInfo.aspx.cs and you can now load the user’s profile with this codevar servicePointUri = new Uri(UnifiedResourceId); var serviceRoot = new Uri(servicePointUri, "/beta/" + tenantID); var unifiedClient = new GraphService(serviceRoot, async () => await TokenHelper.GetTokenForApplicationSilent(TokenHelper.UnifiedResourceId)); IUser user = unifiedClient.Me.ExecuteAsync().Result;
You also need to change the aspx page to the correct type as the IUser interface is different between the Unified API’s classes and the Graph Service classes.
The send email code now looks like this (except it bombs at the time of writing October 2015):
private Task SendEmailTaskUnified() { return Task.Run(async () => { var tenantId = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value; var servicePointUri = new Uri(TokenHelper.UnifiedResourceId); var serviceRoot = new Uri(servicePointUri, "/beta/" + tenantId); var unifiedClient = new GraphService(serviceRoot, async () => await TokenHelper.GetTokenForApplicationSilent(TokenHelper.UnifiedResourceId)); // Load your profile and retrieve e-mail address - could have been cached on initial page load var user = unifiedClient.Me.ExecuteAsync().Result; var body = new Microsoft.Graph.ItemBody { Content = "<h1>YOU DID IT!!</h1>", ContentType = Microsoft.Graph.BodyType.HTML }; var toRecipients = new List<Microsoft.Graph.Recipient> { new Microsoft.Graph.Recipient { EmailAddress = new Microsoft.Graph.EmailAddress {Address = user.mail} } }; var newMessage = new Microsoft.Graph.Message { Subject = "O365 Mail by Mikael", Body = body, ToRecipients = toRecipients, Importance = Microsoft.Graph.Importance.High }; await unifiedClient.Me.SendMailAsync(newMessage, true); }); }
In my case the above code bombs on the last line to send the e-mail. Instead you can keep using the OutlookClient without having to register the resource endpoint in StartupAuth.cs. Seems the authorization token from the Unified API handles this just fine. Or you can copy the SendMessageAsync snippet from https://github.com/OfficeDev/O365-UWP-Unified-API-Snippets/blob/master/O365-UWP-Unified-API-Snippets/Users/UserSnippets.cs which uses the Unified API endpoint with pure REST. This actually works compared to the GraphClient which uses OData. Replace the code to retrieve the token in the snippet with the one you already have and pass it in to the function.
string token = await TokenHelper.GetTokenForApplicationSilent(TokenHelper.UnifiedResourceId); await SendMessageAsync("O365 Mail by Mikael", "<h1>YOU DID IT!!</h1>", user.mail, token);