Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8901

PHPでC#アプリケーションとデータをやり取りするためのAPIを作ってみる

$
0
0

はじめに

当記事では、C#アプリケーションとデータをやり取りするAPIを作成して実際に動かしてみます。
C#アプリケーションから、ライブラリを使用して直接データベースに接続することも可能ですが、
C#等の高級言語は「リバースエンジニアリングしやすい」といった特徴や、そもそも外部からの接続を許してしまうデータベースはセキュアではないので、基本的にはAPIを通す必要があります。

環境

Visual Studio 2019 Professional
Windows 10 1903
.NET Framework: 4.7.2
XAMPP: 7.3.7
PHP: 7.3.7
Apache: 2.4.39
MariaDB: 10.3.16

データベース

テーブルを新規作成します。
今回は例として以下の構造で作成しました。
23358688b8684b29fe96195c69bfedf5.png

PHP側

今回作成するのは以下3つのファイルです。

class.php
database.php
index.php

PHPのフルソースコードは以下の通りです。
今回はあくまで一例として行いますので、複数のデータが見つかった場合や例外エラーの処理は一切していません。

ソースコード

database.php
<?phpclassdatabase{public$db;private$db_host="localhost";private$db_user="root";private$db_password="";private$db_name="testdb";publicfunctionconnect(){$this->db=newPDO("mysql:host=".$this->db_host.";dbname=".$this->db_name,$this->db_user,$this->db_password);if(!$this->db){die("Failed to connect");}}}?>
class.php
<?phpinclude"database.php";class_main_extendsdatabase{publicfunction__construct(){$this->connect();}publicfunctionInsertData($data){if(empty($data)){die('{"result":"failed"}');}else{$query=$this->db->prepare("INSERT INTO data_table (data) VALUES ('$data')");$query->execute();die('{"result":"success"}');}}publicfunctionGetData(){$query=$this->db->prepare("SELECT * FROM data_table LIMIT 1");$query->execute();$result=$query->fetch(PDO::FETCH_ASSOC);if(isset($result)){$data=$result["data"];die('{"result":"success", "data":"'.$data.'"}');}else{die('{"result":"failed"}');}}}?>
index.php
<?php//ini_set( 'display_errors', 1 );//error_reporting(E_ALL);include"class.php";$main=new_main_;if(isset($_POST['type']))$Type=$_POST['type'];if(isset($_POST['data']))$Data=$_POST['data'];if(isset($Type)){switch(strip_tags($Type)){case"t_insert_data":$main->InsertData($Data);break;case"t_get_data":$main->GetData();break;}}?>

C#側

.NET Frameworkを使用します。
Jsonを扱うので、Newtonsoft Jsonを予めNuGetでインストールして下さい。
18c8268b08b08a0109e7e3c8140708bd.png

ソースコード

using(WebClient wc = new WebClient()) { }としているのは、必ずリソースが破棄されるからです。
NameValueCollectionに値を格納し、それを渡す感じです。
Encoding.Default.GetString(wc.UploadValues(URL, Values));でPOSTし、返ってきた値を関数の返り値としています。
一応、WebExceptionはキャッチします。

Handle.cs
usingNewtonsoft.Json;usingSystem;usingSystem.Collections.Generic;usingSystem.Collections.Specialized;usingSystem.Linq;usingSystem.Net;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Windows.Forms;namespacedatatest{classHandler{//ポスト先のURLpublicstaticstringURL{get;set;}//コンストラクタpublicHandler(){}publicstaticstringDoPost(NameValueCollectionValues){try{using(WebClientwc=newWebClient()){returnEncoding.Default.GetString(wc.UploadValues(URL,Values));}}catch(WebExceptione){MessageBox.Show(e.Message);Dictionary<string,object>ERROR=newDictionary<string,object>();HttpWebResponseresponse=(HttpWebResponse)e.Response;switch(response.StatusCode){caseHttpStatusCode.NotFound:ERROR.Add("result","net_error_not_found");break;caseHttpStatusCode.RequestEntityTooLarge:ERROR.Add("result","net_error_request_entry_too_large");break;caseHttpStatusCode.ServiceUnavailable:ERROR.Add("result","net_error_service_unavailable");break;caseHttpStatusCode.Forbidden:ERROR.Add("result","net_error_forbidden");break;default:ERROR.Add("result","net_error_unknown"+Environment.NewLine+e.Message);break;}returnJsonConvert.SerializeObject(ERROR);}}}}

フォームがロードされたタイミングでハンドラーのURLをセットし、
NameValueCollectionに各値を格納してHandler.DoPost()するだけです。
Stringとして帰ってくるので、JObject.Parse()でパースする必要があります。

Form1.cs
usingNewtonsoft.Json.Linq;usingSystem;usingSystem.Collections.Generic;usingSystem.Collections.Specialized;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Windows.Forms;namespacedatatest{publicpartialclassForm1:Form{publicForm1(){InitializeComponent();}privatevoidForm1_Load(objectsender,EventArgse){Handler.URL="http://localhost/api/index.php";}privatestaticvoidInsertData(stringdata){varvalues=newNameValueCollection();values["type"]="t_insert_data";values["data"]=data;stringresult=Handler.DoPost(values);if(result!=""){varjobj=JObject.Parse(result);switch((string)jobj["result"]){case"success":MessageBox.Show("Success!");break;case"failed":MessageBox.Show("Failed!");break;default:MessageBox.Show("Unknown error!");break;}}}privatestaticvoidGetData(){varvalues=newNameValueCollection();values["type"]="t_get_data";stringresult=Handler.DoPost(values);MessageBox.Show(result);if(result!=""){varjobj=JObject.Parse(result);switch((string)jobj["result"]){case"success":MessageBox.Show("Success!"+Environment.NewLine+"Data: "+(string)jobj["data"]);break;case"failed":MessageBox.Show("Failed!");break;default:MessageBox.Show("Unknown error!");break;}}}privatevoidBtnInsert_Click(objectsender,EventArgse){InsertData("SETO_KOUJI");}privatevoidBtnGet_Click(objectsender,EventArgse){GetData();}}}

実行結果

InsertData
f50400ab75c092e9cca8fee357cbb5b6.png

GetData
18ca9f79fe35d70f50a497c066a4035b.png

無事データのやり取りを行うことができました。
このとき、データベースの中身は以下のようになっています。

e57922efa41d6387cf2f38c3677cc15a (1).png

正しい値を取得できていますね。

最後に

今回は、C#アプリケーションとデータベースでのやり取りにAPIを使用してみました。
APIを使用しても、肝心の通信の中身が暗号化されていなければセキュアであるとは言えないですし、中間者攻撃も容易にできてしまいます。
実際に実装して運用する際は十分な注意を払う必要がありますね。

通信内容の暗号化に関しては、セッションを利用して共通鍵方式で暗号化するのも手段の一つだと思います。


Viewing all articles
Browse latest Browse all 8901

Trending Articles