プリザンターのAPI連携をデスクトップアプリで使ってみた!

IISの石崎です。
以前にIISの田口が「プリザンターのAPI連携を試してみた!」と「プリザンターのAPI連携を試してみた!(実践編)」という記事を書いています。

今回は、APIで取得したデータを一覧表示するWindowsデスクトップアプリをC#で書いてみます。

完成イメージ

このようなデータが登録されていると
f:id:imageinformationsystem:20181015174844j:plain

このように一覧表示されます。
f:id:imageinformationsystem:20181015174909j:plain

画面上部の「タイトル」「説明」テキストボックスで取得するデータの条件を設定できます。

コード

コード全体はこのようになっています。jsonを扱うためにNuGetでJson.NETをインストールしています。

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal" Margin="5">
            <TextBlock Text="タイトル" Margin="5,0" VerticalAlignment="Center"/>
            <TextBox Width="100" x:Name="title"/>
            <TextBlock Text="説明" Margin="5,0" VerticalAlignment="Center"/>
            <TextBox Width="100" x:Name="body"/>
        </StackPanel>
        <Button Content=" Item取得 " Margin="5,0" HorizontalAlignment="Right" Click="Button_Click"/>

        <DataGrid ItemsSource="{Binding}" Grid.Row="1" IsReadOnly="True" x:Name="dataGrid">
            
        </DataGrid>
    </Grid>
</Window>
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            // Apiキー、HttpClient の準備
            var apiKey = "取得したAPIキー";
            var httpClient = new HttpClient();

            // 取得条件のセット
            var requestData = new ApiRequest();
            requestData.View.ColumnFilterHash.Add("Title", title.Text);
            requestData.View.ColumnFilterHash.Add("Body", body.Text);

            // API 呼び出し Item を取得
            var apiClient = new ApiClient();
            var apiResponse = await apiClient.GetItemsAsync(httpClient, apiKey, "http://localhost:1759/", "Api_Items", 取得するテーブルのID, "get", requestData);

            // 取得結果の表示
            dataGrid.DataContext = apiResponse.Response.Data;
        }
    }

    public class ApiClient
    {
        public async Task<ApiResponse> GetItemsAsync(HttpClient httpClient, string apiKey, string baseUrl, string apiName, long id, string apiMethod, ApiRequest requestData)
        {
            requestData.ApiKey = apiKey;
            var json = JsonConvert.SerializeObject(requestData);
            var content = new StringContent(json, Encoding.UTF8, "application/x-www-form-urlencoded");

            var response = await httpClient.PostAsync($"{baseUrl}/{apiName}/{id}/{apiMethod}", content);
            var responseContentString = await response?.Content?.ReadAsStringAsync();
            var responseContent = JsonConvert.DeserializeObject<ApiResponse>(responseContentString);
            return responseContent;
        }
    }

    public class ApiRequest
    {
        public string ApiKey { get; set; }
        public long Offset { get; set; }
        public View View { get; } = new View();
    }

    public class View
    {
        public Dictionary<string, string> ColumnFilterHash { get; } = new Dictionary<string, string>();
    }

    public class ApiResponse
    {
        public decimal? Id { get; set; }
        public decimal? StatusCode { get; set; }
        public string Message { get; set; }
        public Response Response { get; set; }
    }

    public class Response
    {
        public decimal? Offset { get; set; }
        public decimal? PageSize { get; set; }
        public decimal? TotalCount { get; set; }
        public Item[] Data { get; set; }
    }

    public class Item
    {
        public DateTimeOffset? UpdatedTime { get; set; }
        public long? ResultId { get; set; }
        public long? IssueId { get; set; }
        public long? Ver { get; set; }
        public string Title { get; set; }
        public string Body { get; set; }
        public long? Status { get; set; }
        public long? Manager { get; set; }
        public long? Owner { get; set; }
        public string ClassA { get; set; }
        public string ClassB { get; set; }
        public decimal? NumA { get; set; }
        public decimal? NumB { get; set; }
        public DateTimeOffset? DateA { get; set; }
        public DateTimeOffset? DateB { get; set; }
        public string DescriptionA { get; set; }
        public string DescriptionB { get; set; }
        public bool? CheckA { get; set; }
        public bool? CheckB { get; set; }
        public decimal? Updator { get; set; }
        public string ItemTitle { get; set; }
    }
}

軽く解説

・メインの処理
メインの処理はMainWindowのButton_Clickメソッドです。取得条件(変数名: requestData)を構築して、API呼び出し処理(クラス名: ApiClient)でAPIを呼び出しています。取得結果は、DataGridへセットし画面表示しています。

// Apiキー、HttpClient の準備
var apiKey = "取得したAPIキー";
var httpClient = new HttpClient();

// 取得条件のセット
var requestData = new ApiRequest();
requestData.View.ColumnFilterHash.Add("Title", title.Text);
requestData.View.ColumnFilterHash.Add("Body", body.Text);

// API 呼び出し Item を取得
var apiClient = new ApiClient();
var apiResponse = await apiClient.GetItemsAsync(httpClient, apiKey, "http://localhost:1759/", "Api_Items", 取得するテーブルのID, "get", requestData);

// 取得結果の表示
dataGrid.DataContext = apiResponse.Response.Data;

API呼び出し処理
APIを呼ぶ手続きをApiClientクラスにまとめています。将来他のAPIにも対応する事を見越して一旦、リソース名("Api_Items")やメソッド名("get")などを外から与えられる形にしています。別途リソース名のセットなどもまとめたファサードクラスを作っても良いかもしれません。

public class ApiClient
{
    public async Task<ApiResponse> GetItemsAsync(HttpClient httpClient, string apiKey, string baseUrl, string apiName, long id, string apiMethod, ApiRequest requestData)
    {
        requestData.ApiKey = apiKey;
        var json = JsonConvert.SerializeObject(requestData);
        var content = new StringContent(json, Encoding.UTF8, "application/x-www-form-urlencoded");

        var response = await httpClient.PostAsync($"{baseUrl}/{apiName}/{id}/{apiMethod}", content);
        var responseContentString = await response?.Content?.ReadAsStringAsync();
        var responseContent = JsonConvert.DeserializeObject<ApiResponse>(responseContentString);
        return responseContent;
    }
}

・POCO
残りのクラスは、APIで送受信するデータを持つPOCOです。jsonのデータを型のあるオブジェクトとして扱えるようにしています。型にうるさいC#の恩恵が受けられます。

public class ApiRequest
{
    public string ApiKey { get; set; }
    public long Offset { get; set; }
    public View View { get; } = new View();
}

public class View
{
    public Dictionary<string, string> ColumnFilterHash { get; } = new Dictionary<string, string>();
}

public class ApiResponse
{
    public decimal? Id { get; set; }
    public decimal? StatusCode { get; set; }
    public string Message { get; set; }
    public Response Response { get; set; }
}

public class Response
{
    public decimal? Offset { get; set; }
    public decimal? PageSize { get; set; }
    public decimal? TotalCount { get; set; }
    public Item[] Data { get; set; }
}

public class Item
{
    public DateTimeOffset? UpdatedTime { get; set; }
    public long? ResultId { get; set; }
    public long? IssueId { get; set; }
    public long? Ver { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
    public long? Status { get; set; }
    public long? Manager { get; set; }
    public long? Owner { get; set; }
    public string ClassA { get; set; }
    public string ClassB { get; set; }
    public decimal? NumA { get; set; }
    public decimal? NumB { get; set; }
    public DateTimeOffset? DateA { get; set; }
    public DateTimeOffset? DateB { get; set; }
    public string DescriptionA { get; set; }
    public string DescriptionB { get; set; }
    public bool? CheckA { get; set; }
    public bool? CheckB { get; set; }
    public decimal? Updator { get; set; }
    public string ItemTitle { get; set; }
}

最後に

C#によるデスクトップアプリ開発IISが最も得意とする領域です。今後もプリザンターとデスクトップアプリの連携の研究を進めて行くつもりです。デスクトップアプリとの連携に関心のある方、よかったらブログ上部の「+読者になる」をクリックをお願いします!