使用 C# 管理 Azure 时序见解第 1 代环境的参考数据Manage reference data for an Azure Time Series Insights Gen 1 environment using C Sharp

本文演示如何将 C#、MSAL.NET 和 Azure Active Directory 结合使用,以向 Azure 时序见解 Gen 1 参考数据管理 API 发出编程性 API 请求。This article demonstrates how to combine C#, MSAL.NET, and Azure Active Directory to make programmatic API requests to the Azure Time Series Insights Gen 1 Reference Data Management API.

总结Summary

下面的示例代码演示了以下功能:The sample code below demonstrates the following features:

  • 使用 MSAL.NET PublicClientApplication 获取访问令牌。Acquiring an access token using MSAL.NET PublicClientApplication.

  • 针对 Gen 1 参考数据管理 API 的顺序创建、读取、更新和删除操作。Sequential CREATE, READ, UPDATE, and DELETE operations against the Gen 1 Reference Data Management API.

  • 常见的响应代码,包括常见错误代码Common response codes including common error codes.

    参考数据管理 API 单独处理每个项,一个项出现错误不会阻止其他项成功完成。The Reference Data Management API processes each item individually and an error with one item does not prevent the others from successfully completing. 例如,如果你的请求包含 100 个项,其中一个项发生错误,则会写入 99 个项,并拒绝一个项。For example, if your request has 100 items and one item has an error, then 99 items are written and one is rejected.

先决条件和设置Prerequisites and setup

在编译和运行示例代码之前,请完成以下步骤:Complete the following steps before you compile and run the sample code:

  1. 预配 Gen 1 Azure 时序见解环境。Provision a Gen 1 Azure Time Series Insights environment.

  2. 在环境中创建参考数据集Create a Reference Data set within your environment. 使用以下参考数据方案:Use the following Reference Data scheme:

    项名Key name 类型Type
    uuiduuid 字符串String
  3. 为 Azure Active Directory 配置 Azure 时序见解环境,如身份验证和授权中所述。Configure your Azure Time Series Insights environment for Azure Active Directory as described in Authentication and authorization. 使用 http://localhost:8080/ 作为“重定向 URI”。Use http://localhost:8080/ as the Redirect URI.

  4. 安装必需的项目依赖项。Install the required project dependencies.

  5. 编辑下面的示例代码,将每个 #PLACEHOLDER# 替换为相应的环境标识符。Edit the sample code below by replacing each #PLACEHOLDER# with the appropriate environment identifier.

  6. 在项目的根目录中运行 dotnet runRun dotnet run within the root directory of your project. 出现提示时,使用你的用户配置文件登录到 Azure。When prompted, use your user profile to sign in to Azure.

项目依赖项Project dependencies

建议使用最新版本的 Visual Studio 和 NETCore.app:It's recommended that you use the newest version of Visual Studio and NETCore.app:

示例代码包含两个必需的依赖项:The sample code has two required dependencies:

使用 NuGet 2.12+ 添加包:Add the packages using NuGet 2.12+:

  • dotnet add package Newtonsoft.Json --version 12.0.3
  • dotnet add package Microsoft.Identity.Client --version 4.7.1

或:Or:

  1. 声明一个 csharp-tsi-msal-ga-sample.csproj 文件:Declare a csharp-tsi-msal-ga-sample.csproj file:

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>netcoreapp2.1</TargetFramework>
        <LangVersion>latest</LangVersion>
        <RootNamespace>csharp-tsi-msal-ga-sample</RootNamespace>
        <RunWorkingDirectory>$(MSBuildThisFileDirectory)</RunWorkingDirectory>
      </PropertyGroup>
      <ItemGroup>
        <PackageReference Include="Microsoft.Identity.Client" Version="4.7.1.0" Culture="neutral" PublicKeyToken="0a613f4dd989e8ae" />
        <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
      </ItemGroup>
    </Project>
    
  2. 然后运行 dotnet restoreThen run dotnet restore.

C# 示例代码C# sample code

// Copyright (c) Microsoft Corporation.  All rights reserved.

namespace CsharpTsiMsalGaSample
{
    using Microsoft.Identity.Client;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System;
    using System.IO;
    using System.Net.Http;
    using System.Text;
    using System.Threading.Tasks;

    public static class Program
    {
        /**
         * Review the product documentation for detailed configuration steps or skip ahead and configure your environment settings.
         *
         * https://docs.azure.cn/time-series-insights/time-series-insights-authentication-and-authorization
         */

        // Azure Time Series Insights environment configuration
        internal static string EnvironmentFqdn = "#PLACEHOLDER#.env.timeseries.azure.cn";
        internal static string EnvironmentReferenceDataSetName = "#PLACEHOLDER#";

        // Azure Active Directory application configuration
        internal static string AadClientApplicationId = "#PLACEHOLDER#";
        internal static string[] AadScopes = new string[] { "https://api.timeseries.azure.cn//user_impersonation" };
        internal static string AadRedirectUri = "http://localhost:8080/";
        internal static string AadTenantName = "#PLACEHOLDER#";
        internal static string AadAuthenticationAuthority = "https://login.partner.microsoftonline.cn/" + AadTenantName + ".partner.onmschina.cn/oauth2/authorize?resource=https://api.timeseries.azure.cn/";

        private static async Task<string> AcquireAccessTokenAsync()
        {
            if (AadClientApplicationId == "#PLACEHOLDER#" || AadScopes.Length == 0 || AadRedirectUri == "#PLACEHOLDER#" || AadTenantName.StartsWith("#PLACEHOLDER#"))
            {
                throw new Exception($"Use the link {"https://docs.azure.cn/time-series-insights/time-series-insights-get-started"} to update the values of 'AadClientApplicationId', 'AadScopes', 'AadRedirectUri', and 'AadAuthenticationAuthority'.");
            }

            /**
             * MSAL.NET configuration. Review the product documentation for more information about MSAL.NET authentication options.
             *
             * https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/
             */

            IPublicClientApplication app = PublicClientApplicationBuilder
                .Create(AadClientApplicationId)
                .WithRedirectUri(AadRedirectUri)
                .WithAuthority(AadAuthenticationAuthority)
                .Build();

            AuthenticationResult result = await app
                .AcquireTokenInteractive(AadScopes)
                .ExecuteAsync();

            Console.WriteLine("MSAL Authentication Token Acquired: {0}", result.AccessToken);
            Console.WriteLine("");
            return result.AccessToken;
        }

        // System.Net.HttpClient helper to wrap HTTP POST made to the GA Reference Data API
        private static async Task<HttpResponseMessage> AsyncHttpPostRequestHelper(HttpClient httpClient, string input)
        {
             if (EnvironmentFqdn.StartsWith("#PLACEHOLDER#") || EnvironmentReferenceDataSetName == "#PLACEHOLDER#")
             {
                throw new Exception($"Use the link {"https://docs.azure.cn/time-series-insights/time-series-insights-authentication-and-authorization"} to update the values of 'EnvironmentFqdn' and 'EnvironmentReferenceDataSetName'.");
             }

             Console.WriteLine("HTTP JSON Request Body: {0}", input);
             Console.WriteLine("");
             HttpContent requestBody = new StringContent(input, Encoding.UTF8, "application/json");

             Uri uri = new UriBuilder("https", EnvironmentFqdn)
             {
                Path = $"referencedatasets/{EnvironmentReferenceDataSetName}/$batch",
                Query = "api-version=2016-12-12"
             }.Uri;

             Console.WriteLine("Making HTTP POST to URI: {0}", uri);
             Console.WriteLine("");

             HttpResponseMessage response = await httpClient.PostAsync(uri, requestBody);
             if (response.IsSuccessStatusCode)
             {
                var jsonString = await response.Content.ReadAsStringAsync();
                var jsonStringTransferObject = JsonConvert.DeserializeObject<object>(jsonString);
                Console.WriteLine("HTTP JSON Response Body: {0}", jsonStringTransferObject);
                Console.WriteLine("");
                return response;
             }

             return null;
        }

        private static async Task TsiMsalGaSample()
        {
            Console.WriteLine("Beginning demo...");
            Console.WriteLine("");
            Console.WriteLine("The following samples assume a single Key Name (uuid) with String type...");
            Console.WriteLine("");

            string accessToken = await AcquireAccessTokenAsync();
            var httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);

            {
                // CREATE reference data
                Console.WriteLine("CREATE reference data example...");
                Console.WriteLine("");
                string createInput = @"
                    {
                        ""put"": [
                            {
                                ""uuid"": ""Fan1""
                            },
                            {
                                ""uuid"": ""Fan2"",
                                ""color"": ""White"",
                                ""floor"": 2
                            },
                            {
                                ""uuid"": ""Fan3"",
                                ""color"": ""Red"",
                                ""maxSpeed"": 5
                            }
                        ]
                    }";


                var createResponse = await AsyncHttpPostRequestHelper(httpClient, createInput);

                // READ reference data
                Console.WriteLine("READ reference data example...");
                Console.WriteLine("");
                string readInput = @"
                    {
                        ""get"": [
                            {
                                ""uuid"": ""Fan1""
                            },
                            {
                                ""uuid"": ""Fan2"",
                                ""color"": ""White"",
                                ""desc"": ""example""
                            },
                            {
                                ""uuid"": ""Fan3"",
                                ""color"": ""Red"",
                                ""maxSpeed"": 5
                            }
                        ]
                    }";

                var readResponse = await AsyncHttpPostRequestHelper(httpClient, readInput);

                // UPDATE reference data
                Console.WriteLine("UPDATE reference data example...");
                Console.WriteLine("");
                string updateInput = @"
                    {
                        ""patch"": [
                            {
                                ""uuid"": ""Fan1"",
                                ""color"": ""Red""
                            },
                            {
                                ""uuid"": ""Fan2"",
                                ""color"": ""Orange""
                            },
                            {
                                ""uuid"": ""Fan3"",
                                ""desc"": ""Example""
                            }
                        ]
                    }";

                var inputResponse = await AsyncHttpPostRequestHelper(httpClient, updateInput);

                // DELETE reference data
                Console.WriteLine("DELETE reference data example...");
                Console.WriteLine("");
                string deleteInput = @"
                    {
                        ""delete"": [
                            {
                                ""uuid"": ""Fan1""
                            },
                            {
                                ""uuid"": ""Fan2"",
                                ""color"": ""Orange""
                            },
                            {
                                ""uuid"": ""Fan2"",
                                ""desc"": ""Blue""
                            }
                        ]
                    }";

                var deleteResponse = await AsyncHttpPostRequestHelper(httpClient, deleteInput);
            }
        }

        internal static void Main(string[] args)
        {
            Task.Run(async () => await TsiMsalGaSample()).Wait();
        }
    }
}

后续步骤Next steps