Skip to content

Commit 658cecd

Browse files
authored
update the ASP.NET Core Web API tutorial ASP.NET Core 3.0 (#111)
* Updating the first folder to ASP.NET Core 3.0 and Microsoft.Identity.Web - updating Program.cs and Startup.cs * Synching Folder 1 with relevant content of Folder 2 which was better * Updating the second folder to ASP.NET core 3.0 * Updating the third folder to ASP.NET Core 3.0 * Updating the test project to .NET Core 3.0
1 parent 1e97054 commit 658cecd

File tree

28 files changed

+283
-475
lines changed

28 files changed

+283
-475
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,4 @@ artifacts/
188188
/2. Web API now calls Microsoft Graph/AppCreationScripts/createdApps.html
189189
/2. Web API now calls Microsoft Graph/AppCreationScripts/Steps.md
190190
/1. Desktop app calls Web API/AppCreationScripts/Steps.md
191+
/3.-Web-api-call-Microsoft-graph-for-personal-accounts/AppCreationScripts/createdApps.html

1. Desktop app calls Web API/TodoListClient/App.xaml.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using System.Windows;
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Windows;
25

36
namespace TodoListClient
47
{

1. Desktop app calls Web API/TodoListClient/MainWindow.xaml.cs

Lines changed: 83 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,18 @@
1-
/*
2-
The MIT License (MIT)
3-
4-
Copyright (c) 2018 Microsoft Corporation
5-
6-
Permission is hereby granted, free of charge, to any person obtaining a copy
7-
of this software and associated documentation files (the "Software"), to deal
8-
in the Software without restriction, including without limitation the rights
9-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10-
copies of the Software, and to permit persons to whom the Software is
11-
furnished to do so, subject to the following conditions:
12-
13-
The above copyright notice and this permission notice shall be included in all
14-
copies or substantial portions of the Software.
15-
16-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22-
SOFTWARE.
23-
*/
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
243

254
using Microsoft.Identity.Client;
265
using Newtonsoft.Json;
276
using System.Collections.Generic;
287
using System.Configuration;
8+
using System.Diagnostics;
299
// The following using statements were added for this sample.
3010
using System.Globalization;
11+
using System.IO;
3112
using System.Linq;
3213
using System.Net.Http;
3314
using System.Net.Http.Headers;
15+
using System.Reflection;
3416
using System.Text;
3517
using System.Threading.Tasks;
3618
using System.Windows;
@@ -55,18 +37,25 @@ public partial class MainWindow : Window
5537

5638
private static readonly string Authority = string.Format(CultureInfo.InvariantCulture, AadInstance, Tenant);
5739

58-
//
59-
// To authenticate to the To Do list service, the client needs to know the service's App ID URI.
60-
// To contact the To Do list service we need it's URL as well.
61-
//
40+
// To authenticate to the To Do list service, the client needs to know the service's App ID URI and URL
41+
6242
private static readonly string TodoListScope = ConfigurationManager.AppSettings["todo:TodoListScope"];
6343
private static readonly string TodoListBaseAddress = ConfigurationManager.AppSettings["todo:TodoListBaseAddress"];
6444
private static readonly string[] Scopes = { TodoListScope };
45+
private static string TodoListApiAddress
46+
{
47+
get
48+
{
49+
string baseAddress = TodoListBaseAddress;
50+
return baseAddress.EndsWith("/") ? TodoListBaseAddress + "api/todolist"
51+
: TodoListBaseAddress + "/api/todolist";
52+
}
53+
}
6554

6655
private readonly HttpClient _httpClient = new HttpClient();
6756
private readonly IPublicClientApplication _app;
6857

69-
// Button strings
58+
// Button content
7059
const string SignInString = "Sign In";
7160
const string ClearCacheString = "Clear Cache";
7261

@@ -84,7 +73,7 @@ public MainWindow()
8473

8574
private void GetTodoList()
8675
{
87-
GetTodoList(SignInButton.Content.ToString() != ClearCacheString);
76+
GetTodoList(SignInButton.Content.ToString() != ClearCacheString).ConfigureAwait(false);
8877
}
8978

9079
private async Task GetTodoList(bool isAppStarting)
@@ -95,9 +84,8 @@ private async Task GetTodoList(bool isAppStarting)
9584
SignInButton.Content = SignInString;
9685
return;
9786
}
98-
//
87+
9988
// Get an access token to call the To Do service.
100-
//
10189
AuthenticationResult result = null;
10290
try
10391
{
@@ -135,29 +123,42 @@ private async Task GetTodoList(bool isAppStarting)
135123
return;
136124
}
137125

138-
// Once the token has been returned by ADAL, add it to the http authorization header, before making the call to access the To Do list service.
126+
// Once the token has been returned by MSAL, add it to the http authorization header, before making the call to access the To Do list service.
139127
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
140128

141129
// Call the To Do list service.
142-
HttpResponseMessage response = await _httpClient.GetAsync(TodoListBaseAddress + "/api/todolist");
130+
HttpResponseMessage response = await _httpClient.GetAsync(TodoListApiAddress);
143131

144132
if (response.IsSuccessStatusCode)
145133
{
146-
147134
// Read the response and data-bind to the GridView to display To Do items.
148135
string s = await response.Content.ReadAsStringAsync();
149136
List<TodoItem> toDoArray = JsonConvert.DeserializeObject<List<TodoItem>>(s);
150137

151138
Dispatcher.Invoke(() =>
152139
{
153-
154140
TodoList.ItemsSource = toDoArray.Select(t => new { t.Title });
155141
});
156142
}
157143
else
158144
{
159-
string failureDescription = await response.Content.ReadAsStringAsync();
160-
MessageBox.Show($"{response.ReasonPhrase}\n {failureDescription}", "An error occurred while getting /api/todolist", MessageBoxButton.OK);
145+
await DisplayErrorMessage(response);
146+
}
147+
}
148+
149+
private static async Task DisplayErrorMessage(HttpResponseMessage httpResponse)
150+
{
151+
string failureDescription = await httpResponse.Content.ReadAsStringAsync();
152+
if (failureDescription.StartsWith("<!DOCTYPE html>"))
153+
{
154+
string path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
155+
string errorFilePath = Path.Combine(path, "error.html");
156+
File.WriteAllText(errorFilePath, failureDescription);
157+
Process.Start(errorFilePath);
158+
}
159+
else
160+
{
161+
MessageBox.Show($"{httpResponse.ReasonPhrase}\n {failureDescription}", "An error occurred while getting /api/todolist", MessageBoxButton.OK);
161162
}
162163
}
163164

@@ -176,17 +177,19 @@ private async void AddTodoItem(object sender, RoutedEventArgs e)
176177
return;
177178
}
178179

179-
//
180180
// Get an access token to call the To Do service.
181-
//
182181
AuthenticationResult result = null;
183182
try
184183
{
185184
result = await _app.AcquireTokenSilent(Scopes, accounts.FirstOrDefault())
186185
.ExecuteAsync()
187186
.ConfigureAwait(false);
188-
SetUserName(result.Account);
189-
UserName.Content = Properties.Resources.UserNotSignedIn;
187+
188+
Dispatcher.Invoke(() =>
189+
{
190+
SetUserName(result.Account);
191+
UserName.Content = Properties.Resources.UserNotSignedIn;
192+
});
190193
}
191194
// There is no access token in the cache, so prompt the user to sign-in.
192195
catch (MsalUiRequiredException)
@@ -217,7 +220,7 @@ private async void AddTodoItem(object sender, RoutedEventArgs e)
217220
// Call the To Do service.
218221
//
219222

220-
// Once the token has been returned by ADAL, add it to the http authorization header, before making the call to access the To Do service.
223+
// Once the token has been returned by MSAL, add it to the http authorization header, before making the call to access the To Do service.
221224
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
222225

223226
// Forms encode Todo item, to POST to the todo list web api.
@@ -227,7 +230,7 @@ private async void AddTodoItem(object sender, RoutedEventArgs e)
227230

228231
// Call the To Do list service.
229232

230-
HttpResponseMessage response = await _httpClient.PostAsync(TodoListBaseAddress + "/api/todolist", content);
233+
HttpResponseMessage response = await _httpClient.PostAsync(TodoListApiAddress, content);
231234

232235
if (response.IsSuccessStatusCode)
233236
{
@@ -236,8 +239,7 @@ private async void AddTodoItem(object sender, RoutedEventArgs e)
236239
}
237240
else
238241
{
239-
string failureDescription = await response.Content.ReadAsStringAsync();
240-
MessageBox.Show($"{response.ReasonPhrase}\n {failureDescription}", "An error occurred while posting to /api/todolist", MessageBoxButton.OK);
242+
await DisplayErrorMessage(response);
241243
}
242244
}
243245

@@ -262,18 +264,13 @@ private async void SignIn(object sender = null, RoutedEventArgs args = null)
262264
return;
263265
}
264266

265-
//
266267
// Get an access token to call the To Do list service.
267-
//
268268
try
269269
{
270-
// Force a sign-in (PromptBehavior.Always), as the ADAL web browser might contain cookies for the current user, and using .Auto
271-
// would re-sign-in the same user
272-
var result = await _app.AcquireTokenInteractive(Scopes)
273-
.WithAccount(accounts.FirstOrDefault())
274-
.WithPrompt(Prompt.SelectAccount)
270+
var result = await _app.AcquireTokenSilent(Scopes, accounts.FirstOrDefault())
275271
.ExecuteAsync()
276272
.ConfigureAwait(false);
273+
277274
Dispatcher.Invoke(() =>
278275
{
279276
SignInButton.Content = ClearCacheString;
@@ -282,25 +279,49 @@ private async void SignIn(object sender = null, RoutedEventArgs args = null)
282279
}
283280
);
284281
}
285-
catch (MsalException ex)
282+
catch (MsalUiRequiredException)
286283
{
287-
if (ex.ErrorCode == "access_denied")
288-
{
289-
// The user canceled sign in, take no action.
284+
try
285+
{
286+
// Force a sign-in (Prompt.SelectAccount), as the MSAL web browser might contain cookies for the current user
287+
// and we don't necessarily want to re-sign-in the same user
288+
var result = await _app.AcquireTokenInteractive(Scopes)
289+
.WithAccount(accounts.FirstOrDefault())
290+
.WithPrompt(Prompt.SelectAccount)
291+
.ExecuteAsync()
292+
.ConfigureAwait(false);
293+
294+
Dispatcher.Invoke(() =>
295+
{
296+
SignInButton.Content = ClearCacheString;
297+
SetUserName(result.Account);
298+
GetTodoList();
299+
}
300+
);
290301
}
291-
else
302+
catch (MsalException ex)
292303
{
293-
// An unexpected error occurred.
294-
string message = ex.Message;
295-
if (ex.InnerException != null)
304+
if (ex.ErrorCode == "access_denied")
296305
{
297-
message += "Error Code: " + ex.ErrorCode + "Inner Exception : " + ex.InnerException.Message;
306+
// The user canceled sign in, take no action.
298307
}
308+
else
309+
{
310+
// An unexpected error occurred.
311+
string message = ex.Message;
312+
if (ex.InnerException != null)
313+
{
314+
message += "Error Code: " + ex.ErrorCode + "Inner Exception : " + ex.InnerException.Message;
315+
}
299316

300317
MessageBox.Show(message);
301318
}
302319

303-
UserName.Content = Properties.Resources.UserNotSignedIn;
320+
Dispatcher.Invoke(() =>
321+
{
322+
UserName.Content = Properties.Resources.UserNotSignedIn;
323+
});
324+
}
304325
}
305326
}
306327

1. Desktop app calls Web API/TodoListClient/TodoItem.cs

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,5 @@
1-
/*
2-
The MIT License (MIT)
3-
4-
Copyright (c) 2018 Microsoft Corporation
5-
6-
Permission is hereby granted, free of charge, to any person obtaining a copy
7-
of this software and associated documentation files (the "Software"), to deal
8-
in the Software without restriction, including without limitation the rights
9-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10-
copies of the Software, and to permit persons to whom the Software is
11-
furnished to do so, subject to the following conditions:
12-
13-
The above copyright notice and this permission notice shall be included in all
14-
copies or substantial portions of the Software.
15-
16-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22-
SOFTWARE.
23-
*/
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
243

254
namespace TodoListClient
265
{

1. Desktop app calls Web API/TodoListClient/TokenCacheHelper.cs

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,5 @@
1-
//------------------------------------------------------------------------------
2-
//
3-
// Copyright (c) Microsoft Corporation.
4-
// All rights reserved.
5-
//
6-
// This code is licensed under the MIT License.
7-
//
8-
// Permission is hereby granted, free of charge, to any person obtaining a copy
9-
// of this software and associated documentation files(the "Software"), to deal
10-
// in the Software without restriction, including without limitation the rights
11-
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
12-
// copies of the Software, and to permit persons to whom the Software is
13-
// furnished to do so, subject to the following conditions :
14-
//
15-
// The above copyright notice and this permission notice shall be included in
16-
// all copies or substantial portions of the Software.
17-
//
18-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
21-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24-
// THE SOFTWARE.
25-
//
26-
//------------------------------------------------------------------------------
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
273

284
using System.IO;
295
using System.Security.Cryptography;
@@ -32,8 +8,7 @@
328
namespace TodoListClient
339
{
3410
static class TokenCacheHelper
35-
{
36-
11+
{
3712
/// <summary>
3813
/// Path to the token cache
3914
/// </summary>

0 commit comments

Comments
 (0)