|
| 1 | +<!-- markdownlint-disable MD002 MD041 --> |
| 2 | + |
| 3 | +Open Visual Studio, and select **File > New > Project**. In the **New Project** dialog, do the following: |
| 4 | + |
| 5 | +1. Select **Templates > Visual C# > Web**. |
| 6 | +1. Select **ASP.NET Web Application (.NET Framework)**. |
| 7 | +1. Enter **graph-tutorial** for the Name of the project. |
| 8 | + |
| 9 | +  |
| 10 | + |
| 11 | + > [!NOTE] |
| 12 | + > Ensure that you enter the exact same name for the Visual Studio Project that is specified in these lab instructions. The Visual Studio Project name becomes part of the namespace in the code. The code inside these instructions depends on the namespace matching the Visual Studio Project name specified in these instructions. If you use a different project name the code will not compile unless you adjust all the namespaces to match the Visual Studio Project name you enter when you create the project. |
| 13 | +
|
| 14 | +1. Select **OK**. In the **New ASP.NET Web Application Project** dialog, select **MVC** (under **ASP.NET 4.7.2 Templates**) and select **OK**. |
| 15 | + |
| 16 | +1. Press **F5** or select **Debug > Start Debugging**. If everything is working, your default browser should open and display a default ASP.NET page. |
| 17 | + |
| 18 | +## Add NuGet packages |
| 19 | + |
| 20 | +Before moving on, update the `bootstrap` NuGet package, and install some additional NuGet packages that you will use later. |
| 21 | + |
| 22 | +- [Microsoft.Owin.Host.SystemWeb](https://www.nuget.org/packages/Microsoft.Owin.Host.SystemWeb/) to enable the [OWIN](http://owin.org/) interfaces in the ASP.NET application. |
| 23 | +- [Microsoft.Owin.Security.OpenIdConnect](https://www.nuget.org/packages/Microsoft.Owin.Security.OpenIdConnect/) for doing OpenID Connect authentication with Azure. |
| 24 | +- [Microsoft.Owin.Security.Cookies](https://www.nuget.org/packages/Microsoft.Owin.Security.Cookies/) to enable cookie-based authentication. |
| 25 | +- [Microsoft.Identity.Client](https://www.nuget.org/packages/Microsoft.Identity.Client/) for requesting and managing access tokens. |
| 26 | +- [Microsoft.Graph](https://www.nuget.org/packages/Microsoft.Graph/) for making calls to Microsoft Graph. |
| 27 | + |
| 28 | +1. Select **Tools > NuGet Package Manager > Package Manager Console**. |
| 29 | +1. In the Package Manager Console, enter the following commands. |
| 30 | + |
| 31 | + ```Powershell |
| 32 | + Update-Package bootstrap |
| 33 | + Install-Package Microsoft.Owin.Host.SystemWeb |
| 34 | + Install-Package Microsoft.Owin.Security.OpenIdConnect |
| 35 | + Install-Package Microsoft.Owin.Security.Cookies |
| 36 | + Install-Package Microsoft.Identity.Client -Version 3.0.8 |
| 37 | + Install-Package Microsoft.Graph -Version 1.15.0 |
| 38 | + ``` |
| 39 | +
|
| 40 | +## Design the app |
| 41 | +
|
| 42 | +In this section you will create the basic structure of the application. |
| 43 | +
|
| 44 | +1. Create a basic OWIN startup class. Right-click the `graph-tutorial` folder in Solution Explorer and select **Add > New Item**. Choose the **OWIN Startup Class** template, name the file `Startup.cs`, and select **Add**. |
| 45 | +
|
| 46 | +1. Right-click the **Models** folder in Solution Explorer and select **Add > Class...**. Name the class `Alert` and select **Add**. Add the following code in `Alert.cs`. You'll use this class to flash error messages in the app's views. |
| 47 | +
|
| 48 | + ```cs |
| 49 | + namespace graph_tutorial.Models |
| 50 | + { |
| 51 | + public class Alert |
| 52 | + { |
| 53 | + public const string AlertKey = "TempDataAlerts"; |
| 54 | + public string Message { get; set; } |
| 55 | + public string Debug { get; set; } |
| 56 | + } |
| 57 | + } |
| 58 | + ``` |
| 59 | +
|
| 60 | +1. Open the `./Views/Shared/_Layout.cshtml` file, and replace its entire contents with the following code to update the global layout of the app. |
| 61 | +
|
| 62 | + ```html |
| 63 | + @{ |
| 64 | + var alerts = TempData.ContainsKey(graph_tutorial.Models.Alert.AlertKey) ? |
| 65 | + (List<graph_tutorial.Models.Alert>)TempData[graph_tutorial.Models.Alert.AlertKey] : |
| 66 | + new List<graph_tutorial.Models.Alert>(); |
| 67 | + } |
| 68 | +
|
| 69 | + <!DOCTYPE html> |
| 70 | + <html> |
| 71 | + <head> |
| 72 | + <meta charset="utf-8" /> |
| 73 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 74 | + <title>ASP.NET Graph Tutorial</title> |
| 75 | + @Styles.Render("~/Content/css") |
| 76 | + @Scripts.Render("~/bundles/modernizr") |
| 77 | +
|
| 78 | + <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" |
| 79 | + integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" |
| 80 | + crossorigin="anonymous"> |
| 81 | + </head> |
| 82 | +
|
| 83 | + <body> |
| 84 | + <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark"> |
| 85 | + <div class="container"> |
| 86 | + @Html.ActionLink("ASP.NET Graph Tutorial", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" }) |
| 87 | + <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" |
| 88 | + aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation"> |
| 89 | + <span class="navbar-toggler-icon"></span> |
| 90 | + </button> |
| 91 | + <div class="collapse navbar-collapse" id="navbarCollapse"> |
| 92 | + <ul class="navbar-nav mr-auto"> |
| 93 | + <li class="nav-item"> |
| 94 | + @Html.ActionLink("Home", "Index", "Home", new { area = "" }, |
| 95 | + new { @class = ViewBag.Current == "Home" ? "nav-link active" : "nav-link" }) |
| 96 | + </li> |
| 97 | + @if (Request.IsAuthenticated) |
| 98 | + { |
| 99 | + <li class="nav-item" data-turbolinks="false"> |
| 100 | + @Html.ActionLink("Calendar", "Index", "Calendar", new { area = "" }, |
| 101 | + new { @class = ViewBag.Current == "Calendar" ? "nav-link active" : "nav-link" }) |
| 102 | + </li> |
| 103 | + } |
| 104 | + </ul> |
| 105 | + <ul class="navbar-nav justify-content-end"> |
| 106 | + <li class="nav-item"> |
| 107 | + <a class="nav-link" href="https://developer.microsoft.com/graph/docs/concepts/overview" target="_blank"> |
| 108 | + <i class="fas fa-external-link-alt mr-1"></i>Docs |
| 109 | + </a> |
| 110 | + </li> |
| 111 | + @if (Request.IsAuthenticated) |
| 112 | + { |
| 113 | + <li class="nav-item dropdown"> |
| 114 | + <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false"> |
| 115 | + @if (!string.IsNullOrEmpty(ViewBag.User.Avatar)) |
| 116 | + { |
| 117 | + <img src="@ViewBag.User.Avatar" class="rounded-circle align-self-center mr-2" style="width: 32px;"> |
| 118 | + } |
| 119 | + else |
| 120 | + { |
| 121 | + <i class="far fa-user-circle fa-lg rounded-circle align-self-center mr-2" style="width: 32px;"></i> |
| 122 | + } |
| 123 | + </a> |
| 124 | + <div class="dropdown-menu dropdown-menu-right"> |
| 125 | + <h5 class="dropdown-item-text mb-0">@ViewBag.User.DisplayName</h5> |
| 126 | + <p class="dropdown-item-text text-muted mb-0">@ViewBag.User.Email</p> |
| 127 | + <div class="dropdown-divider"></div> |
| 128 | + @Html.ActionLink("Sign Out", "SignOut", "Account", new { area = "" }, new { @class = "dropdown-item" }) |
| 129 | + </div> |
| 130 | + </li> |
| 131 | + } |
| 132 | + else |
| 133 | + { |
| 134 | + <li class="nav-item"> |
| 135 | + @Html.ActionLink("Sign In", "SignIn", "Account", new { area = "" }, new { @class = "nav-link" }) |
| 136 | + </li> |
| 137 | + } |
| 138 | + </ul> |
| 139 | + </div> |
| 140 | + </div> |
| 141 | + </nav> |
| 142 | + <main role="main" class="container"> |
| 143 | + @foreach (var alert in alerts) |
| 144 | + { |
| 145 | + <div class="alert alert-danger" role="alert"> |
| 146 | + <p class="mb-3">@alert.Message</p> |
| 147 | + @if (!string.IsNullOrEmpty(alert.Debug)) |
| 148 | + { |
| 149 | + <pre class="alert-pre border bg-light p-2"><code>@alert.Debug</code></pre> |
| 150 | + } |
| 151 | + </div> |
| 152 | + } |
| 153 | +
|
| 154 | + @RenderBody() |
| 155 | + </main> |
| 156 | + @Scripts.Render("~/bundles/jquery") |
| 157 | + @Scripts.Render("~/bundles/bootstrap") |
| 158 | + @RenderSection("scripts", required: false) |
| 159 | + </body> |
| 160 | + </html> |
| 161 | + ``` |
| 162 | +
|
| 163 | + This code adds [Bootstrap](https://getbootstrap.com/) for simple styling, and [Font Awesome](https://fontawesome.com/) for some simple icons. It also defines a global layout with a nav bar, and uses the `Alert` class to display any alerts. |
| 164 | +
|
| 165 | +1. Open `Content/Site.css` and replace its entire contents with the following code. |
| 166 | +
|
| 167 | + ```css |
| 168 | + body { |
| 169 | + padding-top: 4.5rem; |
| 170 | + } |
| 171 | +
|
| 172 | + .alert-pre { |
| 173 | + word-wrap: break-word; |
| 174 | + word-break: break-all; |
| 175 | + white-space: pre-wrap; |
| 176 | + } |
| 177 | + ``` |
| 178 | +
|
| 179 | +1. Open the `Views/Home/index.cshtml` file and replace its contents with the following. |
| 180 | +
|
| 181 | + ```html |
| 182 | + @{ |
| 183 | + ViewBag.Current = "Home"; |
| 184 | + } |
| 185 | +
|
| 186 | + <div class="jumbotron"> |
| 187 | + <h1>ASP.NET Graph Tutorial</h1> |
| 188 | + <p class="lead">This sample app shows how to use the Microsoft Graph API to access Outlook and OneDrive data from ASP.NET</p> |
| 189 | + @if (Request.IsAuthenticated) |
| 190 | + { |
| 191 | + <h4>Welcome @ViewBag.User.DisplayName!</h4> |
| 192 | + <p>Use the navigation bar at the top of the page to get started.</p> |
| 193 | + } |
| 194 | + else |
| 195 | + { |
| 196 | + @Html.ActionLink("Click here to sign in", "SignIn", "Account", new { area = "" }, new { @class = "btn btn-primary btn-large" }) |
| 197 | + } |
| 198 | + </div> |
| 199 | + ``` |
| 200 | +
|
| 201 | +1. Right-click the **Controllers** folder in Solution Explorer and select **Add > Controller...**. Choose **MVC 5 Controller - Empty** and select **Add**. Name the controller `BaseController` and select **Add**. Replace the contents of `BaseController.cs` with the following code. |
| 202 | +
|
| 203 | + ```cs |
| 204 | + using graph_tutorial.Models; |
| 205 | + using System.Collections.Generic; |
| 206 | + using System.Web.Mvc; |
| 207 | +
|
| 208 | + namespace graph_tutorial.Controllers |
| 209 | + { |
| 210 | + public abstract class BaseController : Controller |
| 211 | + { |
| 212 | + protected void Flash(string message, string debug=null) |
| 213 | + { |
| 214 | + var alerts = TempData.ContainsKey(Alert.AlertKey) ? |
| 215 | + (List<Alert>)TempData[Alert.AlertKey] : |
| 216 | + new List<Alert>(); |
| 217 | +
|
| 218 | + alerts.Add(new Alert |
| 219 | + { |
| 220 | + Message = message, |
| 221 | + Debug = debug |
| 222 | + }); |
| 223 | +
|
| 224 | + TempData[Alert.AlertKey] = alerts; |
| 225 | + } |
| 226 | + } |
| 227 | + } |
| 228 | + ``` |
| 229 | +
|
| 230 | + Any controller can inherit from this base controller class to gain access to the `Flash` function. Update the `HomeController` class to inherit from `BaseController`. |
| 231 | +
|
| 232 | +1. Open `Controllers/HomeController.cs` and change the `public class HomeController : Controller` line to: |
| 233 | +
|
| 234 | + ```cs |
| 235 | + public class HomeController : BaseController |
| 236 | + ``` |
| 237 | +
|
| 238 | +1. Save all of your changes and restart the server. Now, the app should look very different. |
| 239 | +
|
| 240 | +  |
0 commit comments