C#
.NETCore
アドベントカレンダー2018

.NET Coreでサービスを作ってデスクトップアプリで利用してみる

Ateam Lifestyle x cyma Advent Calendar 2018 の19日目は自転車通販サイト「cyma -サイマ-」の運営を預かる@shimura_atsushiが担当します。



普段は自転車を扱うECサイトの運営/開発を担当しておりますが今回はデスクトップアプリの試作に取り組んでみました。


読んでほしい方

今回は私の方で特にこういう方にとターゲットを決めておりません。

取り立てて難しいことはしていないので強いて言うならタイトルから

興味を持っていただいた全ての方になります。


何を作るか?

今回は.NET CoreをLinuxにインストールして自転車情報を管理するサービスを作成してみます。

用意したサービスをデスクトップアプリケーションから利用し、自転車情報を管理するという構成のシステムを作成します。

以下の環境でシステムを開発します。

利用する環境

クライアント
Mac

サーバ
CentOS7

DB
MySQL

言語
C#


.NET Coreを使う


.NET Coreとは?

.NET CoreはWindows/Mac/Linuxなど動作するオープンソースの開発プラットホームです。

コンソール向けのアプリ、Web向けのアプリなどがC#で開発できます。

詳しいことはMicrosoftの資料をごらんください。

.NET Core

今回は.NET Coreによりサービスの開発を行います。

サーバ側であるLinuxに.NET Coreをインストールします。

.NET Coreのインストールは下記リンク環境別にインストール方法の紹介があります。

.NET Core SDK

Microsoftが公式のDockerイメージを用意してくれています。こちらを利用する方が環境構築は楽かもしれません。

.NET Core Docker

お好きな方を選択してください。

ちなみに今回の私の環境はDocker上のLinuxに.NET Coreをインストールしたものを利用してます。

※執筆中に.NET Coreの公式Dockerの存在を知りました。


とりあえず「Hello World」

.NET Coreのインストールが済んだら、例によって「HelloWorld」を試してみます。

新規にプロジェクトを作成して「HelloWorld」を実行してみます。

# dotnet new console -n HelloWorld

コマンドを実行すればプロジェクトに必要なファイル群が作成されます。

consoleとあるのは「コンソールアプリのテンプレートでプロジェクトを作成してね」ということです。

更に'-n'オプションで指定した内容でディレクトリを作成し、その配下にプロジェクトを展開してくれます。

 HelloWord/

┣ Program.cs
┣ bin
┣ Helloworld.csproj
┗ obj

エントリポイントは「Program.cs」です。

「Program.cs」を開いてみます。


Program.cs

using System;

namespace Helloworld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}


内容をみると既に「HelloWorld」を出力するプログラムが記述されているので今回はこのまま実行してみます。

# dotnet run 

Hello World!

労せずして「HelloWorld」ができました。



これらの作業と後述のサービス作成はVisualStudioを利用することでも可能です、お好みに応じて利用してみてください。

VisualStudio


MySQLを使う

サービスで利用するデータベースにMySQLを利用します。


MySQLのインストールなど導入に関する情報は溢れていると思いますので今回はスキップします。

MySQLへアクセスするためにはそのためのライブラリが必要なのでNuGetを利用してMySQLにアクセス可能なライブラリを用意します。

NuGet, MySQL.Data

プロジェクトの格納ディレクトリで以下ライブラリを追加するコマンドを実行します。

# dotnet add package MySql.Data --version 8.0.13

*.csprojファイルを開くとMySql.Dataのライブラリが追加されていることがわかります。


mysql.csproj

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MySql.Data" Version="8.0.13" />
</ItemGroup>

</Project>


これでMySQLを利用する環境は整ったはずです、次は実際にMySQLへのアクセスを試します。


MySQLへのアクセスを試す

簡単ですが自電車のサンプルのデータを以下のように用意します。

id
名前
価格
メーカID

1
bike_1
10000
0

2
bike_2
14000
0

3
bike_3
20000
1

データを利用するサンプルプログラムは以下の通りです。


Product.cs

using System;

using MySql.Data.MySqlClient;
using System.Data;

namespace BikesAdmin
{
class Program
{
static void Main(string[] args)
{
//MySQLへの接続文字列 
string connstr = "userid=***;
password=***;
database = example;
Host=127.0.0.1";

//MySQLへ接続
MySqlConnection conn = new MySqlConnection(connstr);
conn.Open();

// データを格納するテーブル作成
DataTable ds = new DataTable();
// SQL文と接続情報を指定し、データアダプタを作成
string SQL = "SELECT * FROM bikes;";
MySqlDataAdapter da = new MySqlDataAdapter(SQL, conn);
da.Fill(ds);

foreach(DataRow d in ds.Select()) {
Console.WriteLine(String.Format("{0}, {1}, {2}", d[0], d[1], d[2]));
}
conn.Close();
}
}
}

//# 実行結果
//# 1, bike_001, 10000
//# 2, bike_002, 14000
//# 3, bike_003, 20000


これで.NET Core/C#のプログラムからMySQLを利用することができました。


.NET Coreでサービスを作る

今度はコンソール向けのプロジェクトではなくサービス向けのテンプレートでプロジェクトを作成してみます。

# dotnet new webapi -n BikeAdmin

以上のコマンドでWebapi用のプロジェクトを作成できます。


自転車情報を取得するサービスを作る

MySQLへ登録した自転車情報を取得するサービスを作成します。

自転車情報全件と特定の自転車情報を取得するサービスを作成してみます。

まず、サービスを記述するためのWebApi用コントローラのクラスファイルを作成します。


BikesController.cs

using System;

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MySql.Data.MySqlClient;
using BikeAdmin.models;
using System.Data;
using Newtonsoft.Json;

namespace BikeAdmin.Controllers
{
[Route("bikes")]
[ApiController]
public class BikesController : Controller
{
[HttpGet]
public IEnumerable<string> GetBikeAll() //全件検索
{
BikeAdmin.db.db con = new BikeAdmin.db.db();
con.Open();
string SQL = "SELECT * FROM bikes";
MySqlDataAdapter da = con.execute(SQL);
DataTable dt = new DataTable();
da.Fill(dt);

List<string> bikeList = new List<string>();
foreach(DataRow d in dt.Select())
{
Bikes bikes = new Bikes();
bikes.Id = (int)d[0];
bikes.Name = (string)d[1];
bikes.Price = (int)d[2];
bikes.MakerId = (int)d[3];
string json = JsonConvert.SerializeObject(bikes);
bikeList.Add(json);
}

return bikeList.ToArray();
}

[HttpGet("{id}")]
public string GetBike(int id) //idによる絞り込み
{
BikeAdmin.db.db con = new BikeAdmin.db.db();
con.Open();
string SQL = "SELECT * FROM bikes";
MySqlDataAdapter da = con.execute(SQL);
DataTable dt = new DataTable();
da.Fill(dt);

string json = null;
foreach (DataRow dr in dt.Select("id = " + id)) {
Bikes bikes = new Bikes();
bikes.Id = (int)dr["id"];
bikes.Name = (string)dr["name"];
bikes.Price = (int)dr["price"];
bikes.MakerId = (int)dr["maker_id"];
json = JsonConvert.SerializeObject(b);
}
return json;
}

以下略



リクエストをする

※.NET Coreのビルドインサーバは5000番ポートを利用します、Dockerを利用する際はコンテナ起動時に5000番ポートを割り当ててください。

ブラウザから

http://localhost:5000/bikes へリクエストしてみます。


getBikeAll.png

DBから自転車情報が全件取得しJSONで返って来ているのがわかります。

http://localhost:5000/bikes/1 へリクエストしてみます。

getBike.png

こちらはIDにより絞り込みされたデータで取得できています。

至極、簡素ではありますが自転車情報を取得するためのWebサービスが出来上がりました。次はこのデータを再利用するアプリを作成していきます。


クライアントのアプリを作る

本来はWindowsFormもしくはWPFでのクライアントアプリの開発をしたいところではありましたが私の手元にWindowsがインストールされた端末がなくMacしかないという都合でCocoaを利用してWebサービスを扱うアプリの開発をします。

VisualStudio for Macを用いればC#を利用したCocoaのアプリを開発することができます。

以下ソースコードがサービスにリクエストしている箇所です。(抜粋)

※jsonを扱うためにJson.NETというパッケージを利用しています、ここではNuGetで取得したものを使用します。


ViewController.cs

        public override void ViewWillAppear()  //・・・(1)

{
string url = "http://localhost:5000/bikes/";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "GET";
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
Stream s = res.GetResponseStream();
StreamReader sr = new StreamReader(s);
string content = sr.ReadToEnd();
List<Bikes.models.Bikes> de = JsonConvert.DeserializeObject<List<Bikes.models.Bikes>>(content);
BikesDataSource bds = new BikesDataSource();
bds.DataSource = de;
BikeTable.DataSource = bds;
BikeTable.Delegate = new BikesTableDelegate(bds);
}

partial void ExecuteRequestBike(NSObject sender) //・・・(2)
{
int id = ReqId.IntValue;

string url = "http://localhost:5000/bikes/" + id + "/";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "GET";
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
Stream s = res.GetResponseStream();
StreamReader sr = new StreamReader(s);
string content = sr.ReadToEnd();
Bikes.models.Bikes de = JsonConvert.DeserializeObject<Bikes.models.Bikes>(content);
BikesDataSource bds = new BikesDataSource(de);
BikeTable.DataSource = bds;
BikeTable.Delegate = new BikesTableDelegate(bds);
}


※サンプルなのでソースコードが重複しているのは容赦ください。

(1)アプリの起動と同時にサービスへリクエストをして車種情報を全件取得しTableViewへ表示します。

getBikeAllforApp.png

(2)画面上のTextFieldにIDを入力してボタンを押下するとID別の車種情報を取得しTableViewへ表示します。

getBikeforApp.png


最後に

今回はクライアント側はCocoaで作成しましたがWindowsFormもしくはWPFを用いたアプリなどのほうが開発がしやすく利便性が個人的に高いように思います。

業務系のアプリを開発する際はデザインを飾ることも少ないと思うのでデスクトップアプリの方がWebアプリのようにCSSやJavascriptを利用しなくてもよくコストが安くなる場合があるのではないでしょうか?

サービスを管理するアプリはこういった技術を利用したものを選択肢として持っておくのもいいと思いました。


Ateam Lifestyle x cyma Advent Calendar 2018、明日も「cyma -サイマ-」の@k_moriに書いてもらう予定です。お楽しみに!

エイチームグループでは、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。興味を持たれた方はぜひエイチームグループ採用サイトを御覧ください。

https://www.a-tm.co.jp/recruit/