Skip to content

Commit b58a712

Browse files
committed
Merge branch 'master' into pehecke-solutions-update
2 parents 0167e58 + 97efb64 commit b58a712

40 files changed

+419
-105
lines changed
96.9 KB
Loading
56.7 KB
Loading
64.9 KB
Loading
46.6 KB
Loading
78.7 KB
Loading
70.9 KB
Loading

powerapps-docs/developer/common-data-service/walkthrough-blazor-webassembly-single-tenant.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: "Tutorial: Create an ASP.NET Core Blazor WebAssembly App using Common Data Service | Microsoft Docs"
33
description: ""
44
keywords: ""
5-
ms.date: 05/25/2020
5+
ms.date: 07/08/2020
66
ms.service: powerapps
77
ms.topic: article
88
author: JimDaly # GitHub ID
@@ -499,7 +499,8 @@ In Visual Studio, press F5 to launch the app with the code changes.
499499

500500
### See also
501501

502+
[Quickstart: Blazor Server Web API sample (C#)](./webapi/quick-start-blazor-server-app.md)
502503
[Secure an ASP.NET Core Blazor WebAssembly standalone app with Azure Active Directory](/aspnet/core/security/blazor/webassembly/standalone-with-azure-active-directory)<br />
503504
[Walkthrough: Register an app with Azure Active Directory](walkthrough-register-app-azure-active-directory.md)<br />
504505
[Use OAuth with Common Data Service](authenticate-oauth.md)<br />
505-
[Use the Common Data Service Web API](webapi/overview.md)
506+
[Use the Common Data Service Web API](webapi/overview.md)

powerapps-docs/developer/common-data-service/webapi/TOC.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
href: get-started-dynamics-365-web-api-csharp.md
1111
- name: 'Quick Start: Web API sample (C#)'
1212
href: quick-start-console-app-csharp.md
13+
- name: 'Quick Start: Blazor Server sample (C#)'
14+
href: quick-start-blazor-server-app.md
1315
- name: Enhanced quick start (C#)
1416
href: enhanced-quick-start.md
1517
- name: Start Web API project in Visual Studio
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
---
2+
title: "Quickstart: Blazor Server Web API sample (C#) (Common Data Service)| Microsoft Docs"
3+
description: "This sample demonstrates how to authenticate with a Common Data Service from a Blazor Server application and then call a basic WhoAmI Web API function."
4+
ms.custom: ""
5+
ms.date: 07/07/2020
6+
ms.service: powerapps
7+
ms.topic: "article"
8+
author: "JeremyLikness" # GitHub ID
9+
ms.author: "jeliknes" # MSFT alias of Microsoft employees only
10+
ms.reviewer: "pehecke"
11+
manager: "" # MSFT alias of manager or PM counterpart
12+
search.audienceType:
13+
- developer
14+
search.app:
15+
- PowerApps
16+
- D365CE
17+
---
18+
# Quickstart: Blazor Server Web API sample (C#)
19+
20+
In this quickstart, you'll create a Blazor Server application to connect to your Common Data Service environment using the Web API.
21+
22+
You'll authenticate and use <xref:System.Net.Http.HttpClient> to send a `GET` request containing the [WhoAmI](/dynamics365/customer-engagement/web-api/whoami) function. The response will be a [WhoAmIResponse](/dynamics365/customer-engagement/web-api/whoamiresponse) complex type. After call completion, the `UserId` property value is displayed.
23+
24+
> [!NOTE]
25+
> This is a very simple example to show how to get connected with a minimum of code. The [Enhanced quickstart](enhanced-quick-start.md) will build upon this sample to apply better design patterns.
26+
27+
## Prerequisites
28+
29+
- Visual Studio 2019 (version 16.6.2 or later recommended)
30+
- Familiarity with the Microsoft Azure portal
31+
- Internet connection
32+
- Valid user account for a Common Data Service instance
33+
- Administrator access to grant application registrations
34+
- URL to the Common Data Service environment you want to connect with
35+
- Basic understanding of the Visual C# language
36+
37+
> [!NOTE]
38+
> To authenticate you must have an app registered in Azure Active Directory. The registration will happen automatically as part of the template creation, but will require additional updates in the Azure portal.
39+
40+
## Create a Visual Studio project
41+
42+
1. Create a new Blazor Server app using .NET Core 3.1 but don't choose **Create** just yet.
43+
44+
![Start a Blazor Server project](../media/quick-start-blazor-server-app-csharp-1.png)
45+
46+
1. Select **Change** under **Authentication** and then choose **Work or School Accounts**.
47+
48+
![Choose authentication](../media/quick-start-blazor-server-app-csharp-2.png)
49+
50+
1. Choose the appropriate dropdown and then replace `CRM520451` in the example with your environment's name.
51+
52+
1. Select **Create**.
53+
54+
## Configure the application in Active Directory
55+
56+
By default, the template will create a registered application. Connecting to Common Data Service will require additional permissions. Open the Azure portal and log in with your credentials. Navigate to **Active Directory** and **App Registrations**, and then choose the entry with the same name as your application.
57+
58+
1. Choose **Authentication**, select (check) **Access tokens** under **Implicit grant**, and then click **Save**.
59+
60+
![Implicit grant](../media/quick-start-blazor-server-app-csharp-3.png)
61+
62+
1. Choose **Certificates & secrets** and then select **New client secret**.
63+
64+
1. Assign the secret a name (for example, "Blazor Server client") and expiration date, and then select **Add**.
65+
66+
1. Select the clipboard icon next to your secret to copy it.
67+
68+
![Copy secret](../media/quick-start-blazor-server-app-csharp-4.png)
69+
70+
1. In your Blazor Server app, open `appsettings.json` and add an entry for "ClientSecret". The Active Directory settings should look like this:
71+
72+
```json
73+
{
74+
"AzureAd": {
75+
"Instance": "https://login.microsoftonline.com/",
76+
"Domain": "{org}.onmicrosoft.com",
77+
"TenantId": "{tenantId}",
78+
"ClientId": "{clientId}",
79+
"ClientSecret": "{secret}",
80+
"CallbackPath": "/signin-oidc"
81+
}
82+
}
83+
```
84+
85+
1. Navigate to **API permissions**
86+
87+
1. Select **Add a permission** and choose **Dynamics CRM**
88+
89+
1. Choose **Delegated permissions** and select (check) **user_impersonation**, and then click **Add permissions**
90+
91+
![Add permission](../media/quick-start-blazor-server-app-csharp-5.png)
92+
93+
1. Select the newly created permission to highlight it, and then shoose **Grant admin consent for organization** (your environment name is shown)
94+
95+
1. Verify the permissions have green checkboxes in the **status** column
96+
97+
## Prepare the app to use Azure AD tokens
98+
99+
The application requires some extra steps to capture the authentication token and pass it to the Web API request.
100+
101+
1. Right-click on the **Data** folder and add a new class named `TokenProvider`.
102+
103+
```csharp
104+
public class TokenProvider
105+
{
106+
public string AccessToken { get; set; }
107+
}
108+
```
109+
110+
1. Open the App.razor file and add the following statements to the top of the file. Change the namespace to match the name of your application.
111+
112+
```razor
113+
@using BlazorWebAPIExample.Data
114+
@inject TokenProvider Service
115+
```
116+
117+
1. Add a `@code` block to accept a parameter and move the token into the service.
118+
119+
```csharp
120+
[Parameter]
121+
public TokenProvider InitialState { get; set; }
122+
123+
protected override void OnInitialized()
124+
{
125+
Service.AccessToken = InitialState.AccessToken;
126+
base.OnInitialized();
127+
}
128+
```
129+
130+
1. Open the Pages/\_Host.cshtml file and add the following using statements after the namespace declaration.
131+
132+
```razor
133+
@using BlazorCommonDataService.Data
134+
@using Microsoft.AspNetCore.Authentication
135+
```
136+
137+
1. After the `<body>` tag, add the following code and update the app component to acquire and pass the token.
138+
139+
```razor
140+
@{
141+
var token = new TokenProvider
142+
{
143+
AccessToken = await HttpContext.GetTokenAsync("access_token")
144+
};
145+
}
146+
<app>
147+
<component type="typeof(App)" param-InitialState="token" render-mode="ServerPrerendered" />
148+
</app>
149+
```
150+
151+
1. Obtain the environment name for the Common Data Services management API. If you're not sure what the name is, open the [Power Platform admin center](https://admin.powerplatform.microsoft.com/environments), navigate to **Environments** then choose **Open environment**. You will see a URL like this: `https://{org}.crm.dynamics.com` where {org} is the environment name.
152+
153+
1. Add an entry named `CDSAPI` to the appsettings.json file with the environment URL as the value. Append `/api/data/v.9.0/` to the end of the URL so it looks like this:
154+
155+
```json
156+
{ "CDSAPI": "https://{org}.crm.dynamics.com/api/data/v9.0/" }
157+
```
158+
159+
1. Add this `using` statement to the file Startup.cs.
160+
161+
```csharp
162+
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
163+
```
164+
165+
1. In the `Startup.cs` class, add registrations to retrieve the authentication token and configure a client ready to use the token. Place this code between `services.AddAuthentication` and `services.AddControllersWithViews`.
166+
167+
```csharp
168+
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme,
169+
opt =>
170+
{
171+
var resourceUri = new Uri(Configuration["CDSAPI"]);
172+
var resource = $"{resourceUri.Scheme}://{resourceUri.Host}/";
173+
opt.ResponseType = "code";
174+
opt.SaveTokens = true;
175+
opt.Scope.Add("user_impersonation");
176+
opt.Scope.Add(new Uri(Configuration["CDSAPI"]).Host);
177+
opt.Resource = resource;
178+
});
179+
services.AddScoped<TokenProvider>();
180+
services.AddHttpClient("CDS", client =>
181+
{
182+
client.BaseAddress = new Uri(Configuration["CDSAPI"]);
183+
});
184+
```
185+
186+
The first registration allows requesting the token with the proper scope. The second registers the service that tracks the token, and the third creates a client with the base API address pre-configured.
187+
188+
## Make a call to the Web API
189+
190+
Next, you'll update the `Index.razor` component to call the Web API.
191+
192+
1. Open the Index.razor file and add these statements to the top:
193+
194+
```razor
195+
@using System.Text.Json
196+
@using BlazorWebAPIExample.Data;
197+
@using System.Net.Http.Headers;
198+
@inject IHttpClientFactory Factory
199+
@inject TokenProvider TokenProvider
200+
```
201+
202+
1. Add this markup after the `SurveyPrompt` component:
203+
204+
```razor
205+
@if (Loading)
206+
{
207+
<div class="alert alert-warning">Loading...</div>
208+
}
209+
@if (Error)
210+
{
211+
<div class="alert alert-danger">@ErrorMessage</div>
212+
}
213+
@if (!Loading && !Error)
214+
{
215+
<div class="alert alert-info">You did it! Your user id is: @UserId</div>
216+
}
217+
```
218+
219+
1. Finally, add a `@code` block with the following code:
220+
221+
```csharp
222+
public bool Loading;
223+
public string ErrorMessage;
224+
public bool Error => !string.IsNullOrWhiteSpace(ErrorMessage);
225+
public string UserId;
226+
227+
protected override async Task OnInitializedAsync()
228+
{
229+
Loading = true;
230+
try
231+
{
232+
var client = Factory.CreateClient("CDS");
233+
client.DefaultRequestHeaders.Authorization =
234+
new AuthenticationHeaderValue("Bearer", TokenProvider.AccessToken);
235+
var result = await client.GetAsync("WhoAmI");
236+
result.EnsureSuccessStatusCode();
237+
UserId = JsonDocument.Parse(await result.Content.ReadAsStringAsync())
238+
.RootElement.GetProperty("UserId").GetGuid().ToString();
239+
}
240+
catch (Exception ex)
241+
{
242+
ErrorMessage = ex.Message;
243+
}
244+
finally
245+
{
246+
Loading = false;
247+
}
248+
await base.OnInitializedAsync();
249+
}
250+
```
251+
252+
The application is now ready!
253+
254+
## Run the program
255+
256+
Press F5 to run the program. The output should look like this:
257+
258+
![Connection success](../media/quick-start-blazor-server-app-csharp-6.png)
259+
260+
**Congratulations!** You have successfully connected to the Web API.
261+
262+
This quickstart sample shows a simple approach to create a Visual Studio project without any exception handling or method to refresh the access token. You can expand on the example to perform more complex operations, and wrap the `HttpClient` object in a service class to handle the permissions.
263+
264+
The [Enhanced quickstart](enhanced-quick-start.md) topic shows how to:
265+
266+
- Implement exception handling methods
267+
- Use basic authentication with a connection string
268+
- Create a reusable method to refresh the access token
269+
- Build reusable methods for data operations
270+
271+
## Next steps
272+
273+
Learn how to structure your code for a better design.
274+
275+
> [!div class="nextstepaction"]
276+
> [Enhanced quickstart](enhanced-quick-start.md)<br/>
277+
278+
### See Also
279+
280+
[Tutorial: Create an ASP.NET Core Blazor WebAssembly App using Common Data Service](../walkthrough-blazor-webassembly-single-tenant.md)

powerapps-docs/developer/component-framework/add-custom-controls-to-a-field-or-entity.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ Following the steps below will change the default label and text box field of th
6363

6464
- **Step**. This represents the unit to increment or decrement when adding to or subtracting from the current value. For example, for budget amount you can select 100 dollar increments\decrements.
6565

66-
- **Hide Default Control**. Hides the component so neither the component or the data is displayed in any of the clients that don't support the code component.
66+
- **Hide Default Control**. Hides the component so neither the component nor the data is displayed in any of the clients that don't support the code component.
6767

6868
8. Select **OK**, to close the Field Properties page.
6969

0 commit comments

Comments
 (0)