こんにちは。MGKです。
最近 .Net関連ニュースでVisual Studio Code用のDevKit Previewがリリースされたそうで、ますますVSCodeが便利になっていくことになりそうです。DevKitがあればVisual Studioがなくても簡単なアプリケーションは作れるようになるかもしれません。特に.Net SDKがOpenSourceとして公開されてからはバッチプログラムなどはVisual Studioがなくても作成できるようになりました。バッチ開発ならVSCodeの方が軽くて快適な開発環境かもしれません。
VS Codeで.Net SDKのコンソールアプリケーションの開発について基礎的な内容は他ブログでもよく見かけますが、DB接続やデプロイ方法など最初から最後までまとまった記事がなかったので、いろいろ調べて整理をしました。

今日のゴールは
・開発環境構築
・DBからデータを取得
・Windowsで実行
・Linuxで実行
となります。
では、はじめます。

1. Install Visual Studio Code

まず、Visual Studio Code(以下、VS Code)をインストールします。

https://code.visualstudio.com/

2. Install .Net SDK

https://dotnet.microsoft.com/ja-jp/download/dotnet/6.0

コンパイルに必要な.Net SDKをインストールします。
2023/06/09現在安定バージョンは .net SDK 6.0.408です。このバージョンをインストールします。

Windows x64をインストールします。

Windows上で実行できるようRuntimeをインストールします。

3. プロジェクトフォルダーを作成する

アプリケーションのプロジェクトフォルダーを作成します。

Windows エクスプローラーを開き、フォルダーを作成します。

例)C:\workspace\vscode\GetData
C:\workspace\vscode
↑ベースになるパス

GetData
↑プロジェクトフォルダー

(プロジェクト名はプログラムの内容にあわせた名前にしましょう。)

4. VS Codeを起動

VS Codeを起動して、プロジェクトフォルダーを開きます。

File -> OpenFolder

5. Install C# extension

VS CodeにC#をインストールします。

つづいて、NuGet Package Managerをインストールします。
NuGet Package ManagerはMysqlなど各種ライブラリをインストールするとき便利です。

6. Terminal 設定

View -> Terminalメニューをクリックして、VS CodeでTerminalを起動します。

下記のようにTerminalが起動されます。

この状態で「dotnet new console」と入力します。

このコマンドは現在のフォルダーをC#プロジェクトフォルダーとして使用するという意味です。
Enterを押して実行すると、空だったフォルダーにC#プロジェクトファイルが生成されます。

7. Program.cs

Programe.csファイルを開いてみましょう。

初期コードとして「Hello,World!」を出力するコードが生成されています。

このまま、Program.csを実行してみます。

Program.csを実行するには先と同じくTerminalで「dotnet run」コマンドを入力します。

Hello, World!が出力されました。

※毎回、コマンドを入力して実行するのは手間なので実行を楽にするように設定を行います。
Ctrl + P (または Ctrl + g)を押してVS Codeの検索窓を開きます。
入力欄に「>.Net」を入力します。

上記のように「.NET : Generate Assets for Build and Debug」というメニューがあります。
このメニューをクリックします。

左のように .vscodeというフォルダーが生成されます。
中には launch.json, tasks.jsonというファイルがあります。
このプロジェクトの設定ファイルとなります。

Program.csに戻って、F5キーを押してみます。


先よりは出力されるログの量は多くなりましたが、問題なくHello,World!が出力できました。
これからF5キーを押すことで実行とデバックができます。

8. Mysqlデータベースに接続する

Mysqlデータベースに接続するにはMysqlライブラリをインポートする必要があります。

F1でコマンドパレットを開いて nugetを入力して、Nuget Package Manager : Add Packageを選択します。

検索キーワードに Mysql.Dataを入力してEnter

表示された候補からMysql.Dataをクリック

一番最新バージョン 8.0.33をクリックします。

右下に成功メッセージが表示されます。

これでMysqlデータベースへ接続できるようになりましたが、SQLを実行するためにO/Rマッパーのライブラリをインポートして置きます。

Nugetから Dapperを検索してインストールしましょう。手順は同じです。
最新バージョン2.0.123をインストールします。

9. データ取得クラスの追加

サンプルとして簡単にユーザ情報を取得するプログラムを作ってみます。

プロジェクトにクラスを追加します。

プロジェクトのエクスプローラー空いてるところをマウス右クリックし、New Fileをクリック
ファイル名 GetUserData.cs を入力しEnterします。

新しく追加したクラスにコードを作成します。ここからは通常のC#プログラムとなります。

using Dapper;
using MySql.Data;
using MySql.Data.MySqlClient;
using System.Data;
using System.Diagnostics;
using System.Text;


namespace GETDATA{


    public class GetUserData{
        private static string dbconnection_string = "";    


        public void Main(string param){
            dbconnection_string = MakeConnectionString("{your ip}", 3306, "{your db}", "{your id}", "{your pass}");


            string ask_user_id = "admin";
            if(!string.IsNullOrEmpty(param)){
                //パラメータがあったら置換する。
                ask_user_id = param;
            }
            StringBuilder sql = new StringBuilder();
            sql.AppendLine($" SELECT ");
            sql.AppendLine($" user_id ");
            sql.AppendLine($" ,user_name ");
            sql.AppendLine($" FROM ");
            sql.AppendLine($" table_user ");
            sql.AppendLine($" WHERE ");
            sql.AppendLine($" user_id = '{ask_user_id}' ");
            using(DataTable dt = select_mysql(sql.ToString(),dbconnection_string)){
                if(dt != null && dt.Rows.Count > 0){
                    Console.WriteLine("user_id = " + dt.Rows[0]["user_id"].ToString());
                    Console.WriteLine("user_name = " + dt.Rows[0]["user_name"].ToString());
                }
                else{
                    Console.WriteLine("該当するユーザ情報がありません。");
                }
            }
        }


        /// <summary>
        /// DB接続文字列作成
        /// </summary>
        /// <param name="server"></param>
        /// <param name="port"></param>
        /// <param name="database"></param>
        /// <param name="uid"></param>
        /// <param name="pw"></param>
        /// <param name="isOdbc"></param>
        /// <returns></returns>
        private string MakeConnectionString(string server, int port, string database, string uid, string pw)
        {
            var builder = new MySqlConnectionStringBuilder();
            builder.Server = server;
            builder.Port = (uint)port;
            builder.UserID = uid;
            builder.Password = pw;
            builder.Database = database;
            builder.ConnectionLifeTime = 600;
            builder.ConnectionTimeout = 180;
            builder.DefaultCommandTimeout = 180;
            builder.CharacterSet = "utf8";
            builder.SslMode = MySqlSslMode.Disabled;
            builder.ConvertZeroDateTime = true;
            return builder.ConnectionString;
        }
        /// <summary>
        /// Data取得
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="dbconnect_string"></param>
        /// <returns></returns>
        private DataTable select_mysql(string sql, string dbconnect_string)
        {
            var dbConn = new MySqlConnection();
            dbConn.ConnectionString = dbconnect_string;
            Debug.WriteLine(sql);
            var dt = new DataTable();
            try
            {
                if (dbConn.State != ConnectionState.Open)
                    dbConn.Open();
                else if (dbConn.State == ConnectionState.Broken)
                {
                    dbConn.Close();
                    dbConn.Open();
                }
                dt = new DataTable();
                dt.TableName = "dt";
                dt.Load(dbConn.ExecuteReader(sql));
                Debug.WriteLine(" >RESULT: " + dt.Rows.Count);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
            finally
            {
                if(dbConn != null && dbConn.State != ConnectionState.Closed){
                    dbConn.Close();
                }              
                if(dbConn != null) {
                    dbConn.Dispose();
                }                
            }
            return dt;
        }
    }
}

重要なところだけ説明します。

Main()

ユーザテーブルに接続して、ユーザIDと名前を取得するメインメソッドです。

MakeConnectionString(string server, int port, string database, string uid, string pw)

Mysqlに接続するためのコネクション文字列を生成します。

DataTable select_mysql(string sql, string dbconnect_string)

SQLを実行してDataTable結果を返します。

「admin」というUser IDを渡して結果が取得できたら User IDとUser Nameを出力するプログラムです。

次はProgram.csから新しいメソッドの呼び出しを追加します。

using GETDATA;


string param = "";
if(args.Length > 0){
    param = args[0];
}
GetUserData gud = new GetUserData();
gud.Main(param);

argsは外部からもらったパラメータとなります。
複数のパラメータを渡す場合は半角スペース区切りにします。

内容はシンプルでどこにもありそうな内容なので、難しくないと思います。

では実行してみましょう。
先程設定をしたので、F5キーを押して実行とDebugを行います。

正しく、結果が取得できました。

9. リリースモードのコンパイル

作成したプロジェクトをLinuxにデプロイするためを準備を行います。
Windows上実行することも可能ですが、バッチプログラムなのでLinuxで実行するのが効率がいいでしょう。
規定のBuildはDebugモードになってますので、Releaseオプションをつけてコンパイルを行います。

Terminalから下記のコマンドを実行します。

dotnet publish --configuration Release

Releaseモードでのコンパイルができます。

エクスプローラーを起動してファイル構成を確認してみましょう。

bin の配下にReleaseフォルダーが生成されていることがわかります。

NugetでインポートしたMysql.Data.dllも追加されています。

プロジェクト名と同じGetData.dllが実行ファイルとなります。

コンパイルされた GetData.dllをWindows上で実行してみます。
Terminalから下記のコマンドを実行します。

dotnet C:\workspace\vscode\GetData\bin\Release\net6.0\publish\GetData.dll

パラメータを渡すこともできます。 GetData.dllの後ろに半角スペースを開けてパラメータを指定します。

dotnet C:\workspace\vscode\GetData\bin\Release\net6.0\publish\GetData.dll system

もちろん、結果なしも実行できます。

これでコンパイルされたプログラムは正常に動作することが確認できました。

次はLinuxへデプロイをしてみます。

やり方は簡単です。同じくLinuxサーバに.Net6をインストールし、デプロイしたいディレクトリに「publish」配下のファイルをコピーするだけです。

.Net6のインストールは次のサイトを参考してください。Linux に .NET をインストールする

以下はCentOSへのインストール方法です。

sudo rpm -Uvh https://packages.microsoft.com/config/centos/6/packages-microsoft-prod.rpm
dnf install -y dotnet-sdk-6.0

実行はwindowsと同様「dotnet {ビルドパス}/GetData.dll {パラメータ}」で実行します。

[batch]$ cd GetData
[GetData]$ ll
合計 6748
-rw-rw-r-- 1 3318504 10月 19  2021 BouncyCastle.Crypto.dll
-rw-rw-r-- 1  202752 11月  3  2021 Dapper.dll
-rw-rw-r-- 1   21066  6月  9 17:06 GetData.deps.json
-rw-rw-r-- 1    7680  6月  9 17:22 GetData.dll
-rw-rw-r-- 1  147968  6月  9 17:22 GetData.exe
-rw-rw-r-- 1   11528  6月  9 17:22 GetData.pdb
-rw-rw-r-- 1     253  6月  9 17:06 GetData.runtimeconfig.json
-rw-rw-r-- 1  409368 10月 26  2022 Google.Protobuf.dll
-rw-rw-r-- 1   80384  1月  7  2023 K4os.Compression.LZ4.Streams.dll
-rw-rw-r-- 1   67072  1月  7  2023 K4os.Compression.LZ4.dll
-rw-rw-r-- 1   13312 11月  9  2022 K4os.Hash.xxHash.dll
-rw-rw-r-- 1   23112 11月 15  2019 Microsoft.Win32.SystemEvents.dll
-rw-rw-r-- 1 1194496  4月 13 09:31 MySql.Data.dll
-rw-rw-r-- 1  380848 11月 21  2017 System.Configuration.ConfigurationManager.dll
-rw-rw-r-- 1  143408  9月 19  2018 System.Drawing.Common.dll
-rw-rw-r-- 1   79512  4月 14  2022 System.IO.Pipelines.dll
-rw-rw-r-- 1   24880  7月 19  2017 System.Security.Cryptography.ProtectedData.dll
-rw-rw-r-- 1   92536 11月 15  2019 System.Security.Permissions.dll
-rw-rw-r-- 1   71312 10月 19  2022 System.Text.Encodings.Web.dll
-rw-rw-r-- 1  543920 11月 19  2022 System.Text.Json.dll
-rw-rw-r-- 1   25976 11月 15  2019 System.Windows.Extensions.dll
drwxrwxr-x 6    4096  8月 22 10:12 runtimes
[GetData]$ dotnet GetData.dll system
user_id = system
user_name = 自動処理 システム
[GetData]$ 

デプロイ環境がWindowsからLinuxに変わっただけで、設置やデプロイ、実行はほぼ同じです。

実行環境によってデプロイ難易度が変わる他の言語よりどのプラットフォームでも同じやり方、低い難易度で実装できることも.Netの強みだと思います。

Linuxの初心者でも特に難しいスクリプトやインストール手順を知らなくても「.Net SDK」と作成したソースさえあれば、プログラムを実行することが可能です。

 

最後に

リバークレインでは非エンジニア社員のテック担当部署があります。
専用のデータベースサーバから各自日々覚えたSQLを実行して売上情報の分析やお客様お問い合わせのパターン分析など自部門で必要な集計などの分析やKPI取得を自力で取得しています。ただ、独学が多いため効率よく開発ができない。開発環境の構築などどうすればいいのかわからない方が多いです。中にはPython使ってかなり進んだプログラムを作ってるメンバーもいれば、SQLだけでなんとか頑張ってる人もいます。なんかより効率的にプログラムを構築したいメンバーに.Net エンジニアからの贈り物のような感じでこの記事を作成してみました。

ほかにもVisual Stuidoのように高価なソフトウェアを購入しなくてもC#とVSCodeを利用して効率よくプログラムを作成したい方に役に立つといいかと思います。

次回はASP.NET Core MVCプロジェクトの作り方について作成したいと思います。
C#言語さえあれば、簡単な構成で好きなWebサイトを作成することができます。

That`s All!