├── Day29-OneDrive ├── Images │ ├── aad-create-app-05.png │ └── aad-grant-permissions-Files.png ├── FileUploadSample │ ├── Assets │ │ ├── StoreLogo.png │ │ ├── SplashScreen.scale-200.png │ │ ├── LockScreenLogo.scale-200.png │ │ ├── Square44x44Logo.scale-200.png │ │ ├── Wide310x150Logo.scale-200.png │ │ ├── Square150x150Logo.scale-200.png │ │ └── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── App.xaml │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ └── Default.rd.xml │ ├── MainPage.xaml │ ├── Package.appxmanifest │ ├── App.xaml.cs │ ├── FileUploadSample.csproj │ └── MainPage.xaml.cs ├── FileUploadSample.sln └── README.md ├── Day13-Postman.md ├── Day27-Teams.md ├── Day01-WhyMSGraph.md ├── Day02-OverviewMSGraph.md ├── Day29-OneDrive.md ├── Day28-Webhooks.md ├── Day10-AzureADAppV1.md ├── Day09-AzureADAppV2.md ├── Day23-SPAPart1.md ├── Day11-AppPermissions.md ├── Day17-AssignLicense.md ├── Day26-GraphAndFlow.md ├── Day25-OneNote.md ├── Day16-CreateUser.md ├── Day18-Mailbox.md ├── Day20-DeviceCode.md ├── Day21-Planner.md ├── Day19-O365GroupsPerm.md ├── Day15-DotnetCoreSample.md ├── Day05-QueryParamPt1.md ├── Day30-Conclusion.md ├── Day04-RequestSyntax.md ├── Day06-QueryParamPt2.md ├── Day24-SPAPart2.md ├── LICENSE ├── README.md ├── Day22-Intune.md ├── Day14-BatchProcessing.md ├── Day03-GraphExplorer.md ├── Day07-PagingNextLink.md ├── Day12-AuthScenarios.md ├── Day08-AccessTokens.md └── .gitignore /Day29-OneDrive/Images/aad-create-app-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/30DaysMSGraph-TryItOut/master/Day29-OneDrive/Images/aad-create-app-05.png -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/30DaysMSGraph-TryItOut/master/Day29-OneDrive/FileUploadSample/Assets/StoreLogo.png -------------------------------------------------------------------------------- /Day29-OneDrive/Images/aad-grant-permissions-Files.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/30DaysMSGraph-TryItOut/master/Day29-OneDrive/Images/aad-grant-permissions-Files.png -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/30DaysMSGraph-TryItOut/master/Day29-OneDrive/FileUploadSample/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/30DaysMSGraph-TryItOut/master/Day29-OneDrive/FileUploadSample/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/30DaysMSGraph-TryItOut/master/Day29-OneDrive/FileUploadSample/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/30DaysMSGraph-TryItOut/master/Day29-OneDrive/FileUploadSample/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/30DaysMSGraph-TryItOut/master/Day29-OneDrive/FileUploadSample/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoftgraph/30DaysMSGraph-TryItOut/master/Day29-OneDrive/FileUploadSample/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Day13-Postman.md: -------------------------------------------------------------------------------- 1 | # [Day 13 - Postman to make Microsoft Graph requests](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-13-postman-to-make-microsoft-graph-calls) 2 | 3 | Using Postman try below Microsoft Graph API calls: 4 | 5 | 1. Use Paging and NextLink discussed on Day 7 to get all users. 6 | 1. Use filter query parameters to filter the users by JobTitle. -------------------------------------------------------------------------------- /Day27-Teams.md: -------------------------------------------------------------------------------- 1 | # [Day 27 - Use case: Create a Team](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-27-use-case-create-a-team) 2 | 3 | 1. Navigate to the [contoso-airlines-teams-sample repo](https://github.com/microsoftgraph/contoso-airlines-teams-sample). 4 | 1. Check out the [Teams overview](https://aka.ms/teamsgraph/v1) for more details on the Teams APIs in Microsoft Graph. 5 | 1. Watch the [video](https://aka.ms/teamsgraph/v1/video). -------------------------------------------------------------------------------- /Day01-WhyMSGraph.md: -------------------------------------------------------------------------------- 1 | # [Day 1 - Why you should learn Microsoft Graph](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-1-why-you-should-learn-the-microsoft-graph) 2 | 3 | 1. What's new on Microsoft Graph (BUILD 2018): [https://channel9.msdn.com/events/Build/2018/THR5011](https://channel9.msdn.com/events/Build/2018/THR5011) 4 | 5 | 2. Microsoft Graph (BUILD 2019): [https://www.youtube.com/watch?v=XgkcCOvURaY](https://www.youtube.com/watch?v=XgkcCOvURaY) 6 | -------------------------------------------------------------------------------- /Day02-OverviewMSGraph.md: -------------------------------------------------------------------------------- 1 | # [Day 2 - Overview Microsoft Graph](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-2-overview-microsoft-graph) 2 | 3 | 1. Microsoft Graph documentation: [https://developer.microsoft.com/en-us/graph](https://developer.microsoft.com/en-us/graph) 4 | - Also available at the short link [https://aka.ms/graph](https://aka.ms/graph) 5 | 1. Microsoft Graph blog: [https://developer.microsoft.com/en-us/graph/blogs](https://developer.microsoft.com/en-us/graph/blogs) -------------------------------------------------------------------------------- /Day29-OneDrive.md: -------------------------------------------------------------------------------- 1 | # [Day 29 - Use case: Upload files to OneDrive](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-29-use-case-upload-files-to-onedrive) 2 | 3 | Navigate to the [30DaysMSGraph-TryItOut](https://github.com/microsoftgraph/30DaysMSGraph-TryItOut) repo. Clone the repo and configure the project in the Day 29 sub-folder using steps from the README or this post. 4 | 5 | If you run into any issues while building or configuring the project, please create a new Issue on the repo. -------------------------------------------------------------------------------- /Day28-Webhooks.md: -------------------------------------------------------------------------------- 1 | # [Day 28 - Use case: Webhooks](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-28-use-case-webhooks) 2 | 3 | Navigate to the [dotnetcore-console-sample](https://github.com/microsoftgraph/dotnetcore-console-sample) repo. Clone the repo and configure the project in the Day 28 sub-folder. 4 | 5 | 1. Follow the instructions in Day 28 sub-folder to build the project from scratch yourself. 6 | 7 | If you run into any issues while building or configuring the project, please create a new Issue on the repo. -------------------------------------------------------------------------------- /Day10-AzureADAppV1.md: -------------------------------------------------------------------------------- 1 | # [Day 10 - Azure AD application on V1 endpoint](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-10-azure-ad-applications-on-v1-endpoint) 2 | 3 | Navigate to the Azure AD Portal.  Walk through these steps to create an app, assign it permissions, and grant admin consent. 4 | 5 | 1. Create a new Azure AD application. 6 | 1. Assign the delegated permission for Read user mail. 7 | 1. Assign the delegated permission for Read user calendars. 8 | 1. Assign the application permission for Read directory data. 9 | 1. Grant admin consent to the application. -------------------------------------------------------------------------------- /Day09-AzureADAppV2.md: -------------------------------------------------------------------------------- 1 | # [Day 9 - Azure AD application on V2 endpoint](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-9-azure-ad-applications-on-v2-endpoint) 2 | 3 | Navigate to the [App registrations (Preview)](https://aka.ms/AppRegistrationsPreview).  Walk through these steps to create an app, assign it permissions, and grant admin consent. 4 | 5 | 1. Create a new Azure AD application. 6 | 1. Assign the delegated permission for Mail.Read. 7 | 1. Assign the delegated permission for Calendars.ReadWrite. 8 | 1. Assign the application permission for User.Invite.All. 9 | 1. Grant admin consent to the application. -------------------------------------------------------------------------------- /Day23-SPAPart1.md: -------------------------------------------------------------------------------- 1 | # [Day 23 - Use case: Calling Microsoft Graph from a single-page application Part 1](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-23-use-case-calling-microsoft-graph-from-a-single-page-application-part-1/) 2 | 3 | Navigate to [today's post](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-23-use-case-calling-microsoft-graph-from-a-single-page-application-part-1/). 4 | 5 | 1. Follow the instructions to update (or create new) the Azure AD V1 and V2 applications to support implicit authentication. 6 | 1. Use Postman to obtain an access token for the updated (newly created) Azure AD V1 and V2 applications. -------------------------------------------------------------------------------- /Day11-AppPermissions.md: -------------------------------------------------------------------------------- 1 | # [Day 11 - Azure AD application permissions](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-11-azure-ad-application-permissions) 2 | 3 | Navigate to the [Microsoft Graph API reference](https://developer.microsoft.com/en-us/graph/docs/concepts/v1-overview). 4 | 5 | 1. Find 1 or more operations that you would like to complete and identify the permissions required for those operations. 6 | - Ex. Users – [Create User](https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/user_post_users) 7 | - Ex. Mail - [List Messages](https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/user_list_messages) -------------------------------------------------------------------------------- /Day17-AssignLicense.md: -------------------------------------------------------------------------------- 1 | # [Day 17 - Use Case: Assign License](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-17-use-case-assign-license) 2 | 3 | Navigate to the [dotnetcore-console-sample](https://github.com/microsoftgraph/dotnetcore-console-sample) repo.  Do one (or both) of the following: 4 | 5 | 1. Clone the repo and configure the project in the Day 17 sub-folder. 6 | 1. Follow the instructions in [Day 17 sub-folder](https://github.com/microsoftgraph/dotnetcore-console-sample/tree/master/day17-assign-license) to build the project from scratch yourself. 7 | 8 | If you run into any issues while building or configuring the project please create a new Issue on the repo. -------------------------------------------------------------------------------- /Day26-GraphAndFlow.md: -------------------------------------------------------------------------------- 1 | # [Day 26 - Use case: Calling Microsoft Graph using Flow](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-26-use-case-calling-microsoft-graph-using-flow/) 2 | 3 | Create your own Microsoft Flow using Microsoft Graph. Then do one of the following: 4 | 5 | 1. Create Azure AD app registration (refer to [Day 9](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-9-azure-ad-applications-on-v2-endpoint) or [Day 10](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-10-azure-ad-applications-on-v1-endpoint) posts for more information) 6 | 1. Create the Flow using the above sample or download the flow package and update that. -------------------------------------------------------------------------------- /Day25-OneNote.md: -------------------------------------------------------------------------------- 1 | # [Day 25 - Use case: Create a OneNote notebook](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-25-use-case-create-a-onenote-notebook) 2 | 3 | Navigate to the [dotnetcore-console-sample](https://github.com/microsoftgraph/dotnetcore-console-sample) repo.  Do one (or both) of the following: 4 | 5 | 1. Clone the repo and configure the project in the Day 25 sub-folder. 6 | 1. Follow the instructions in [Day 25 sub-folder](https://github.com/microsoftgraph/dotnetcore-console-sample/tree/master/day25-onenote) to build the project from scratch yourself. 7 | 8 | If you run into any issues while building or configuring the project please create a new Issue on the repo. -------------------------------------------------------------------------------- /Day16-CreateUser.md: -------------------------------------------------------------------------------- 1 | # [Day 16 - Use Case: Create user in Azure AD](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-16-use-case-create-user-in-azure-ad) 2 | 3 | Navigate to the [dotnetcore-console-sample](https://github.com/microsoftgraph/dotnetcore-console-sample) repo.  Do one (or both) of the following: 4 | 5 | 1. Clone the repo and configure the project in the Day 16 subfolder. 6 | 1. Follow the instructions in [Day 16 subfolder](https://github.com/microsoftgraph/dotnetcore-console-sample/tree/master/day16-create-user) to build the project from scratch yourself. 7 | 8 | If you run into any issues while building or configuring the project please create a new Issue on the repo. -------------------------------------------------------------------------------- /Day18-Mailbox.md: -------------------------------------------------------------------------------- 1 | # [Day 18 - Use Case: Update Exchange Online mailbox](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-18-use-case-update-user-mailbox-settings/) 2 | 3 | Navigate to the [dotnetcore-console-sample](https://github.com/microsoftgraph/dotnetcore-console-sample) repo.  Do one (or both) of the following: 4 | 5 | 1. Clone the repo and configure the project in the Day 18 sub-folder. 6 | 1. Follow the instructions in [Day 18 sub-folder](https://github.com/microsoftgraph/dotnetcore-console-sample/tree/master/day18-mailbox) to build the project from scratch yourself. 7 | 8 | If you run into any issues while building or configuring the project please create a new Issue on the repo. -------------------------------------------------------------------------------- /Day20-DeviceCode.md: -------------------------------------------------------------------------------- 1 | # [Day 20 - Use case: Device Code flow to authenticate users](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-20-use-case-device-code-flow-to-authenticate-users) 2 | 3 | Navigate to the [dotnetcore-console-sample](https://github.com/microsoftgraph/dotnetcore-console-sample) repo.  Do one (or both) of the following: 4 | 5 | 1. Clone the repo and configure the project in the Day 20 sub-folder. 6 | 1. Follow the instructions in [Day 20 sub-folder](https://github.com/microsoftgraph/dotnetcore-console-sample/tree/master/day20-devicecode) to build the project from scratch yourself. 7 | 8 | If you run into any issues while building or configuring the project please create a new Issue on the repo. -------------------------------------------------------------------------------- /Day21-Planner.md: -------------------------------------------------------------------------------- 1 | # [Day 21 - Use case: Create plans, buckets, and tasks in Planner](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-21-use-case-create-plans-buckets-and-tasks-in-planner) 2 | 3 | Navigate to the [dotnetcore-console-sample](https://github.com/microsoftgraph/dotnetcore-console-sample) repo.  Do one (or both) of the following: 4 | 5 | 1. Clone the repo and configure the project in the Day 21 sub-folder. 6 | 1. Follow the instructions in [Day 21 sub-folder](https://github.com/microsoftgraph/dotnetcore-console-sample/tree/master/day21-planner) to build the project from scratch yourself. 7 | 8 | If you run into any issues while building or configuring the project please create a new Issue on the repo. -------------------------------------------------------------------------------- /Day19-O365GroupsPerm.md: -------------------------------------------------------------------------------- 1 | # [Day 19 - Use Case: Assign Permissions using Unified Groups](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-19-use-case-assign-permissions-using-unified-groups/) 2 | 3 | Navigate to the [dotnetcore-console-sample](https://github.com/microsoftgraph/dotnetcore-console-sample) repo.  Do one (or both) of the following: 4 | 5 | 1. Clone the repo and configure the project in the Day 19 sub-folder. 6 | 1. Follow the instructions in [Day 19 sub-folder](https://github.com/microsoftgraph/dotnetcore-console-sample/tree/master/day19-assign-permissions) to build the project from scratch yourself. 7 | 8 | If you run into any issues while building or configuring the project please create a new Issue on the repo. -------------------------------------------------------------------------------- /Day15-DotnetCoreSample.md: -------------------------------------------------------------------------------- 1 | # [Day 15 - Microsoft Graph in .Net Core application](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-15-microsoft-graph-in-dotnet-core-application) 2 | 3 | Create your own Azure AD application from the instructions in [Day 15](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-15-microsoft-graph-in-dotnet-core-application) blog post. Then do one (or both if you are ambitious) of the following: 4 | 5 | 1. Build out the sample project from a blank .Net Core console application to use your Azure AD app registration. 6 | 1. Clone the [.Net Core console sample](https://github.com/microsoftgraph/dotnetcore-console-sample) from Microsoft Graph repo and configure it to use your Azure AD app registration. -------------------------------------------------------------------------------- /Day05-QueryParamPt1.md: -------------------------------------------------------------------------------- 1 | # [Day 5 - Query Parameters Part 1](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-5-query-parameters-part-1) 2 | 3 | Use the query parameters covered today to filter, sort, and specify columns.  Navigate to the [Graph Explorer](https://aka.ms/ge).  Execute the following commands. 4 | 5 | 1. Get logged in user's high priority emails. 6 | - https://graph.microsoft.com/v1.0/me/messages?$filter=importance eq 'High' 7 | 1. Get name, size, and webUrl of logged in user's OneDrive site files. 8 | - https://graph.microsoft.com/v1.0/me/drive/root/children?$select=name,size,webUrl 9 | 1. Get logged in user's contacts sorted by birthday. 10 | - https://graph.microsoft.com/v1.0/me/contacts?$orderby=birthday 11 | -------------------------------------------------------------------------------- /Day30-Conclusion.md: -------------------------------------------------------------------------------- 1 | # [Day 30 - Community resources and next steps](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-30-community-resources-and-next-steps) 2 | 3 | You may or may not know this but this project was almost entirely a labor of love and not the primary day job for many of our planners or contributors.  This series wouldn't have been possible without all the planners, content contributors, and you as readers.  A huge thank you to all for helping make this project a reality.  As we reflect on lessons learned, what went well, and what we can improve on for future projects we especially appreciate your feedback.  Please take a few minutes to share your feedback and suggestions on anything and everything related to this series as it helps make future projects like this possible. 4 | 5 | **30 Days of Microsoft Graph feedback and suggestions survey** 6 | [https://aka.ms/30DaysMSGraph-Survey](https://aka.ms/30DaysMSGraph-Survey) -------------------------------------------------------------------------------- /Day04-RequestSyntax.md: -------------------------------------------------------------------------------- 1 | # [Day 4 - Request syntax](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-4-request-syntax) 2 | 3 | Explore additional resources related to the Me (logged in user) entity and also add query parameters to filter the base query.  Navigate to the [Graph Explorer](https://aka.ms/ge) then execute the following commands: 4 | 5 | 1. Get logged in user's OneDrive site 6 | - [https://graph.microsoft.com/v1.0/me/drive](https://graph.microsoft.com/v1.0/me/drive) 7 | 1. Get users whose email address starts with "Adele" 8 | - [https://graph.microsoft.com/v1.0/users?\$filter=startswith(mail,'adele')](https://graph.microsoft.com/v1.0/users?$filter=startswith(mail,'adele')) 9 | 1. Get logged in user's user profile picture 10 | - [https://graph.microsoft.com/v1.0/me/photo/\$value](https://graph.microsoft.com/v1.0/me/photo/$value) 11 | 1. (Choose a new sample query by clicking show more samples from the left hand menu) -------------------------------------------------------------------------------- /Day06-QueryParamPt2.md: -------------------------------------------------------------------------------- 1 | # [Day 6 - Query Parameters Part 2](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-6-query-parameters-part-2) 2 | 3 | Use query parameters we covered today to count, search, expand, and restrict results.  Navigate to the [Graph Explorer](https://aka.ms/ge).  Execute the following commands. 4 | 5 | 1. Get number of contacts for the logged in user 6 | - https://graph.microsoft.com/v1.0/me/contacts?$count=true 7 | 1. Get the logged in user's OneNote notebooks, 2 per page 8 | - https://graph.microsoft.com/v1.0/me/onenote/notebooks?$top=2 9 | 1. Get the logged in user's emails starting with the 11th email 10 | - https://graph.microsoft.com/v1.0/me/messages?$skip=10 11 | 1. Get the logged in user's emails that contain the word "Contoso" in the message body 12 | - https://graph.microsoft.com/v1.0/me/messages?$search="body:Contoso" 13 | 1. Get expanded information for logged in user's manager 14 | - https://graph.microsoft.com/beta/me?$expand=manager 15 | -------------------------------------------------------------------------------- /Day24-SPAPart2.md: -------------------------------------------------------------------------------- 1 | # [Day 24 - Use case: Calling Microsoft Graph from a single-page application Part 2](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-24-use-case-calling-microsoft-graph-from-a-single-page-application-part-2/) 2 | 3 | Navigate to [today's post](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-24-use-case-calling-microsoft-graph-from-a-single-page-application-part-2/). 4 | 5 | 1. Complete the pre-requisites in [Day 23](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-23-use-case-calling-microsoft-graph-from-a-single-page-application-part-1/) to prepare an Azure AD app for V1 and V2. 6 | 1. Download or clone Bob German's [AADSamples repo](https://github.com/BobGerman/AADsamples) and navigate to the [implicitFlow sub-folder](https://github.com/BobGerman/AADsamples/tree/master/implicitFlow). 7 | 1. Follow the instructions in either Day 24 or the [README](https://github.com/BobGerman/AADsamples/blob/master/implicitFlow/readme.md) in repo (the latter will also contain Day 23's instructions, so skip to the [Sample Applications](https://github.com/BobGerman/AADsamples/tree/master/implicitFlow#sample-applications) section). -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("FileUploadSample")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("FileUploadSample")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 30 Days of Microsoft Graph - Try It Out 2 | 3 | The files in this repo correspond to the daily 4 | Try It Out exercises from the [30 Days of Microsoft Graph](https://aka.ms/30DaysMSGraph) blog series. Each day has a corresponding Markdown file consisting of resource links, hands-on exercises, or sample projects. 5 | 6 | ## Contributing 7 | 8 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 9 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 10 | the rights to use your contribution. For details, visit https://cla.microsoft.com. 11 | 12 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide 13 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions 14 | provided by the bot. You will only need to do this once across all repos using our CLA. 15 | 16 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 17 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 18 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 19 | -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Day22-Intune.md: -------------------------------------------------------------------------------- 1 | # [Day 22 - Use case: Device and App Management with Intune](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-22-device-and-app-management-with-intune) 2 | 3 | Navigate to the [dotnetcore-console-sample](https://github.com/microsoftgraph/dotnetcore-console-sample) repo.  Do one (or both) of the following: 4 | 5 | 1. Sign up for a free Intune trial at [https://docs.microsoft.com/en-us/intune/get-started-evaluation](https://docs.microsoft.com/en-us/intune/get-started-evaluation). 6 | 1. Clone the dotnetcore-console-sample repo and configure the project in the [Day 22 sub-folder](https://github.com/microsoftgraph/dotnetcore-console-sample/tree/master/day22-intune). 7 | 1. Follow the instructions in readme.md to add Intune functionality to the sample program. (This exercise requires delegated permissions so be sure to include device code authentication from [Day 20](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-20-use-case-device-code-flow-to-authenticate-users) if building from scratch). 8 | 1. Check out [https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/resources/intune_graph_overview](https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/resources/intune_graph_overview) for more details on the Intune APIs in Microsoft Graph. 9 | 10 | If you run into any issues while building or configuring the project please create a new Issue on the repo. -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/MainPage.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | Upload to SharePoint? 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Day14-BatchProcessing.md: -------------------------------------------------------------------------------- 1 | # [Day 14 - Batch processing](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-14-batch-processing) 2 | 3 | 1. Create a batch request to get user profile picture, list of direct reports, list of calendar reminders for today. 4 | 5 | ```json 6 | { 7 | "requests": [ 8 | { 9 | "id": "1", 10 | "method": "GET", 11 | "url": "/me/photo/$value" 12 | }, 13 | { 14 | "id": "2", 15 | "method": "GET", 16 | "url": "/me/directReports" 17 | }, 18 | { 19 | "id": "3", 20 | "method": "GET", 21 | "url": "/me/reminderView(startDateTime='2018-11-134T08:00:00.0000000', endDateTime='2018-11-134T17:00:00.0000000')", 22 | "headers": { 23 | "Content-Type": "application/json" 24 | } 25 | } 26 | ] 27 | } 28 | ``` 29 | 30 | 1. Assuming you got a list of your direct reports, now you can build another batch request to check track their out of office settings. Below is a sample batch request. Be sure to replace \, etc. with the actual user UPN values returned from above query Ex. john@contoso.com. 31 | 32 | ```json 33 | { 34 | "requests": [ 35 | { 36 | "id": "1", 37 | "method": "GET", 38 | "url": "/users/john@contoso.com/mailboxSettings/automaticRepliesSetting" 39 | }, 40 | { 41 | "id": "2", 42 | "method": "GET", 43 | "url": "/users/katie@contoso.com/mailboxSettings/automaticRepliesSetting" 44 | }, 45 | … 46 | … 47 | ] 48 | } 49 | ``` -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/Package.appxmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | FileUploadSample 18 | jeremyke 19 | Assets\StoreLogo.png 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Day03-GraphExplorer.md: -------------------------------------------------------------------------------- 1 | # [Day 3 - Graph Explorer](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-3-graph-explorer) 2 | 3 | Navigate to the [Graph Explorer](https://aka.ms/ge). Try the following calls to the Microsoft Graph using the demo tenant or logging into your own tenant. 4 | 5 | 1. Get logged in user - https://graph.microsoft.com/v1.0/me 6 | 7 | Sample response: 8 | 9 | ```json 10 | { 11 | "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity", 12 | "id": "48d31887-5fad-4d73-a9f5-3c356e68a038", 13 | "businessPhones": [ 14 | "+1 412 555 0109" 15 | ], 16 | "displayName": "Megan Bowen", 17 | "givenName": "Megan", 18 | "jobTitle": "Auditor", 19 | "mail": "MeganB@M365x214355.onmicrosoft.com", 20 | "mobilePhone": null, 21 | "officeLocation": "12/1110", 22 | "preferredLanguage": "en-US", 23 | "surname": "Bowen", 24 | "userPrincipalName": "MeganB@M365x214355.onmicrosoft.com" 25 | } 26 | ``` 27 | 28 | 1. Get logged in user's manager - https://graph.microsoft.com/v1.0/me/manager 29 | 30 | Sample response: 31 | 32 | ```json 33 | { 34 | "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#directoryObjects/$entity", 35 | "@odata.type": "#microsoft.graph.user", 36 | "id": "24fcbca3-c3e2-48bf-9ffc-c7f81b81483d", 37 | "businessPhones": [ 38 | "+1 205 555 0108" 39 | ], 40 | "displayName": "Diego Siciliani", 41 | "givenName": "Diego", 42 | "jobTitle": "CVP Finance", 43 | "mail": "DiegoS@M365x214355.onmicrosoft.com", 44 | "mobilePhone": null, 45 | "officeLocation": "14/1108", 46 | "preferredLanguage": "en-US", 47 | "surname": "Siciliani", 48 | "userPrincipalName": "DiegoS@M365x214355.onmicrosoft.com" 49 | } 50 | ``` -------------------------------------------------------------------------------- /Day07-PagingNextLink.md: -------------------------------------------------------------------------------- 1 | # [Day 7 - Paging and NextLink](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-7-paging-and-nextlink) 2 | 3 | Navigate to the [Graph Explorer](https://aka.ms/ge). Execute the following commands. 4 | 5 | 1. Get the users from your organization’s directory 6 | - https://graph.microsoft.com/v1.0/users?$top=10 7 | 1. Get all the items in your OneDrive for Business 8 | - https://graph.microsoft.com/v1.0/me/drive/root/children?$top=5 9 | 1. Get all the items from a SharePoint Online Site list 10 | - https://graph.microsoft.com/v1.0/sites/m365x214355.sharepoint.com:/sites/HR:/lists/ed70c81d-fedf-4a1b-a1f1-f44e39c5bb78/items?$top=5000 11 | - See appendix for details on how to build this Microsoft Graph query for SharePoint 12 | 13 | ## Appendix 14 | 15 | How to get SharePoint List Items using Microsoft Graph 16 | 17 | 1. If you are not logged into the Graph Explorer (i.e. using a demo tenant) find out the name of the tenant. Issue the following Microsoft Graph query: 18 | - https://graph.microsoft.com/v1.0/sites/root 19 | - Copy the **hostname** value from siteCollection entity, ex. "m365x214355.sharepoint.com" 20 | 1. Next you must use the site collection relative URL and find out the **id** of a list on that site. Issue below Microsoft Graph query to get those details: 21 | - https://graph.microsoft.com/v1.0/sites/:/\:/lists 22 | - Ex. https://graph.microsoft.com/v1.0/sites/m365x214355.sharepoint.com:/sites/HR:/lists 23 | - Copy the **{id}** value from the first list record shown. 24 | - Ex. "id": "ed70c81d-fedf-4a1b-a1f1-f44e39c5bb78" 25 | 1. Next create Microsoft Graph query to fetch the top 5000 items (max that SharePoint can return in one page) from the list 26 | - https://graph.microsoft.com/v1.0/sites/:/\:/lists//items?$top=5000 27 | - Ex. https://graph.microsoft.com/v1.0/sites/m365x214355.sharepoint.com:/sites/HR:/lists/ed70c81d-fedf-4a1b-a1f1-f44e39c5bb78/items?$top=5000 28 | -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2042 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileUploadSample", "FileUploadSample\FileUploadSample.csproj", "{051BC360-AF62-4600-8AED-32172F4480A3}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|x64 = Debug|x64 12 | Debug|x86 = Debug|x86 13 | Release|ARM = Release|ARM 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {051BC360-AF62-4600-8AED-32172F4480A3}.Debug|ARM.ActiveCfg = Debug|ARM 19 | {051BC360-AF62-4600-8AED-32172F4480A3}.Debug|ARM.Build.0 = Debug|ARM 20 | {051BC360-AF62-4600-8AED-32172F4480A3}.Debug|ARM.Deploy.0 = Debug|ARM 21 | {051BC360-AF62-4600-8AED-32172F4480A3}.Debug|x64.ActiveCfg = Debug|x64 22 | {051BC360-AF62-4600-8AED-32172F4480A3}.Debug|x64.Build.0 = Debug|x64 23 | {051BC360-AF62-4600-8AED-32172F4480A3}.Debug|x64.Deploy.0 = Debug|x64 24 | {051BC360-AF62-4600-8AED-32172F4480A3}.Debug|x86.ActiveCfg = Debug|x86 25 | {051BC360-AF62-4600-8AED-32172F4480A3}.Debug|x86.Build.0 = Debug|x86 26 | {051BC360-AF62-4600-8AED-32172F4480A3}.Debug|x86.Deploy.0 = Debug|x86 27 | {051BC360-AF62-4600-8AED-32172F4480A3}.Release|ARM.ActiveCfg = Release|ARM 28 | {051BC360-AF62-4600-8AED-32172F4480A3}.Release|ARM.Build.0 = Release|ARM 29 | {051BC360-AF62-4600-8AED-32172F4480A3}.Release|ARM.Deploy.0 = Release|ARM 30 | {051BC360-AF62-4600-8AED-32172F4480A3}.Release|x64.ActiveCfg = Release|x64 31 | {051BC360-AF62-4600-8AED-32172F4480A3}.Release|x64.Build.0 = Release|x64 32 | {051BC360-AF62-4600-8AED-32172F4480A3}.Release|x64.Deploy.0 = Release|x64 33 | {051BC360-AF62-4600-8AED-32172F4480A3}.Release|x86.ActiveCfg = Release|x86 34 | {051BC360-AF62-4600-8AED-32172F4480A3}.Release|x86.Build.0 = Release|x86 35 | {051BC360-AF62-4600-8AED-32172F4480A3}.Release|x86.Deploy.0 = Release|x86 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {A5031674-7518-47EE-9373-CEC8ACA4F724} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /Day12-AuthScenarios.md: -------------------------------------------------------------------------------- 1 | # [Day 12 - Authentication and authorization scenarios](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-12-authentication-and-authorization-scenarios) 2 | 3 | You can try the authorization code grant flow out using your browser and [Postman](https://www.getpostman.com/apps).  If you are not familiar with Postman or similar REST endpoint development tools feel free to revisit these exercises after you've gone through tomorrow's post for Day 13. 4 | 5 | 1. Register an Azure AD V2 app following the directions from Day 9. 6 | - Ensure that the redirect URI is https://localhost:8080 to match the below steps. 7 | 1. Open Postman and create a new POST request to https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/token, replacing ‘YOUR_TENANT_ID’ with your tenant ID from your app registration. 8 | 1. Configure the Body tab as follows: 9 | - Choose ‘x-www-form-urlencoded’ 10 | - Add a ‘client_id’ key and put your application ID from your app registration in the value 11 | - Add a ‘client_secret’ key and put your application secret from your app registration in the value 12 | - Add a ‘redirect_uri’ key and put ‘https://localhost:8080’ in the value 13 | - Add a ‘grant_type’ key and put ‘authorization_code’ in the value. 14 | - Add a ‘scope’ key and put ‘openid profile offline_access User.Read’ in the value. 15 | - Add a ‘code’ key and leave the value blank. 16 | 1. Open your browser and go to https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/authorize?client_id=YOUR_APP_ID&response_type=code&redirect_uri=https%3A%2F%2Flocalhost%3A8080&response_mode=query&scope=openid%20profile%20offline_access%20User.Read, replacing ‘YOUR_TENANT_ID’ with your tenant ID and ‘YOUR_APP_ID’ with your application ID from your app registration. 17 | 1. Login and authorize the app. Your browser redirects back to https://localhost:8080 and should show an error that the site cannot be reached. 18 | 1. Copy the URL in the address bar of your browser and paste it into Notepad. It should look like https://localhost:8080/?code=IAQABAAIAAAC...&session_state=.... Copy all of the characters after code= and before &session_state. This is the authorization code returned by Azure. 19 | 1. Paste the authorization code into the ‘code’ key in Postman, then send the request. 20 | 1. The response contains a JSON payload with the access token, refresh token, and ID token. -------------------------------------------------------------------------------- /Day08-AccessTokens.md: -------------------------------------------------------------------------------- 1 | # [Day 8 - Authentication roadmap and access tokens](https://developer.microsoft.com/en-us/graph/blogs/30daysmsgraph-day-8-authentication-roadmap-and-access-tokens) 2 | 3 | Navigate to the documentation for [Azure AD Access Tokens](https://docs.microsoft.com/en-us/azure/active-directory/develop/access-tokens). Decode the v1 and v2 sample tokens using [http://jwt.ms](http://jwt.ms). 4 | 5 | 1. V1 sample token 6 | - eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N5SEpsWSIsImtpZCI6Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N5SEpsWSJ9.eyJhdWQiOiJlZjFkYTlkNC1mZjc3LTRjM2UtYTAwNS04NDBjM2Y4MzA3NDUiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9mYTE1ZDY5Mi1lOWM3LTQ0NjAtYTc0My0yOWYyOTUyMjIyOS8iLCJpYXQiOjE1MzcyMzMxMDYsIm5iZiI6MTUzNzIzMzEwNiwiZXhwIjoxNTM3MjM3MDA2LCJhY3IiOiIxIiwiYWlvIjoiQVhRQWkvOElBQUFBRm0rRS9RVEcrZ0ZuVnhMaldkdzhLKzYxQUdyU091TU1GNmViYU1qN1hPM0libUQzZkdtck95RCtOdlp5R24yVmFUL2tES1h3NE1JaHJnR1ZxNkJuOHdMWG9UMUxrSVorRnpRVmtKUFBMUU9WNEtjWHFTbENWUERTL0RpQ0RnRTIyMlRJbU12V05hRU1hVU9Uc0lHdlRRPT0iLCJhbXIiOlsid2lhIl0sImFwcGlkIjoiNzVkYmU3N2YtMTBhMy00ZTU5LTg1ZmQtOGMxMjc1NDRmMTdjIiwiYXBwaWRhY3IiOiIwIiwiZW1haWwiOiJBYmVMaUBtaWNyb3NvZnQuY29tIiwiZmFtaWx5X25hbWUiOiJMaW5jb2xuIiwiZ2l2ZW5fbmFtZSI6IkFiZSAoTVNGVCkiLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83MmY5ODhiZi04NmYxLTQxYWYtOTFhYi0yZDdjZDAxMjIyNDcvIiwiaXBhZGRyIjoiMjIyLjIyMi4yMjIuMjIiLCJuYW1lIjoiYWJlbGkiLCJvaWQiOiIwMjIyM2I2Yi1hYTFkLTQyZDQtOWVjMC0xYjJiYjkxOTQ0MzgiLCJyaCI6IkkiLCJzY3AiOiJ1c2VyX2ltcGVyc29uYXRpb24iLCJzdWIiOiJsM19yb0lTUVUyMjJiVUxTOXlpMmswWHBxcE9pTXo1SDNaQUNvMUdlWEEiLCJ0aWQiOiJmYTE1ZDY5Mi1lOWM3LTQ0NjAtYTc0My0yOWYyOTU2ZmQ0MjkiLCJ1bmlxdWVfbmFtZSI6ImFiZWxpQG1pY3Jvc29mdC5jb20iLCJ1dGkiOiJGVnNHeFlYSTMwLVR1aWt1dVVvRkFBIiwidmVyIjoiMS4wIn0=.D3H6pMUtQnoJAGq6AHd 7 | 8 | 1. V2 sample token 9 | - eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N5SEpsWSJ9.eyJhdWQiOiI2ZTc0MTcyYi1iZTU2LTQ4NDMtOWZmNC1lNjZhMzliYjEyZTMiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vNzJmOTg4YmYtODZmMS00MWFmLTkxYWItMmQ3Y2QwMTFkYjQ3L3YyLjAiLCJpYXQiOjE1MzcyMzEwNDgsIm5iZiI6MTUzNzIzMTA0OCwiZXhwIjoxNTM3MjM0OTQ4LCJhaW8iOiJBWFFBaS84SUFBQUF0QWFaTG8zQ2hNaWY2S09udHRSQjdlQnE0L0RjY1F6amNKR3hQWXkvQzNqRGFOR3hYZDZ3TklJVkdSZ2hOUm53SjFsT2NBbk5aY2p2a295ckZ4Q3R0djMzMTQwUmlvT0ZKNGJDQ0dWdW9DYWcxdU9UVDIyMjIyZ0h3TFBZUS91Zjc5UVgrMEtJaWpkcm1wNjlSY3R6bVE9PSIsImF6cCI6IjZlNzQxNzJiLWJlNTYtNDg0My05ZmY0LWU2NmEzOWJiMTJlMyIsImF6cGFjciI6IjAiLCJuYW1lIjoiQWJlIExpbmNvbG4iLCJvaWQiOiI2OTAyMjJiZS1mZjFhLTRkNTYtYWJkMS03ZTRmN2QzOGU0NzQiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhYmVsaUBtaWNyb3NvZnQuY29tIiwicmgiOiJJIiwic2NwIjoiYWNjZXNzX2FzX3VzZXIiLCJzdWIiOiJIS1pwZmFIeVdhZGVPb3VZbGl0anJJLUtmZlRtMjIyWDVyclYzeERxZktRIiwidGlkIjoiNzJmOTg4YmYtODZmMS00MWFmLTkxYWItMmQ3Y2QwMTFkYjQ3IiwidXRpIjoiZnFpQnFYTFBqMGVRYTgyUy1JWUZBQSIsInZlciI6IjIuMCJ9.pj4N-w_3Us9DrBLfpCt -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.ApplicationModel; 7 | using Windows.ApplicationModel.Activation; 8 | using Windows.Foundation; 9 | using Windows.Foundation.Collections; 10 | using Windows.UI.Xaml; 11 | using Windows.UI.Xaml.Controls; 12 | using Windows.UI.Xaml.Controls.Primitives; 13 | using Windows.UI.Xaml.Data; 14 | using Windows.UI.Xaml.Input; 15 | using Windows.UI.Xaml.Media; 16 | using Windows.UI.Xaml.Navigation; 17 | 18 | namespace FileUploadSample 19 | { 20 | /// 21 | /// Provides application-specific behavior to supplement the default Application class. 22 | /// 23 | sealed partial class App : Application 24 | { 25 | /// 26 | /// Initializes the singleton application object. This is the first line of authored code 27 | /// executed, and as such is the logical equivalent of main() or WinMain(). 28 | /// 29 | public App() 30 | { 31 | this.InitializeComponent(); 32 | this.Suspending += OnSuspending; 33 | } 34 | 35 | /// 36 | /// Invoked when the application is launched normally by the end user. Other entry points 37 | /// will be used such as when the application is launched to open a specific file. 38 | /// 39 | /// Details about the launch request and process. 40 | protected override void OnLaunched(LaunchActivatedEventArgs e) 41 | { 42 | Frame rootFrame = Window.Current.Content as Frame; 43 | 44 | // Do not repeat app initialization when the Window already has content, 45 | // just ensure that the window is active 46 | if (rootFrame == null) 47 | { 48 | // Create a Frame to act as the navigation context and navigate to the first page 49 | rootFrame = new Frame(); 50 | 51 | rootFrame.NavigationFailed += OnNavigationFailed; 52 | 53 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) 54 | { 55 | //TODO: Load state from previously suspended application 56 | } 57 | 58 | // Place the frame in the current Window 59 | Window.Current.Content = rootFrame; 60 | } 61 | 62 | if (e.PrelaunchActivated == false) 63 | { 64 | if (rootFrame.Content == null) 65 | { 66 | // When the navigation stack isn't restored navigate to the first page, 67 | // configuring the new page by passing required information as a navigation 68 | // parameter 69 | rootFrame.Navigate(typeof(MainPage), e.Arguments); 70 | } 71 | // Ensure the current window is active 72 | Window.Current.Activate(); 73 | } 74 | } 75 | 76 | /// 77 | /// Invoked when Navigation to a certain page fails 78 | /// 79 | /// The Frame which failed navigation 80 | /// Details about the navigation failure 81 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e) 82 | { 83 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 84 | } 85 | 86 | /// 87 | /// Invoked when application execution is being suspended. Application state is saved 88 | /// without knowing whether the application will be terminated or resumed with the contents 89 | /// of memory still intact. 90 | /// 91 | /// The source of the suspend request. 92 | /// Details about the suspend request. 93 | private void OnSuspending(object sender, SuspendingEventArgs e) 94 | { 95 | var deferral = e.SuspendingOperation.GetDeferral(); 96 | //TODO: Save application state and stop any background activity 97 | deferral.Complete(); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/FileUploadSample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x86 7 | {051BC360-AF62-4600-8AED-32172F4480A3} 8 | AppContainerExe 9 | Properties 10 | FileUploadSample 11 | FileUploadSample 12 | en-US 13 | UAP 14 | 10.0.17134.0 15 | 10.0.15063.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | true 20 | FileUploadSample_TemporaryKey.pfx 21 | 22 | 23 | true 24 | bin\x86\Debug\ 25 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 26 | ;2008 27 | full 28 | x86 29 | false 30 | prompt 31 | true 32 | 33 | 34 | bin\x86\Release\ 35 | TRACE;NETFX_CORE;WINDOWS_UWP 36 | true 37 | ;2008 38 | pdbonly 39 | x86 40 | false 41 | prompt 42 | true 43 | true 44 | 45 | 46 | true 47 | bin\ARM\Debug\ 48 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 49 | ;2008 50 | full 51 | ARM 52 | false 53 | prompt 54 | true 55 | 56 | 57 | bin\ARM\Release\ 58 | TRACE;NETFX_CORE;WINDOWS_UWP 59 | true 60 | ;2008 61 | pdbonly 62 | ARM 63 | false 64 | prompt 65 | true 66 | true 67 | 68 | 69 | true 70 | bin\x64\Debug\ 71 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 72 | ;2008 73 | full 74 | x64 75 | false 76 | prompt 77 | true 78 | 79 | 80 | bin\x64\Release\ 81 | TRACE;NETFX_CORE;WINDOWS_UWP 82 | true 83 | ;2008 84 | pdbonly 85 | x64 86 | false 87 | prompt 88 | true 89 | true 90 | 91 | 92 | PackageReference 93 | 94 | 95 | 96 | App.xaml 97 | 98 | 99 | MainPage.xaml 100 | 101 | 102 | 103 | 104 | 105 | Designer 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | MSBuild:Compile 122 | Designer 123 | 124 | 125 | MSBuild:Compile 126 | Designer 127 | 128 | 129 | 130 | 131 | 1.12.0 132 | 133 | 134 | 2.5.0-preview 135 | 136 | 137 | 6.1.5 138 | 139 | 140 | 141 | 14.0 142 | 143 | 144 | 151 | -------------------------------------------------------------------------------- /Day29-OneDrive/FileUploadSample/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Graph; 2 | using Microsoft.Identity.Client; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Net.Http.Headers; 7 | using System.Threading.Tasks; 8 | using Windows.Storage; 9 | using Windows.Storage.Pickers; 10 | using Windows.UI.Xaml; 11 | using Windows.UI.Xaml.Controls; 12 | 13 | // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 14 | 15 | namespace FileUploadSample 16 | { 17 | /// 18 | /// An empty page that can be used on its own or navigated to within a Frame. 19 | /// 20 | public sealed partial class MainPage : Page 21 | { 22 | public MainPage() 23 | { 24 | this.InitializeComponent(); 25 | } 26 | 27 | private const string AADClientId = "YOURAPPIDHERE"; 28 | private const string GraphAPIEndpointPrefix = "https://graph.microsoft.com/v1.0/"; 29 | private string[] AADScopes = new string[] { "files.readwrite.all" }; 30 | private PublicClientApplication AADAppContext = null; 31 | private GraphServiceClient graphClient = null; 32 | 33 | private AuthenticationResult userCredentials; 34 | 35 | public AuthenticationResult UserCredentials 36 | { 37 | get { return userCredentials; } 38 | set { userCredentials = value; } 39 | } 40 | 41 | public void InitializeGraph() 42 | { 43 | if (userCredentials != null) 44 | { 45 | graphClient = new GraphServiceClient( 46 | GraphAPIEndpointPrefix, 47 | new DelegateAuthenticationProvider( 48 | async (requestMessage) => 49 | { 50 | requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", userCredentials.AccessToken); 51 | } 52 | ) 53 | ); 54 | } 55 | } 56 | 57 | 58 | /// 59 | /// Log the user in to either O365 or OneDrive consumer 60 | /// 61 | /// A task to await on 62 | public async Task SignInUser() 63 | { 64 | string status = "Unknown"; 65 | 66 | // Instantiate the app with AAD 67 | AADAppContext = new PublicClientApplication(AADClientId); 68 | 69 | // Get the token, if it fails print out an error message, if it succeeds print out the logged in User's identity as a verification 70 | try 71 | { 72 | UserCredentials = await AADAppContext.AcquireTokenAsync(AADScopes); 73 | if (UserCredentials != null) 74 | { 75 | status = "Signed in as " + UserCredentials.Account.Username; 76 | InitializeGraph(); 77 | } 78 | } 79 | catch (MsalServiceException serviceEx) 80 | { 81 | status = $"Could not sign in, error code: " + serviceEx.ErrorCode; 82 | } 83 | catch (Exception ex) 84 | { 85 | status = $"Error Acquiring Token: {ex}"; 86 | } 87 | 88 | return (status); 89 | } 90 | 91 | /// 92 | /// Take a file less than 4MB and upload it to the service 93 | /// 94 | /// The file that we want to upload 95 | /// Should we upload to SharePoint or OneDrive? 96 | public async Task UploadSmallFile(StorageFile fileToUpload) 97 | { 98 | Stream fileStream = (await fileToUpload.OpenReadAsync()).AsStreamForRead(); 99 | DriveItem uploadedFile = null; 100 | 101 | // Do we want OneDrive for Business/Consumer or do we want a SharePoint Site? 102 | if (uploadToSharePointCheckBox.IsChecked == true) 103 | { 104 | uploadedFile = await graphClient.Sites["root"].Drive.Root.ItemWithPath(fileToUpload.Name).Content.Request().PutAsync(fileStream); 105 | } 106 | else 107 | { 108 | uploadedFile = await graphClient.Me.Drive.Root.ItemWithPath(fileToUpload.Name).Content.Request().PutAsync(fileStream); 109 | } 110 | 111 | return (uploadedFile); 112 | } 113 | 114 | /// 115 | /// Take a file greater than 4MB and upload it to the service 116 | /// 117 | /// The file that we want to upload 118 | /// Should we upload to SharePoint or OneDrive? 119 | public async Task UploadLargeFile(StorageFile fileToUpload) 120 | { 121 | Stream fileStream = (await fileToUpload.OpenReadAsync()).AsStreamForRead(); 122 | DriveItem uploadedFile = null; 123 | UploadSession uploadSession = null; 124 | 125 | // Do we want OneDrive for Business/Consumer or do we want a SharePoint Site? 126 | if (uploadToSharePointCheckBox.IsChecked == true) 127 | { 128 | uploadSession = await graphClient.Sites["root"].Drive.Root.ItemWithPath(fileToUpload.Name).CreateUploadSession().Request().PostAsync(); 129 | } 130 | else 131 | { 132 | uploadSession = await graphClient.Me.Drive.Root.ItemWithPath(fileToUpload.Name).CreateUploadSession().Request().PostAsync(); 133 | } 134 | 135 | if(uploadSession != null) 136 | { 137 | // Chunk size must be divisible by 320KiB, our chunk size will be slightly more than 1MB 138 | int maxSizeChunk = (320 * 1024) * 4; 139 | ChunkedUploadProvider uploadProvider = new ChunkedUploadProvider(uploadSession, graphClient, fileStream, maxSizeChunk); 140 | var chunkRequests = uploadProvider.GetUploadChunkRequests(); 141 | var exceptions = new List(); 142 | var readBuffer = new byte[maxSizeChunk]; 143 | foreach (var request in chunkRequests) 144 | { 145 | var result = await uploadProvider.GetChunkRequestResponseAsync(request, readBuffer, exceptions); 146 | 147 | if(result.UploadSucceeded) 148 | { 149 | uploadedFile = result.ItemResponse; 150 | } 151 | } 152 | } 153 | 154 | return (uploadedFile); 155 | } 156 | 157 | private async Task PickFile() 158 | { 159 | var picker = new FileOpenPicker(); 160 | picker.ViewMode = PickerViewMode.Thumbnail; 161 | picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; 162 | picker.FileTypeFilter.Add(".jpg"); 163 | picker.FileTypeFilter.Add(".jpeg"); 164 | picker.FileTypeFilter.Add(".png"); 165 | 166 | StorageFile pickedFile = await picker.PickSingleFileAsync(); 167 | return (pickedFile); 168 | } 169 | 170 | private async Task UploadFile(object whichButton) 171 | { 172 | if (this.UserCredentials == null) 173 | { 174 | await SignInUser(); 175 | } 176 | 177 | StorageFile fileToUpload = await PickFile(); 178 | DriveItem uploadedFile = null; 179 | 180 | if (whichButton == this.uploadSmallFileButton) 181 | { 182 | uploadedFile = await UploadSmallFile(fileToUpload); 183 | } 184 | else 185 | { 186 | uploadedFile = await UploadLargeFile(fileToUpload); 187 | } 188 | 189 | if (uploadedFile != null) 190 | { 191 | this.statusTextBlock.Text = "Uploaded file: " + uploadedFile.Name; 192 | } 193 | else 194 | { 195 | this.statusTextBlock.Text = "Upload failed"; 196 | } 197 | } 198 | 199 | private async void uploadSmallFileButton_Click(object sender, RoutedEventArgs e) 200 | { 201 | await UploadFile(sender); 202 | } 203 | 204 | private async void uploadLargeFileButton_Click(object sender, RoutedEventArgs e) 205 | { 206 | await UploadFile(sender); 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /Day29-OneDrive/README.md: -------------------------------------------------------------------------------- 1 | # Day 29 - Upload files to OneDrive and SharePoint 2 | 3 | - [Prerequisites](#prerequisites) 4 | - [Step 1: Update the App Registration permissions](#step-1-update-the-app-rgistration-permissions) 5 | - [Step 2: Extend the app to yyy](#step-2-extend-the-app-to-yyy) 6 | - [Create the MyHelper class](#create-the-myhelper-class) 7 | - [Extend program to yyy](#extend-program-to-yyy) 8 | 9 | ## Prerequisites 10 | 11 | To complete this sample you need the following: 12 | 13 | - Complete the [Base Console Application Setup](../base-console-app/) 14 | - [Visual Studio Community](https://visualstudio.microsoft.com/vs/community/) installed on your development machine. If you do not have Visual Studio Community edition (or another version of Visual Studio 2017), visit the previous link for download options. 15 | - Either a personal Microsoft account with a mailbox on Outlook.com, or a Microsoft work or school account. 16 | 17 | If you don't have a Microsoft account, there are a couple of options to get a free account: 18 | 19 | - You can [sign up for a new personal Microsoft account](https://signup.live.com/signup?wa=wsignin1.0&rpsnv=12&ct=1454618383&rver=6.4.6456.0&wp=MBI_SSL_SHARED&wreply=https://mail.live.com/default.aspx&id=64855&cbcxt=mai&bk=1454618383&uiflavor=web&uaid=b213a65b4fdc484382b6622b3ecaa547&mkt=E-US&lc=1033&lic=1). 20 | - You can [sign up for the Office 365 Developer Program](https://developer.microsoft.com/office/dev-program) to get a free Office 365 subscription. 21 | 22 | ## Step 1: Prepare a new client application 23 | 24 | 1. Create a new blank Universal Windows application 25 | 1. Add the following NuGet packages 26 | 1. Microsoft.Graph 27 | 1. Microsoft.Identity.Client 28 | 1. Add the following using declarations to your MainPage.xaml.cs file: 29 | 30 | ```cs 31 | using Microsoft.Graph; 32 | using Microsoft.Identity.Client; 33 | using System.Threading.Tasks; 34 | using System.Net.Http.Headers; 35 | using Windows.Storage; 36 | using Windows.Storage.Pickers; 37 | ``` 38 | 39 | 1. Below the MainPage constructor add the following code: 40 | 41 | ```cs 42 | private const string AADClientId = "YOURAPPIDHERE"; 43 | private const string GraphAPIEndpointPrefix = "https://graph.microsoft.com/v1.0/"; 44 | private string[] AADScopes = new string[] { "files.readwrite.all" }; 45 | private PublicClientApplication AADAppContext = null; 46 | private GraphServiceClient graphClient = null; 47 | private AuthenticationResult userCredentials; 48 | public AuthenticationResult UserCredentials 49 | { 50 | get { return userCredentials; } 51 | set { userCredentials = value; } 52 | } 53 | public void InitializeGraph() 54 | { 55 | if (userCredentials != null) 56 | { 57 | graphClient = new GraphServiceClient( 58 | GraphAPIEndpointPrefix, 59 | new DelegateAuthenticationProvider( 60 | async (requestMessage) => 61 | { 62 | requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", userCredentials.AccessToken); 63 | } 64 | ) 65 | ); 66 | } 67 | } 68 | 69 | /// 70 | /// Log the user in to either Office 365 or OneDrive consumer 71 | /// 72 | /// A task to await on 73 | public async Task SignInUser() 74 | { 75 | string status = "Unknown"; 76 | 77 | // Instantiate the app with AAD 78 | AADAppContext = new PublicClientApplication(AADClientId); 79 | 80 | try 81 | { 82 | UserCredentials = await AADAppContext.AcquireTokenAsync(AADScopes); 83 | if (UserCredentials != null) 84 | { 85 | status = "Signed in as " + UserCredentials.Account.Username; 86 | InitializeGraph(); 87 | } 88 | } 89 | catch (MsalServiceException serviceEx) 90 | { 91 | status = $"Could not sign in, error code: " + serviceEx.ErrorCode; 92 | } 93 | catch (Exception ex) 94 | { 95 | status = $"Error Acquiring Token: {ex}"; 96 | } 97 | 98 | return (status); 99 | } 100 | ``` 101 | 1. Replace YOURAPPIDHERE with the id of your application created in the basic console application example 102 | 103 | ## Step 2: Update the App Registration permissions 104 | 105 | As this exercise requires new permissions the App Registration needs to be updated to include the **Files.ReadWrite.All** permission using the new Azure AD Portal App Registrations UI (in preview as of the time of publish Nov 2018). 106 | 107 | 1. Open a browser and navigate to the [Preview App Registration](https://aka.ms/AppRegistrationsPreview) within Azure AD Portal. Login using a **personal account** (aka: Microsoft Account) or **Work or School Account** with permissions to create app registrations. 108 | 109 | > **Note:** If you do not have permissions to create app registrations contact your Azure AD domain administrators. 110 | 111 | 1. Click on the **.NET Core Graph Tutorial** item in the list 112 | 113 | > **Note:** If you used a different name while completing the [Base Console Application Setup](../base-console-app/) select that instead. 114 | 115 | 1. Click **API permissions** from the current blade content. 116 | 117 | 1. Click **Add a permission** from the current blade content. 118 | 1. On the **Request API permissions** flyout select **Microsoft Graph**. 119 | 120 | ![Screenshot of selecting Microsoft Graph permission to add to app registration](Images/aad-create-app-05.png) 121 | 122 | 1. Select **Delegated permissions**. 123 | 1. In the "Select permissions" search box type "Files.Read". 124 | 1. Select **Files.ReadWrite.All** from the filtered list. 125 | 126 | ![Screenshot of adding application permission for Notes.ReadWrite.All permission](Images/aad-grant-permissions-Files.png) 127 | 128 | 1. Click **Add permissions** at the bottom of flyout. 129 | 130 | ## Step 3: Add upload functionality 131 | 132 | In this step you will add methods to upload small and large files using two different techniques. 133 | 134 | ### Create the upload methods 135 | 136 | 1. Add the following code to your MainPage class for small file uploads: 137 | 138 | ```cs 139 | /// 140 | /// Take a file and upload it to the service 141 | /// 142 | /// The file that we want to upload 143 | /// Should we upload to SharePoint or OneDrive? 144 | public async Task UploadSmallFile(StorageFile fileToUpload, bool uploadToSharePoint) 145 | { 146 | Stream fileStream = (await fileToUpload.OpenReadAsync()).AsStreamForRead(); 147 | DriveItem uploadedFile = null; 148 | 149 | // Do we want OneDrive for Business/Consumer or do we want a SharePoint Site? 150 | if (uploadToSharePoint) 151 | { 152 | uploadedFile = await graphClient.Sites["root"].Drive.Root.ItemWithPath(fileToUpload.Name).Content.Request().PutAsync(fileStream); 153 | } 154 | else 155 | { 156 | uploadedFile = await graphClient.Me.Drive.Root.ItemWithPath(fileToUpload.Name).Content.Request().PutAsync(fileStream); 157 | } 158 | } 159 | ``` 160 | 161 | 1. Add the following code to your MainPage class for large file uploads: 162 | 163 | ```cs 164 | /// 165 | /// Take a file greater than 4MB and upload it to the service 166 | /// 167 | /// The file that we want to upload 168 | /// Should we upload to SharePoint or OneDrive? 169 | public async Task UploadLargeFile(StorageFile fileToUpload, bool uploadToSharePoint) 170 | { 171 | Stream fileStream = (await fileToUpload.OpenReadAsync()).AsStreamForRead(); 172 | DriveItem uploadedFile = null; 173 | UploadSession uploadSession = null; 174 | 175 | // Do we want OneDrive for Business/Consumer or do we want a SharePoint Site? 176 | if (uploadToSharePoint) 177 | { 178 | uploadSession = await graphClient.Sites["root"].Drive.Root.ItemWithPath(fileToUpload.Name).CreateUploadSession().Request().PostAsync(); 179 | } 180 | else 181 | { 182 | uploadSession = await graphClient.Me.Drive.Root.ItemWithPath(fileToUpload.Name).CreateUploadSession().Request().PostAsync(); 183 | } 184 | 185 | if(uploadSession != null) 186 | { 187 | // Chunk size must be divisible by 320KiB, our chunk size will be slightly more than 1MB 188 | int maxSizeChunk = (320 * 1024) * 4; 189 | ChunkedUploadProvider uploadProvider = new ChunkedUploadProvider(uploadSession, graphClient, fileStream, maxSizeChunk); 190 | var chunkRequests = uploadProvider.GetUploadChunkRequests(); 191 | var exceptions = new List(); 192 | var readBuffer = new byte[maxSizeChunk]; 193 | foreach (var request in chunkRequests) 194 | { 195 | var result = await uploadProvider.GetChunkRequestResponseAsync(request, readBuffer, exceptions); 196 | 197 | if(result.UploadSucceeded) 198 | { 199 | uploadedFile = result.ItemResponse; 200 | } 201 | } 202 | } 203 | 204 | return (uploadedFile); 205 | } 206 | ``` 207 | 208 | ### Add UX elements 209 | 210 | 1. Replace the default Grid element in your MainPage.xaml file with the following: 211 | 212 | ```xaml 213 | 214 | 215 | Upload to SharePoint? 216 | 217 | 218 | 219 | 220 | 221 | ``` 222 | 1. In the code behind file (MainPage.xaml.cs) add the following code to add button handlers and connect the file picker: 223 | 224 | ```cs 225 | private async Task PickFile() 226 | { 227 | var picker = new FileOpenPicker(); 228 | picker.ViewMode = PickerViewMode.Thumbnail; 229 | picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; 230 | picker.FileTypeFilter.Add(".jpg"); 231 | picker.FileTypeFilter.Add(".jpeg"); 232 | picker.FileTypeFilter.Add(".png"); 233 | 234 | StorageFile pickedFile = await picker.PickSingleFileAsync(); 235 | return (pickedFile); 236 | } 237 | 238 | private async Task UploadFile(object whichButton) 239 | { 240 | if (this.UserCredentials == null) 241 | { 242 | await SignInUser(); 243 | } 244 | 245 | StorageFile fileToUpload = await PickFile(); 246 | DriveItem uploadedFile = null; 247 | 248 | if (whichButton == this.uploadSmallFileButton) 249 | { 250 | uploadedFile = await UploadSmallFile(fileToUpload); 251 | } 252 | else 253 | { 254 | uploadedFile = await UploadLargeFile(fileToUpload); 255 | } 256 | 257 | if (uploadedFile != null) 258 | { 259 | this.statusTextBlock.Text = "Uploaded file: " + uploadedFile.Name; 260 | } 261 | else 262 | { 263 | this.statusTextBlock.Text = "Upload failed"; 264 | } 265 | } 266 | 267 | private async void uploadSmallFileButton_Click(object sender, RoutedEventArgs e) 268 | { 269 | await UploadFile(sender); 270 | } 271 | 272 | private async void uploadLargeFileButton_Click(object sender, RoutedEventArgs e) 273 | { 274 | await UploadFile(sender); 275 | } 276 | 277 | ``` 278 | 279 | The application is now able to upload small or large files to either OneDrive or SharePoint. --------------------------------------------------------------------------------