強化されたクイック スタート
このトピックでは、再利用可能な HttpClient およびエラー処理方法を追加することによって、クイック スタートトピックのコードをどのようにリファクターするかを示します。 このトピックを開始する前に、クイック スタートトピックの手順を実行して、新しい Visual Studio プロジェクトを作成するか、または Visual Studio プロジェクトの MSAL バージョンをダウンロードします。
この強化されたクイック スタートの後で行き詰まった場合は、完成したソリューションをダウンロードできます。
接続文字列で資格情報を渡すことを有効にする
コード内にユーザー ログオン資格情報を配置することはお勧めできません。 ユーザーの資格情報をどのように取り込むかは、作成しているクライアントのタイプによって異なります。 このコンソール アプリケーション用には、App.config ファイル内に資格情報を設定します。資格情報をコード外へ移動する便利な手段だからです。 またこれは Web API データ操作のサンプル (C#) で使用した方法です。よって、この方法を理解していれば、他の Web API サンプルがどのように機能するかが簡単にわかります。
この要求を有効にするには、3 つのステップが必要です。
System.Configuration 参照を Visual Studio プロジェクトに追加する
- ソリューション エクスプローラー で、参照 を右クリックし、参照の追加... を選択します。
- 参照マネージャー ダイアログで
System.Configurationを検索し、チェックボックスを選択してこの参照をプロジェクトに追加します。 - OK をクリックして 参照マネージャー ダイアログ ボックスを閉じます。
アプリケーション構成ファイルの編集
ソリューション エクスプローラー で、App.config ファイルを開きます。 次のように見えるはずです。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
</configuration>
<configuration> 要素を編集し、以下に示すように connectionStrings ノードを加えます。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
<connectionStrings>
<!--Online using Microsoft 365-->
<add name="Connect"
connectionString="Url=https://yourorg.api.crm.dynamics.com;Username=yourname@yourorg.onmicrosoft.com;Password=mypassword;" />
</connectionStrings>
</configuration>
これは、名前で参照できる接続文字列を作成します。この場合は Connect です。これにより、必要に応じて複数の接続を定義できます。
Microsoft Dataverse テスト環境への接続に必要なものに一致するように、 connectionString パラメータの接続文字列 Url、 Username および Password の値を編集します。
using ディレクティブを Program.cs に追加
Program.cs ファイルの先頭に、この using ディレクティブを追加します:
using System.Configuration;
MSAL NuGet パッケージをインストールします
Visual Studio で、ソリューション エクスプローラー でプロジェクトを右クリックし、コンテキスト メニューで NuGet パッケージを管理する を選択します。 Microsoft.Identity.Client パッケージを参照して、プロジェクトにインストールします。 このパッケージは、Web サービス認証に使用されます。
ヘルパー コードを追加
クイック スタート の例では、すべてのコードは Program.cs ファイル内にあります。 HttpClient の接続と作成を扱うコードを、ヘルパー メソッドの別のファイルに移動します。
これらのヘルパーは、 Web API データ操作のサンプル (C#) で使用された SampleHelper.cs ファイルでも使用されます。 これらのヘルパーを理解すれば、これらがサンプルでどのように使用されるかを理解します。
ソリューション エクスプローラー で、プロジェクトを右クリックし、追加 > クラス... を選択して (または
Shift+Alt+Cを押して) 新しいアイテムの追加 ダイアログを開きます。クラス ファイルの名前を指定します。 Web API データ操作のサンプル (C#) によって使用されるパターンをフォローするには、 「SampleHelpers.cs」と名前を付けます。
注意
クラスの名前によって、 メイン プログラム内でのこれらのヘルパー プロパティとメソッドの参照方法が決まります。 残りの手順では、クラスに SampleHelpers という名前を付けたと想定しています。
- 次のコードを SampleHelpers.cs ファイルに追加します。
using System;
using System.Linq;
using System.Net.Http;
namespace EnhancedQuickStart
{
/// <summary>
/// Shared code for common operations used by many Power Apps samples.
/// </summary>
class SampleHelpers
{
//These sample application registration values are available for all online instances.
//You can use these while running sample code, but you should get your own for your own apps
public static string clientId = "51f81489-12ee-4a9e-aaae-a2591f45987d";
public static string redirectUrl = "app://58145B91-0C36-4500-8554-080854F2AC97";
/// <summary>
/// Method used to get a value from the connection string
/// </summary>
/// <param name="connectionString"></param>
/// <param name="parameter"></param>
/// <returns>The value from the connection string that matches the parameter key value</returns>
public static string GetParameterValueFromConnectionString(string connectionString, string parameter)
{
try
{
return connectionString.Split(';').Where(s => s.Trim().StartsWith(parameter)).FirstOrDefault().Split('=')[1];
}
catch (Exception)
{
return string.Empty;
}
}
/// <summary>
/// Returns an HttpClient configured with an OAuthMessageHandler
/// </summary>
/// <param name="connectionString">The connection string to use.</param>
/// <param name="clientId">The client id to use when authenticating.</param>
/// <param name="redirectUrl">The redirect Url to use when authenticating</param>
/// <param name="version">The version of Web API to use. Defaults to version 9.2 </param>
/// <returns>An HttpClient you can use to perform authenticated operations with the Web API</returns>
public static HttpClient GetHttpClient(string connectionString, string clientId, string redirectUrl, string version = "v9.2")
{
string url = GetParameterValueFromConnectionString(connectionString, "Url");
string username = GetParameterValueFromConnectionString(connectionString, "Username");
string password = GetParameterValueFromConnectionString(connectionString, "Password");
try
{
HttpMessageHandler messageHandler = new OAuthMessageHandler(url, clientId, redirectUrl, username, password,
new HttpClientHandler());
HttpClient httpClient = new HttpClient(messageHandler)
{
BaseAddress = new Uri(string.Format("{0}/api/data/{1}/", url, version)),
Timeout = new TimeSpan(0, 2, 0) //2 minutes
};
return httpClient;
}
catch (Exception)
{
throw;
}
}
/// <summary> Displays exception information to the console. </summary>
/// <param name="ex">The exception to output</param>
public static void DisplayException(Exception ex)
{
Console.WriteLine("The application terminated with an error.");
Console.WriteLine(ex.Message);
while (ex.InnerException != null)
{
Console.WriteLine("\t* {0}", ex.InnerException.Message);
ex = ex.InnerException;
}
}
}
}
OAuthMessageHandlerクラスを、以下に提供されているコードを使用して、独自のクラスファイル内に追加します。
このクラスにより、操作が実行されるたびにアクセス トークンが更新されます。 各アクセス トークンは約 1 時間後に期限切れとなります。 このクラスは DelegatingHandler を実装します。これは、操作が実行されるたびに Microsoft Authentication Library (MSAL) 認証コンテキストと連携して正しい AcquireToken バリエーションを呼び出すため、トークンの有効期限を明示的に管理する必要はありません。
using Microsoft.Identity.Client;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security;
using System.Threading.Tasks;
namespace EnhancedQuickStart
{
/// <summary>
/// Custom HTTP message handler that uses OAuth authentication through
/// Microsoft Authentication Library (MSAL).
/// </summary>
class OAuthMessageHandler : DelegatingHandler
{
private AuthenticationHeaderValue authHeader;
public OAuthMessageHandler(string serviceUrl, string clientId, string redirectUrl, string username, string password,
HttpMessageHandler innerHandler)
: base(innerHandler)
{
string apiVersion = "9.2";
string webApiUrl = $"{serviceUrl}/api/data/v{apiVersion}/";
//Build Microsoft.Identity.Client (MSAL) OAuth Token Request
var authBuilder = PublicClientApplicationBuilder.Create(clientId)
.WithAuthority(AadAuthorityAudience.AzureAdMultipleOrgs)
.WithRedirectUri(redirectUrl)
.Build();
var scope = serviceUrl + "//.default";
string[] scopes = { scope };
AuthenticationResult authBuilderResult;
if (username != string.Empty && password != string.Empty)
{
//Make silent Microsoft.Identity.Client (MSAL) OAuth Token Request
var securePassword = new SecureString();
foreach (char ch in password) securePassword.AppendChar(ch);
authBuilderResult = authBuilder.AcquireTokenByUsernamePassword(scopes, username, securePassword)
.ExecuteAsync().Result;
}
else
{
//Popup authentication dialog box to get token
authBuilderResult = authBuilder.AcquireTokenInteractive(scopes)
.ExecuteAsync().Result;
}
//Note that an Azure AD access token has finite lifetime, default expiration is 60 minutes.
authHeader = new AuthenticationHeaderValue("Bearer", authBuilderResult.AccessToken);
}
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
request.Headers.Authorization = authHeader;
return base.SendAsync(request, cancellationToken);
}
}
}
Program.cs を更新する
これで接続文字列で資格情報を渡すことを有効にするおよびヘルパー コードを追加するに変更を施したため、Program.cs ファイルに次のものだけを含むように Main メソッドを更新できます。
using Newtonsoft.Json.Linq;
using System;
using System.Configuration;
using System.Net.Http;
namespace EnhancedQuickStart
{
class Program
{
static void Main(string[] args)
{
try
{
//Get configuration data from App.config connectionStrings
string connectionString = ConfigurationManager.ConnectionStrings["Connect"].ConnectionString;
using (HttpClient client = SampleHelpers.GetHttpClient(connectionString, SampleHelpers.clientId, SampleHelpers.redirectUrl))
{
// Use the WhoAmI function
var response = client.GetAsync("WhoAmI").Result;
if (response.IsSuccessStatusCode)
{
//Get the response content and parse it.
JObject body = JObject.Parse(response.Content.ReadAsStringAsync().Result);
Guid userId = (Guid)body["UserId"];
Console.WriteLine("Your UserId is {0}", userId);
}
else
{
Console.WriteLine("The request failed with a status of '{0}'",
response.ReasonPhrase);
}
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
}
}
catch (Exception ex)
{
SampleHelpers.DisplayException(ex);
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
}
}
}
}
これはコード量がより少なく、HttpClient を使うたびにエラー処理とアクセス トークンを更新する手段を追加しました。
F5 キーを押してプログラムを実行します。 クイック スタート サンプルのように、出力は次のようになります。
Your UserId is 969effb0-98ae-478c-b547-53a2968c2e75
Press any key to exit.
再利用可能なメソッドを作成
Program.Main メソッドでコードの総量を減らしましたが、1 つの操作を呼び出すためだけにプログラムを書くわけではありません。そして、たった 1 つの操作を呼び出すためだけにそれほど多くのコードを書くのは現実的ではありません。
このセクションでは、これを変更する方法を示します。
var response = client.GetAsync("WhoAmI").Result;
if (response.IsSuccessStatusCode)
{
//Get the response content and parse it.
JObject body = JObject.Parse(response.Content.ReadAsStringAsync().Result);
Guid userId = (Guid)body["UserId"];
Console.WriteLine("Your UserId is {0}", userId);
}
else
{
Console.WriteLine("The request failed with a status of '{0}'",
response.ReasonPhrase);
}
結果として、次を実現します。
WhoAmIResponse response = WhoAmI(client);
Console.WriteLine("Your system user ID is: {0}", response.UserId);
開始する前に、Web API 参照にアクセスして、次のトピックを確認しておくことをお勧めします。
WhoAmI Function がどのようにWhoAmIResponse ComplexType を返し、WhoAmIResponse ComplexType が次の 3 つの GUID プロパティを含んでいることに注意してください: BusinessUnitId、UserId および OrganizationId。
追加するコードは、単にこれらを、パラメーターとして HttpClient を受け取る再利用可能なメソッドにモデル化します。
注意
これをどのように行うかは、個人用な好みの問題です。 この設計は比較的単純なために提供されています。
Visual Studio プロジェクトで、次のステップを実行します:
Programクラスを編集して部分クラスにします。上位では、これを変更します。
class Program結果として、次を実現します。
partial class ProgramProgramMethods.csファイルという名前の新しいクラスを作成しますProgramMethods.csでは、これを変更します。class ProgramMethods結果として、次を実現します。
partial class Programこのように、ProgramMethods.cs ファイルの
Programクラスは、Program.cs ファイルの元のProgramクラスの単なる拡張です。次のディレクティブを ProgramMethods.cs ファイルの上位に追加します。
using Newtonsoft.Json.Linq; using System; using System.Net.Http;次のメソッドを ProgramMethods.cs ファイルの
Programクラスに追加します。public static WhoAmIResponse WhoAmI(HttpClient client) { WhoAmIResponse returnValue = new WhoAmIResponse(); //Send the WhoAmI request to the Web API using a GET request. HttpResponseMessage response = client.GetAsync("WhoAmI", HttpCompletionOption.ResponseHeadersRead).Result; if (response.IsSuccessStatusCode) { //Get the response content and parse it. JObject body = JObject.Parse(response.Content.ReadAsStringAsync().Result); returnValue.BusinessUnitId = (Guid)body["BusinessUnitId"]; returnValue.UserId = (Guid)body["UserId"]; returnValue.OrganizationId = (Guid)body["OrganizationId"]; } else { throw new Exception(string.Format("The WhoAmI request failed with a status of '{0}'", response.ReasonPhrase)); } return returnValue; }次のクラスを、
Programクラスの外側で ProgramMethods.cs ファイルの名前空間内に追加します。public class WhoAmIResponse { public Guid BusinessUnitId { get; set; } public Guid UserId { get; set; } public Guid OrganizationId { get; set; } }元の Program.cs ファイル内の
Program.Mainメソッド:編集前:
var response = client.GetAsync("WhoAmI").Result; if (response.IsSuccessStatusCode) { //Get the response content and parse it. JObject body = JObject.Parse(response.Content.ReadAsStringAsync().Result); Guid userId = (Guid)body["UserId"]; Console.WriteLine("Your UserId is {0}", userId); } else { Console.WriteLine("The request failed with a status of '{0}'", response.ReasonPhrase); }編集後:
WhoAmIResponse response = WhoAmI(client); Console.WriteLine("Your system user ID is: {0}", response.UserId);F5 キーを押してサンプルを実行します。以前と同じ結果を取得します。
トラブルシューティング
このサンプルを実行するときに問題がある場合、https://github.com/Microsoft/PowerApps-Samples の GitHub のリポジトリから、すべての Power Apps のサンプルをダウンロードできます 。
重要
GitHub リポジトリのすべてのサンプルは、PowerApps-Samples:cds\App.config にある共通の App.config を使用するように構成されています。 接続文字列を設定するときは、このファイルを編集する必要があります。 その場合、資格情報を再度設定することなくすべてのサンプルを実行できます。
テンプレート プロジェクトを作成
このトピックを閉じる前に、プロジェクト テンプレートとしてプロジェクトを保存することを検討します。 次に、今後の学習プロジェクトのためにそのテンプレートを再利用すると、新しいプロジェクトの設定の時間と労力を節約できます。 このため、プロジェクトが Microsoft Visual Studioでオープンしている間に、 ファイル メニューで、テンプレートのエクスポート を選択します。 テンプレート ウィザードのエクスポート の指示に従い、テンプレートを作成します。
次のステップ
詳細については、以下のリソースを参照してください。
注意
ドキュメントの言語設定についてお聞かせください。 簡単な調査を行います。 (この調査は英語です)
この調査には約 7 分かかります。 個人データは収集されません (プライバシー ステートメント)。
フィードバック
フィードバックの送信と表示