Office 365 api vs share point app model

  • Published on
    16-Jul-2015

  • View
    394

  • Download
    5

Embed Size (px)

Transcript

<p>Office 365 API vs SharePoint app model#SPSBE02Lieven Iliano, U2UApril 18th, 2015</p> <p>Template may not be modified Twitter hashtag: #spsbe for all sessions1Thanks to our sponsors!PlatinumGoldSilverAgendaIntroducing Office 365 APIDeveloping apps consuming Office 365 APIRegistering Office apps in Azure ADAzure AD Authentication &amp; Authorization.Net Client LibraryOffice 365 apps vs SharePoint appsU2U Site Provisioning</p> <p>Introducing Office 365 APISet of REST services:Microsoft Exchange Online: Mail, Contacts &amp; CalendarsMicrosoft OneDrive for Business: My FilesMicrosoft SharePoint Online: SitesMicrosoft Azure Active Directory: Authentication, Directory GraphOffice 365 API</p> <p>Office 365 API</p> <p>Directly via REST.NET Client Library: Windows apps, ASP.NET, WPF, XamarinJavaScript Client LibraryOpen Source SDK for iOS and Android</p> <p>Choice of client and development</p> <p>How does it work?</p> <p>Applications using Office 365 API need to be registered in Azure Active DirectoryDone manually or from within Visual Studio2 Types of applications can be registered:Web Application (Web API, MVC, Web Forms)Native Client (Mobile, Windows apps, Desktop App)</p> <p>Azure Active DirectoryDemoDiscovering the Office 365 REST APIhttps://msdn.microsoft.com/en-us/office/office365/api/api-cataloghttps://outlook.office365.com/api/v1.0/me/messageshttps://u2u365-my.sharepoint.com/_api/v1.0/me/files10Microsoft SharePoint Server 2013 2012 Microsoft Corporation. All rights reserved. Microsoft, Windows, and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.Developing apps consuming Office 365 APIExtensions and Updates:Microsoft Office 365 API Tools (Part ofOffice Developer Tools)</p> <p>Nuget packages:Office 365 apps in Visual Studio</p> <p>O365 ServiceDesktop App/ Store App/ ASP.NET AppXamarinCordovaUsers and GraphsMicrosoft.Azure.ActiveDirectory.GraphClientMicrosoft.Azure.ActiveDirectory.GraphClient.JSOutlook ServicesMicrosoft.Office365.OutlookServicesSharePoint ServicesMicrosoft.Office365.SharePointDiscovery ClientMicrosoft.Office365.DiscoveryAny ServiceMicrosoft.Office365.OAuth.XamarinMicrosoft.Office365.ClientLib.JSAdd Office 365 API to your projectOffice 365 apps in Visual Studio</p> <p>Configure permissions:</p> <p>Will automatically configure application in AADAdds nuget packages and configuration settings</p> <p>Adds references to project and stores configurationOffice 365 apps in Visual Studio</p> <p>DEMORegistering Office 365 app in Visual StudioMicrosoft.IdentityModel.Clients.ActiveDirectory15Microsoft SharePoint Server 2013 2012 Microsoft Corporation. All rights reserved. Microsoft, Windows, and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.Registering applications in Azure ADYour apps are registered in Azure AD</p> <p>Azure Active Directory</p> <p>Specify the service and permissions</p> <p>Office 365 Exchange Online serviceAccess to Mail, Calendar, ContactsOffice 365 SharePoint Online serviceAccess to Files in SharePoint Online or OneDrive for BusinessAzure Active Directory</p> <p>DEMORegistering Office 365 app in Azure PortalAzure AD Authentication &amp; AuthorizationOAuth 2.0 Authorization Code Grant flowApp uses access token on your behalfOauth 2.0 Client Credentials Grant FlowApp runs with own permissionsOnly supported by contacts, calendar &amp; mailAuthentication and AuthorizationApp redirects user to an AAD authentication endpointAuthentication for Office 365 Apps</p> <p>Your app gets the user's email address. It contacts Discovery Service with email address and the set of scopes the app wants to access.22User authenticates and grants consent </p> <p>Azure AD issues an authorization codeAuthentication for Office 365 Apps</p> <p>The app goes to the Azure AD authorization endpoint and the user authenticates and grants consent (if consent has not been granted before). Azure AD issues an authorization code.23User authenticates and grants consent </p> <p>Authentication for Office 365 Apps</p> <p>App passes authorization code to AAD</p> <p>Azure AD returns access and refresh tokensAuthentication for Office 365 Apps</p> <p>Your app redeems the authorization code. Azure returns an access token and a refresh token.25App uses access/refresh tokens to access Office 365 API </p> <p>Authentication for Office 365 Apps</p> <p>Your app can now call Office 365 APIs using the URI from Discovery Service and the access token. Office 365 returns Http Response.26Authenticate by using Active Directory Authentication Library (ADAL)Discover available App capabilities. Returns only services App has access to.Connect through Outlook/SharePoint Services ClientProgramming with Office 365 APIGet resource endpoints from discovery service</p> <p>Programming with Office 365 APIEnd Point (i.e)Discoveryhttps://api.office.com/discovery/v1.0/meMailContactsCalendarhttps://{server_name}/api/{version}/{user_context}https://outlook.office365.com/api/v1.0/meOneDrive for Businesshttps://{tenant}-my.sharepoint.com/_api/v1.0/meSiteshttps://{tenant}.sharepoint.com/{site-path}/_api/v1.0Discovery client from WebApp// Get user and object ID from claimsvar signInUserId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;var userObjectId = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;</p> <p>// Authority: "https://login.windows.net/"AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.Authority, new ADALTokenCache(signInUserId));</p> <p>// Create Discovery Client// DiscoveryServiceEndpointUri: "https://api.office.com/discovery/v1.0/me/"// DiscoveryServiceResourceId: "https://api.office.com/discovery/"DiscoveryClient discClient = new DiscoveryClient(SettingsHelper.DiscoveryServiceEndpointUri, async () =&gt; { var authResult = await authContext.AcquireTokenSilentAsync( SettingsHelper.DiscoveryServiceResourceId, new ClientCredential(SettingsHelper.ClientId, SettingsHelper.AppKey), new UserIdentifier(userObjectId, UserIdentifierType.UniqueId));</p> <p> return authResult.AccessToken; });</p> <p>Discovery client from Native AppauthenticationContext = new AuthenticationContext("https://login.windows.net/Common/");AuthenticationResult authenticationResult = authenticationContext.AcquireToken("https://graph.windows.net", ClientId, new Uri(RedirectUri));DiscoveryClient discoveryClient = new DiscoveryClient(new Uri("https://api.office.com/discovery/v1.0/me/"), async () =&gt; { return await GetAccessTokenForServiceAsync("https://api.office.com/discovery/"); });</p> <p>private async Task GetAccessTokenForServiceAsync(string serviceResourceId){ AuthenticationResult authResult = await this.authenticationContext.AcquireTokenSilentAsync(serviceResourceId, ClientId); return authResult.AccessToken;}Outlook Services Client// Discover if resource is availableCapabilityDiscoveryResult dcr = await discClient.DiscoverCapabilityAsync(Mail);</p> <p>// Get the OutlookServicesClient: this gives access to mail, contacts, calendarreturn new OutlookServicesClient(dcr.ServiceEndpointUri, async () =&gt; { var authResult = await authContext.AcquireTokenSilentAsync( dcr.ServiceResourceId, new ClientCredential(SettingsHelper.ClientId, SettingsHelper.AppKey), new UserIdentifier(userObjectId, UserIdentifierType.UniqueId));</p> <p> return authResult.AccessToken; });Gives access to Mail, Calendar and ContactsOutlook Services Client</p> <p>Send email// Initialize variablesstring subject = "Mail sent by using Office 365 APIs";string recipients = "lieven@u2u365.onmicrosoft.com;els@u2u365.onmicrosoft.com";string bodyContent = "This email was created from code and was sent using the Office 365 APIs";</p> <p>// Prepare list of recipientsList toRecipients = recipients .Split(new char[]{';'}, StringSplitOptions.RemoveEmptyEntries) .Select( recipient =&gt; new Recipient { EmailAddress = new EmailAddress { Address = recipient, Name = recipient } }) .ToList();</p> <p>// Create draft messageMessage draft = new Message() { Subject = subject, Body = new ItemBody { ContentType = BodyType.Text, Content = bodyContent}, ToRecipients = toRecipients };Send email// Add the message to the draft folder. This results in a call to the service. // Returns full item but unfortunately you dont have access to it.await outlookServicesClient.Me.Folders.GetById("Drafts").Messages.AddMessageAsync(draft);</p> <p>// Gets the full draft message, including the identifier needed to issue a send mail request.// This results in a call to the service. IMessage updatedDraft = await outlookServicesClient.Me.Folders.GetById("Drafts").Messages.GetById(draft.Id).ExecuteAsync();</p> <p>// Issues a send command so that the draft mail is sent to the recipient list.// This results in a call to the service. await outlookServicesClient.Me.Folders.GetById("Drafts").Messages.GetById(updatedDraft.Id).SendAsync();Get contacts</p> <p>Add contact</p> <p>Delete contactContacts// Get paged collection of contactsIPagedCollection contactsPage = await (outlookServicesClient.Me.Contacts.OrderBy(c =&gt; c.FileAs)) .Skip((pageNo - 1) * pageSize).Take(pageSize).ExecuteAsync();// Create contactContact newContact = new Contact();...</p> <p>// This results in a call to the service.await outlookServicesClient.Me.Contacts.AddContactAsync(newContact);// Get the contact to deletevar contactToDelete = await outlookServicesClient.Me.Contacts[contactId].ExecuteAsync();</p> <p>// Delete the contactawait contactToDelete.DeleteAsync();Get events</p> <p>Add event</p> <p>Delete Event</p> <p>Events// Get paged collection of eventsIPagedCollection eventsPage = await (outlookServicesClient.Me.Calendar.Events.Where(e =&gt; e.Start &gt;= DateTimeOffset.Now.AddDays(-30) &amp;&amp; e.Start e.Start)) .Skip((pageNo - 1) * pageSize).Take(pageSize).ExecuteAsync();// Create new event and addEvent newEvent = new Event();await outlookServicesClient.Me.Events.AddEventAsync(newEvent);// Get the event to deleteIEvent eventToDelete = await outlookServicesClient.Me.Calendar.Events[selectedEventId].ExecuteAsync();</p> <p>// Delete the eventawait eventToDelete.DeleteAsync(false);Gives access to Files and OneDriveSharePoint Services Client// Discover if resource is availableCapabilityDiscoveryResult dcr = await discClient.DiscoverCapabilityAsync(MyFiles);</p> <p>// Get the SharePointClient: this gives access to OneDrive and Filesreturn new SharePointClient(dcr.ServiceEndpointUri, async () =&gt; { var authResult = await authContext.AcquireTokenSilentAsync( dcr.ServiceResourceId, new ClientCredential(SettingsHelper.ClientId, SettingsHelper.AppKey), new UserIdentifier(userObjectId, UserIdentifierType.UniqueId));</p> <p> return authResult.AccessToken; });Get files// Do paging when fetching int pageNo = 1;int pageSize = 25;</p> <p>// Get the SharePoint clientSharePointClient sharePointClient = await AuthenticationHelper.EnsureSharePointClientCreatedAsync("MyFiles");</p> <p>// Get the files (and folders)IPagedCollection filesPage = await (sharePointClient.Files.Where(i =&gt; i.Type == "File")) .Skip((pageNo - 1) * pageSize).Take(pageSize).ExecuteAsync();</p> <p>// Get current pageIReadOnlyList fileItems = filesPage.CurrentPage;</p> <p>// Cast to file objectsIEnumerable files = fileItems.Cast();Add file// Filename + SharePoint Clientstring filename = "sample.txt";var spClient = await AuthenticationHelper.EnsureSharePointClientCreatedAsync("MyFiles");</p> <p>// Check if the file exists, delete it if it doestry{ IItem item = await spClient.Files.GetByPathAsync(filename); await item.DeleteAsync();}catch (ODataErrorException){ // fail silently because it doesn't exist.}</p> <p>// In this example, we'll create a simple text file and write the current timestamp into it. string createdTime = "Created at " + DateTime.Now.ToLocalTime().ToString();byte[] bytes = Encoding.UTF8.GetBytes(createdTime);</p> <p>using (MemoryStream stream = new MemoryStream(bytes)){ // If file already exists, we'll get an exception. File newFile = new File { Name = filename }; // Create the empty file. await spClient.Files.AddItemAsync(newFile); // Upload the file contents. await spClient.Files.GetById(newFile.Id).ToFile().UploadAsync(stream);}DEMOOffice 365 API .NET Client LibraryType of application</p> <p>Office 365 apps vs SharePoint apps</p> <p>Office 365 appsSharePoint appsExternal/standalone app</p> <p>Integrated in SharePointAccessibility</p> <p>Office 365 apps vs SharePoint apps</p> <p>Office 365 appsSharePoint appsFrom any link From the Office 365 App Launcher From the Office 365 My apps page </p> <p>from a SharePoint/SharePoint Online siteRegistration</p> <p>Office 365 apps vs SharePoint appsOffice 365 appsSharePoint appsRegistration in Azure AD</p> <p>Registration in _layouts/15/appregnew.aspx</p> <p>Deployment</p> <p>Office 365 apps vs SharePoint appsOffice 365 appsSharePoint appsDeployed once to the hosting platformMobile/Web/Desktop*.app package deployed to app catalog and installed in various SharePoint sitesAccessing CSOM from Office 365 appAccessing CSOM from Office 365 appprivate static async Task GetAccessToken(string resource){ // Redeem the authorization code from the response for an access token and refresh token. var principal = ClaimsPrincipal.Current;</p> <p> var nameIdentifier = principal.FindFirst(ClaimTypes.NameIdentifier).Value; var tenantId = principal.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;</p> <p> AuthenticationContext authContext = new AuthenticationContext( string.Format("{0}/{1}", SettingsHelper.AuthorizationUri, tenantId), new ADALTokenCache(nameIdentifier));</p> <p> var objectId = principal.FindFirst("http://schemas.microsoft.com/ide...</p>