20200920のC#に関する記事は6件です。

Blazor(C#)をDockerで動かす方法

Blazorとは、

Blazor は、.NET を使って対話型のクライアント側 Web UI を構築するためのフレームワークです。
・JavaScript の代わりに C# を使って、優れた対話型 UI を作成します。
・.NET で記述された、サーバー側とクライアント側のアプリのロジックを共有します。
・モバイル ブラウザーを含めた広範なブラウザーのサポートのために、HTML および CSS として UI をレンダリングします。
・Docker などの最新のホスティング プラットフォームと統合します。
https://docs.microsoft.com/ja-jp/aspnet/core/blazor/?view=aspnetcore-3.1

なるほど、すごいですね。

BlazorをDocker上で動かしてみたのでその手順をまとめたいと思います。

今回はASP.NET Core Blazor のホスティング モデルで構築したいと思います。
ブラウザ側ではWebAssembly ベースの .NET ランタイム(Blazor WebAssembly) が動作してます。

dotnet-3.1.402 docker-19.03.12

まずはプロジェクトを作成します

下記コマンドを実行してください。プロジェクト名はBrazorwasmDotNetCoreHostedWithDockerとしています。

dotnet new blazorwasm --hosted -o BrazorwasmDotNetCoreHostedWithDocker

すると、

キャプチャ.JPG

こんな感じで、サーバ側、クライアント側、共通部分のプロジェクトができるかと思います。

ローカルで動作確認します

cd BrazorwasmDotNetCoreHostedWithDocker
dotnet publish

うまくいっていれば、プロジェクトは以下のServer\bin\Debug\netcoreapp3.1\publishに実行ファイルが出力されているはずです。
その配下にwwwrootがいることを確認してください。そこが公開フォルダとなります。

起動いたします。

cd Server\bin\Debug\netcoreapp3.1\publish
dotnet BrazorwasmDotNetCoreHostedWithDocker.Server.dll

こんな感じでログが出力されます。
キャプチャ.JPG
その中にContent root pathというものがあるかと思いますが、そこがコンテントルートとなり、その下のwwwrootが公開フォルダとなります。

ブラウザ上からhttp://localhost:5000/にアクセスして、下記のようなページが表示されれば成功です。
キャプチャ.JPG

上記と同じことをDocker上でします。

Dockerfile作ります

プロジェクトのトップに下記のようなDockerファイルを作成します。

Dockerfile
# コンパイルします
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env
WORKDIR /app
# 配下のもの全部コピーしてrestoreします
COPY . ./
RUN dotnet restore
# outディレクトリに発行します
RUN dotnet publish -c Release -o out

# 実行用Imageを用意します
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
COPY --from=build-env /app/out .
EXPOSE 80
ENTRYPOINT ["dotnet", "BrazorwasmDotNetCoreHostedWithDocker.Server.dll"]

実行用のイメージに関してですが、
コンテントルートパスはdotnetコマンド実行ディレクトリとなり、/appの直下にwwwrootを持ってくるように設定しております。

Docker buildします

プロジェクト直下まで戻っていただいて、

docker build -t brazorwasmdotnetcorehosted .

こちら実行します。brazorwasmdotnetcorehostedというイメージで作成しています。
docker imagesして、イメージができていれば成功です。
キャプチャ.JPG

Docker runします

docker run -d -p 80:80 brazorwasmdotnetcorehosted:latest --rm

http://localhost/にアクセスすれば、先ほどのページが表示されるはずです。

ちなみにスタンドアローン(静的コンテンツのみ)の場合は

最初のプロジェクトを作るときに、

dotnet new blazorwasm -o BrazorwasmDotNetCoreStandAloneWithDocker

とし、Dockerfileで構築すればいけます。nginxで動かしています。

Dockerfile
# コンパイルします
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env
WORKDIR /app
# 配下のもの全部コピーしてrestoreします
COPY . ./
RUN dotnet restore
# outディレクトリに発行します
RUN dotnet publish -c Release -o out

FROM nginx:alpine
EXPOSE 80
COPY --from=build-env /app/out/wwwroot /usr/share/nginx/html
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WPF の OverridesDefaultStyle プロパティの内容

はじめに

WPF の FrameworkElement.OverridesDefaultStyle プロパティの内容が、MSDNの説明を読んでもよく分からなかったので、それを調べた時のメモです。

FrameworkElement.OverridesDefaultStyle プロパティ - MSDN

解説

以下の Stack Overflow のページに書いてありました。

OverridesDefaultStyle in WPF - Stack Overflow

上記によると、コントロールのデフォルトスタイルを無視するために使用するとのことです。
デフォルトでは、コントロールをUIに配置すると、そのコントロール内で設定していない全てのプロパティの値がデフォルトスタイルから取得されます。
OverridesDefaultStyleをtrueに設定することで、デフォルトのスタイルから値を取得されないようにする用途のようです。

日本語記事だと、現在(2020年)ではAzureの記事で有名な「しばやん雑記」の人が、2008年に以下の投稿をしていました。

Template を指定していないのに OverridesDefaultStyle = True にすると何も表示されなくなるので注意

WPF メモ (27) - しばやん雑記

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SimpleInjectorで不要なインスタンス生成を抑止する

.NETにはSimpleInjectorという非常に軽量でよくできたDIコンテナがあります。

私はこれを多用しているのですが、その際にインスタンスを1度生成したつもりが複数生成される事象に、悩まされることがありました。システムで一つしか生成しないインスタンスで、そのインスタンス生成時にやや重たい処理をしたかったのですが、実際には2回実行されていました。

SimpleInjectorは次のように利用します。

var container = new Container();
container.Register<Foo>();
container.Register<Bar>();
container.Verify();

var foo = container.GetInstance<Foo>();

SimpleInjectorでは依存性を登録した後、Verifyで登録が不足しているオブジェクトがないかベリファイすることができますが、実はこの時内部でインスタンスが生成されているために、前述のようなインスタンスの複数生成が行われます。

ではVerifyを外せばいいかというと、つぎの二つの問題があります。

  1. 開発時はVerifyしておかないと、不具合の発見が遅れる
  2. Verifyを明示的に呼ばなくても、GetInstanceした際に、Verifyしていなければ自動的に実行される

そのため、つぎのように実装するとよいのではないかと思います。

            var container = new Container();
            container.Register<Foo>();
            container.Register<Bar>();
#if DEBUG
            container.Verify();
#else
            container.Options.EnableAutoVerification = false;
#endif

            var foo = container.GetInstance<Foo>();

Debug実行時は明示的にVerifyを呼び出し、そうではない場合は、AutoVerificationを明示的にOFFにします。

これでReleaseビルドされたモジュールでは不要なインスタンス生成が避けられるはずです。

なおコメントでいただきましたが、登録するインスタンスをSingletonとして登録できる場合は、そちらでも回避は可能だと思います。どちらが向いているか、ケースによって検討してみてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C#でMySQLを使う - 2.SELECTと画面表示編

前提と準備

C#の記事

前回はVisual Studio 2019にMySQL Connectors .NETを用いて、開発環境を準備する作業でしたが、実際にMySQL Connectors .NETでMySQLに接続して、SELECTを用いてデータの内容を画面に表示します(˶ ・ᴗ・ )੭

環境

  • OS:Windows 10 Pro
  • 開発環境:Visual Studio 2019 (MySQL Connectors .NET利用)
  • データベース:MySQL 5.7

前提

前回のように、Visual Studio 2019とMySQLをインストールし、かつMySQL Connectors .NETがインストールされていること(Visual Studioは自動でMySQL Connectorsのライブラリを認識してくれる)

作業手順

Visual Studio 2019でのコーディング

コンポーネント・コントロールの配置

今回はボタンを押下→MySQLでデータを拾ってくる→画面に表示
という、簡単な使い方について記事にしました。

とりあえず、WindowsのC#フォームのプロジェクトを新規作成し、Form1.csがデフォルトで開かれると思うので、まずはフォームに、

  • 左上:データグリッド dataGridView1
  • 右上:リストボックス2つ listBox1・listBox2
  • 左下:SQLを読み込むボタン button1

これらを貼り付けます。
データグリッドとリストボックスはSQLのデータを表示させるために配置しました

コンポーネントの配置

MySQL Connector .NETの参照を追加

前回の記事の通り、参照を追加していきます。

MySql.Data

「アセンブリ」の中に実際自動で認識してくれるので、参照マネージャーで、右上の検索画面に「mysql」を入力すると、↑の画面のように「MySql.Data」が何行も出てくるので、とりあえず1つだけ、どれでもいいので選択して(行左にマウスを当てると出てくるチェックボックスをON)「OK」を選択すると…

MySQLを使う

MySql.Data」が追加されました(*˘꒳˘*)
この中にMySQLを扱うC#オブジェクトが入っているのです。

ボタンクリック時のソースを記述する

今回はSQLをボタンクリックで読み込むだけなので、Form1.csのコード部分だけをコーディングするので、button1コントロールをダブルクリックして、クリックイベントを自動で生成するので、そのイベント動作をコーディングします。

Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MySql.Data.MySqlClient;

namespace MySqlFormsTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /** Visual Studioではボタンコントロールをダブルクリックすると、自動で生成される
         * 接続ボタン(MySQLサーバーに接続し、一覧データを取得する)
         * */
        private void button1_Click(object sender, EventArgs e)
        {
            string connStr = "server=127.0.0.1;user id=test;password=test1;database=manutest";
            MySqlConnection conn = new MySqlConnection(connStr);

            try
            {
                // 接続を開く
                conn.Open();

                // データを取得するテーブル
                DataTable tbl = new DataTable();

                // SQLを実行する
                MySqlDataAdapter dataAdp = new MySqlDataAdapter("SELECT id, name, memo FROM testtb", conn);
                dataAdp.Fill(tbl);

                // データグリッドに表示させる
                dataGridView1.DataSource = tbl;

                // 実行結果を1行ずつ参照する場合
                for (int i = 0; i < tbl.Rows.Count; i++)
                {
                    DataRow row = tbl.Rows[i];  // データ行

                    // 右のリストボックスにアイテムを追加
                    listBox1.Items.Add(row[1]);
                    listBox2.Items.Add(row[2]);
                }

                // 接続を閉じる
                conn.Close();
            }
            catch (MySqlException mse)
            {
                MessageBox.Show(mse.Message, "データ取得エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
}

MySQL ConnectorsのC#に関する公式の根拠が出回っていなかったので、第三者の情報と実際Visual Studioのコーディングでポップアップされるトピックを頼りにするしかなかったのです…( ´ •̥ ̫ •̥ ` )…なので、データの取得に「MySqlDataAdapter」だったり「MySqlCommand」だったり統一されずに混在している状態で、用途もはっきりしていないが、私はMySqlDataAdapterを使っています

string connStr = "server=127.0.0.1;user id=test;password=test1;database=manutest";

これが接続コマンドで、serverはサーバーのホスト、user idにMySQLのID、passwordはパスワード、そしてdatabaseは接続するDB名ですが、他の記事を見ていると、uidだったりUserIdだったり混在していて、あまり統一されていないように見えました。。。

MySqlDataAdapter dataAdp = new MySqlDataAdapter("SELECT id, name, memo FROM testtb", conn);
dataAdp.Fill(tbl);

ここの部分は「SELECT id, name, memo FROM testtb」というSQLを実行し、実行結果をデータテーブルに格納する部分です。

// データグリッドに表示させる
dataGridView1.DataSource = tbl;

この部分は左上のデータグリッドdataGridView1にSELECTで取得したデータを表示することを意味し、DataSourceにSQLを実行したテーブルをセットするだけで簡単に表示できます。

一方、

// 実行結果を1行ずつ参照する場合
for (int i = 0; i < tbl.Rows.Count; i++)
{
    DataRow row = tbl.Rows[i];  // データ行

    // 右のリストボックスにアイテムを追加
    listBox1.Items.Add(row[1]);
    listBox2.Items.Add(row[2]);
}

こんなふうに、取得したテーブルtblの各行は、tbl.Rows[i]で行を取得することができて、その中の各データを配列の形で取り出すことができるんです。このことはC#のMySQLに限らずC#のDataRowやDataTableの話になるのであまり細かいことは触れず。

それぞれの取得した個別のデータを右上のlistBoxに表示させています。

実行結果

表示成功

次回

Visual StudioでMySQLのデータを表示できたので、次はデータの追加や修正、削除を予定しています٩(.› ‹.♡)۶

参考文献

  1. 【Visual Studio】C#からMySqlの使い方 接続するには?SQL文を実行するには? - 困ったー
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Update your C# in Unity ~ nameof ~

Unityにおいて古いC#しか使えない時代もありました。しかし、それは過去のことです。本稿執筆時の最新LTSであるUnity 2019.4ではC# 7.3がサポートされています。また、本稿執筆時の最新Beta版であるUnity 2020.2ではC# 8.0がサポート予定です。

長らくUnityで古いC#しか使えなかったことで、「C#にこんな機能あるのか?知らなかった!」となることがある方も多いのではないでしょうか?この「Update your C# in Unity」シリーズでは、「C#の比較的新しい機能をUnityでこんな風に使えるよ!」という紹介を行います。


言語機能名: nameof
追加バージョン: C# 6.0
説明: 変数名、型名、メソッド・フィールド・プロパティなどのメンバ名を文字列リテラルとして取得する機能

利用例としては

  • SendMessageの第一引数など、メソッド名を求められる箇所で、文字列リテラルべた書きではなくて、nameofを使う
  • SerializedObjectのFindPropertyの第一引数など、フィールド名を求められる箇所で、文字列リテラルべた書きではなくて、nameofを使う

※ 個人的にはSendMessageの利用は避けるべきだと思っています。しかし、どうしようもない理由があって避けられない場合や、漸進的に改善をしていく必要がある場合、まずnameofで小さく改善するのがオススメです。

using UnityEngine;

public class EnemyLauncher : MonoBehaviour
{
    public void LaunchEnemy()
    {
        Debug.Log("Launched");
    }
}
using UnityEngine;

public class GameController : MonoBehaviour
{
    public void Start()
    {
        SendMessage(nameof(EnemyLauncher.LaunchEnemy));
    }
}

SendMessageやFindPropertyのように、メンバ(メソッドやフィールド)の名前を文字列リテラルとして引数にとる場合、コード中に文字列リテラルを直接埋め込むのではなく、nameofを使いましょう。

nameofを使うメリットは、「型名やメンバ名が変わった時に、対応する文字列リテラルの変更を変え忘れることが防止できる」ということです。

仮に、次のように文字列リテラルを直接引数として渡していて、使ってSendMessageを使っていたとします。

using UnityEngine;

public class GameController : MonoBehaviour
{
    public void Start()
    {
        // このように直接文字列リテラルを埋め込むのは避けるべき
        // EnemyLauncher型のLaunchEnemyメソッドの名前が変更された場合、実行時エラーになってしまう
        SendMessage("LaunchEnemy");
    }
}

この時、EnemyLauncher型のLaunchEnemyメソッドの名前が変えたとしましょう。同時に、GameControllerに直接埋め込まれている"LaunchEnemy"という文字列リテラルも変更しないといけません。しかし、これをうっかり変えそびれてしまうことがありえます。その場合、実行時エラーになってしまいます。このような実行時エラーは非常に厄介です。


一方で、次のように今回紹介するnameofを使っていた場合はどうでしょう?
EnemyLauncher型のLaunchEnemyメソッドの名前が変えた場合、GameController内のnameof内でコンパイルエラーになり、問題があることにすぐに気が付けます。
「メソッド名を変えたことが原因」の厄介な実行時エラーになる可能性を排除できます。
また、もしVisual SturioやRiderのリネーム機能でEnemyLauncher型のLaunchEnemyメソッドの名前が変えた場合、nameofの内部も自動的にリネームされ、非常に円滑にコードを編集することができます。

using UnityEngine;

public class GameController : MonoBehaviour
{
    public void Start()
    {
        // EnemyLauncher型のLaunchEnemyメソッドの名前が変更された場合、コンパイルエラーになり、厄介な実行時エラーの原因を事前に気付ける
        // また、IDEのリネーム機能を使った場合、↓の内容もリネーム対象となる
        SendMessage(nameof(EnemyLauncher.LaunchEnemy));
    }
}

このようにnameofを使うメリットは、「型名やメンバ名が変わった時に、対応する文字列リテラルの変更を変え忘れることが防止できる」ということです。


この投稿ではnameofのUnityでの利用例とそのメリットを説明しました。
なお、nameofのC#におけるより一般的な使い方は、INotifyPropertyChangedの実装や、ArgumentExceptionの引数に使うという利用方法です。
Unityにおいても、エラー文・警告文などでも使う場面があると思います。
変数名、型名、メソッド・フィールド・プロパティなどのメンバ名を文字列リテラルとして必要な場面では、積極的にnameofを使っていきましょう。

※ この投稿では、SendMessageを例にnameofを紹介しましたが、個人的にはSendMessageの利用は避けるべきだと思っています。しかし、どうしようもない理由があって避けられない場合や、漸進的に改善をしていく必要がある場合、まずnameofで小さく改善するのがオススメ。


関連・参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ASP.NET Core と launchSettings.json と appSettings.json

はじめに

Visual Studio で、ASP.NET Core のテンプレートを使いコードを生成すると、launchSettings.json と appSettings.json といった構成情報を管理するファイルが生成されます。
これらを活用すると、環境に応じて処理を分岐して記述すること、参照する構成情報を分けて管理できるようになるので、使用用途と使用方法をまとめてみました。

launchSettings.json

launchSettings.json は、端的に言うと起動プロファイルです。デバッガーからプログラムを起動する際の各種設定をプロファイル単位で定義できます。どのプロファイルを適用して起動するかは、デバッガー起動時に指定します。

以下は、ASP.NET Core の launchSettings.json の例です。"IIS Express", "LaunchSettingsDemo", Profile001" といったプロファイルを定義しています。

launchSettings.json
{
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "LaunchSettingsDemo": {
      "commandName": "Project",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "https://localhost:5001;http://localhost:5000"
    },
    "Profile001": {
      "commandName": "IISExpress",
      "launchBrowser": true
    }
  }
}

各プロファイル毎の commandName では、起動する Web サーバーを指定します。

  • IISExpress - IIS Express を起動します。(Visual Studio 2019 ではデフォルトで設定されます。)
  • IIS - IIS を起動します。
  • Project - Kestrel Web サーバーを起動します。

Kestrel Web Server は、ASP.NET Core 用のクロス プラットフォーム対応 Web サーバーです。
以下のサイトに説明があります。Linux, MacOS 環境でも利用できます。

"launchBrowser" は、ブール値を指定し、デバッガー起動時に、ブラウザを起動するかをブール値で指定します。
"environmentVariables" が重要で、環境変数と値を設定できます。ここで、"ASPNETCORE_ENVIRONMENT" の値を設定することで、実行環境の定義を行います。
"ASPNETCORE_ENVIRONMENT" に設定する値は、任意の値を設定可能ですが、以下の値が定義されています。

  • Development - 開発環境
  • Staging - ステージング(本番環境へ展開前のリハーサル)環境
  • Production - 本番環境

これらの値を定義しないと、Staging として扱われます。

起動プロファイルの選択

どのプロファイルから起動するかは、Visual Studio の場合は、デバッグ実行ボタンから選択できます。
起動プロファイルの設定

.NET Core CLI の場合は、run の --launch-profile オプションで、プロファイル名を指定します。

dotnet
dotnet run --launch-profile <プロファイル名>

ASPNETCORE_ENVIRONMENT の参照

ASPNETCORE_ENVIRONMENT 環境変数の設定値は、IHostingEnvironment.EnvironmentName プロパティから参照できます。また、IHostingEnvironment の拡張メソッド、IsDevelopment, IsStaging, IsProduction, IsEnvironment を使って、現在の環境に応じた処理を記述できます。

ASP.NET Core のコントローラー、PageModel からこれらを参照するには、依存性の注入がされた IWebHostEnvironment のインスタンスをコンストラクター経由で取得、参照を保存し、利用します。
この例では書いてないですが、ASPNETCORE_ENVIRONMENT に任意の名前を定義した場合は、IsEnvironment(string environmentName) で評価することもできます。

Index.cshtml.cs
public class IndexModel : PageModel
{
    public string Message;

    private readonly IWebHostEnvironment _env;
    private readonly ILogger<IndexModel> _logger;

    public IndexModel(IWebHostEnvironment env, ILogger<IndexModel> logger)
    {
        this._env = env;
        this._logger = logger;
    }

    public void OnGet()
    {
        if (this._env.IsDevelopment())
        {
            this.Message = "I'm Development.";
        }
        else if (this._env.IsStaging())
        {
            this.Message = "I'm Staging.";
        }
        else if (this._env.IsProduction())
        {
            this.Message = "I'm Production.";
        }
        else
        {
            this.Message = "I'm Others.";
        }
    }
}

Razor(*.cshtml) での場合でも、もちろん依存性の注入と拡張メソッドで同様のコードを記述できます。

Index.csthml
@page
@using Microsoft.Extensions.Hosting
@using Microsoft.AspNetCore.Hosting
@inject IWebHostEnvironment HostEnvironment
@{
    string Message;

    if (HostEnvironment.IsDevelopment())
    {
        Message = "I'm Development.";
    }
    else if (HostEnvironment.IsStaging())
    {
        Message = "I'm Staging.";
    }
    else if (HostEnvironment.IsProduction())
    {
        Message = "I'm Production.";
    }
    else
    {
        Message = "I'm Others.";
    }
}

Razor(*.cshtml) では、environment 要素により環境に応じたレンダリングの分岐ができます。
以下の例では、開発環境の場合には、jquery.js を参照し、それ以外の場合は、jquery.min.js を参照しています。

_Layout.cshtml
<environment include="Development">
    <script src="~/lib/jquery/dist/jquery.js"></script>
</environment>
<environment exclude="Development">
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
</environment>

appSettings.json

appSettings.json は、アプリの構成情報を管理できます。定義したキーと値の取得方法は以下で説明してます。

ポイントは、ASPNETCORE_ENVIRONMENT 環境変数によって、参照する appSettings.json を変えることができます。
ファイル名を appSettings.%ASPNETCORE_ENVIRONMENT%.json といった書式にすることで、参照先の構成情報を変えることことができます。

  • appSettings.json
  • appSettings.Development.json
  • appSettings.Staging.json
  • appSettings.Production.json

対応する環境変数が含まれたファイルがない場合は、appSettings.json が参照されます。

まとめ

launchSettings.json は、起動プロファイルの定義。デバッガー起動時にどのプロファイルを使用するか、指定できます。起動プロファイルの主な役割は、ASPNETCORE_ENVIRONMENT 環境変数の定義。
appSettings.json は、アプリの構成情報の定義。ASPNETCORE_ENVIRONMENT の定義により、参照先のファイルを変更できます。

launchSettings.json、appSettings.json を使用しなくても、すべてを環境変数で管理できますが、json ベースで構成情報を設計すると、階層的に構成情報を定義でき、管理がしやすくなると考えます。

参考サイト

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む