.net coreでの設定ファイル読み込み

.net coreで設定ファイルを読み込むには通常、下記パッケージを使用する。

Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.Binder
Microsoft.Extensions.Configuration.Json

上記はJSON形式で定義された設定ファイルを読み込むもの。
JSON形式の設定ファイルは下記のような感じで定義する。

{
    "ConnectionStrings": {
        "MyConnection" : "Data Source=..."
    },
    "MySettings": {
        "String" : "Hello",
        "NUmber" : 100
    }
}

設定値を参照するには、ConfigurationBuilderクラスを使用して、IConfiguraionRootのインスタンスを作成し、GetSectionメソッドおよびGetValueメソッドを用いて値を取得することが可能。
なお、接続文字列(ConnectionStrings)に関しては上記を用いずにGetConnecitonStringsを使用することが可能。

// 設定値の取得
var config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .Build();
// MySettingsセクションの"String"の値を取得
string s = config.GetSection("MySettings").GetValue<string>("String");
// MySettingsセクションの"Number"の値を取得
int i = config.GetSection("MySettings").GetValue<int>("Number");
// 接続文字列"MyConnection"の値を取得
string strCon = config.GetConnectionString("MyConnection");

上記では、実行ファイルと同じ場所にappsettings.jsonというファイル名で定義ファイルが置いてあるという想定。フォルダが実行ファイルと異なる場所にあれば、AddJsonFileメソッドを呼び出す前に、    SetBasePathメソッドでディレクトリを指定する。

以上、忘れないようにメモ。

カテゴリー: C#, dotnetcore, 技術系 | コメントする

blazor wasm(hosted)とSignalR

以前、同じようなタイトルで、asp.net core blazor wasm版とSingalRの話を投稿した様な気がするが、blazor wasm版から既存のHubに接続できず、色々試したのだが、結局解決しなかった。

やはり、現状ではhostedプロジェクトとして作成し、同一ドメインでのみしかSignalRを利用できないようだ。

なので、とりあえず、hostedプロジェクトを試してみた。
まず、下記コマンドで、クライアントとサーバプロジェクトを作成する。

dotnet new blazorwasm --hosted -o <ソリューション名>

ソリューションフォルダ下に下記プロジェクトフォルダが作成される。

  • Client-blazor wasm プロジェクト
  • Server-asp.netプロジェクト
  • Shared-共通DLLプロジェクト

ClientプロジェクトにはSharedプロジェクトの参照が含まれ、ServerプロジェクトにはSharedプロジェクトとClientプロジェクトの参照が含まれる。つまり、共通クラスやInterface等はSharedプロジェクトに定義しておけば、Client/Server双方から参照出来るようになっている。

ServerプロジェクトにHUB本体を作成し、HubのEndpoint定義をして、ClientプロジェクトにSignalRクライアントライブラリを追加し、

dotnet add Client package Microsoft.AspNetCore.SignalR.Client

下記要領でHubに接続するコードを書くことで、ServerのHubに接続できるようになる。

    private HubConnection con;
          ・・・
            con = new HubConnectionBuilder()
                .WithUrl(NavigationManager.ToAbsoluteUri("/[ハブのエンドポイント]"))
                .Build();
           ・・・
            // 接続
            await con.StartAsync();

後はServerプロジェクトを起動して、ブラウザからアクセスするだけ。
もちろん、blazor server side版やWindows FormsなどからもこのHubに接続できる。

詳しくは、MSのサイト「Blazor WebAssembly で ASP.NET Core SignalR を使用する」をどうぞ。

正式リリース版では是非とも、既存サイトのHUBに接続できるようになって欲しいな。

カテゴリー: asp.net core, Blazor, C#, dotnetcore, SignalR, 技術系 | コメントする

blazor serverside apache httpdメモ

まぁ、当たり前の話だが、apache上でサーバのサブディレクトリとして、blazor server sideを動作させるには、それ用のサービスと、リバースプロキシ設定が必要。

また、WebSocketのためのリライトルールが必要となる。
以下のような感じ。

http://・・・/blazorappをhttp://localhost:5010/ にマッピングする。

<VirtualHost *:80>
        DocumentRoot /var/www/html
        ServerName ・・・
    
    ProxyPass /blazorapp http://localhost:5010/
    ProxyPassReverse /blazorapp http://localhost:5010/
    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule /blazorapp/(.*) ws://localhost:5010/$1 [P]
</VirtualHost>

※kestrelサービスはlocalhost:5010で口を開けて待っているという想定。(appsettings.jsonにて指定するとかネ。)

[[Service定義ファイル]]

[Unit]
Description=<サービスの説明>
[Service]
WorkingDirectory=/<working directory path>
ExecStart=/usr/bin/dotnet /<dllパス>/<アプリケーション名>.dll
Restart=always
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=<アプリケーション名>
User=apache
Environment=ASPNETCORE_ENVIRONMENT=Production
[Install]
WantedBy=multi-user.target
[[appsettings.json]]

{
  "Kestrel" : {
        "EndPoints" : {
                "Http" : {
                        "Url" : "http://localhost:5010"
                 }
         }
  },
     ・・・
}

一応、動作確認済み。でも、Websocketの箇所は少々、自信無し・・・
後で別のサービスを追加して確認してみよう・・・

カテゴリー: asp.net core, Blazor, dotnetcore, 技術系 | 1件のコメント

asp.net core webapi

ASP.NET CoreにはRESTful Web APIを作成するためのテンプレートが用意されている。
作成するには以下のように、プロジェクトテンプレートとして、webapiを指定する。

dotnet new webapi -o プロジェクトフォルダ

ASP.NET CoreのWeb APIはhttp要求を受け取って、結果をJSON形式で返す。

APIの実装にはhttp要求のメソッド毎に呼び出すインスタンスメソッドを定義するだけで良い。

簡単な例

プロジェクトフォルダ下のControllersフォルダに<コントローラ名>Controller.csと言う形でファイルを作成すると、”http://・・・/UserInfo”というURLを持つWeb APIが作成される。

UserInfoController.cs

namespace WebAPITest.Controllers
{
    [ApiController] // APIコントローラであることを宣言
    // ルーティングを設定
    // この例では、http://・・・/UserInfo [controller]はクラス名から
    // Contrllerを取り除いたものに置換される
    // 仮想ディレクトリの階層を変える事も可能。例えば、apiの下
    // (http://・・・/api/UserInfo)としたければ、
    // [Route("api/[controller]")]
    // コントローラ名と全く異なるURLにする事も可能
    [Route("[controller]")]
    public class UserInfoController : ControllerBase
    {
        // パラメータ無しGETの処理
        // http://・・・/UserInfo/
        [HttpGet]
        public List<UserInfoItem> GetUserList()
        {
            // ユーザー情報リストを取得
            var lst = ・・・.ToList();
            return lst; // 自動的にJSONに変換される
        }
        // パラメータidありの処理。
        // 例 GET http://・・・/UserInfo/5
        [HttpGet("{id}")]
        public UserInfoItem GetUserInfo(int id)
        {
              // 指定されたIDを持つユーザー情報を取得
              var u = ・・・・.FirstOrDefault();
              if (u == null) {
                  // ControllerBaseに定義されている。
                  // HTTPヘッダ Status 404: Not Foundを返す
                return NotFound();
              } else {
                  return u; // 自動的にJSONに変換される
              }
          }
    }
}

この例ではGETリクエストのみだが、POSTやPUT,DELETEも実装可能。

例えば、[HttpDelete(“{id}”)]のような属性を付けると、

DELETE /UserInfo/5

のようなURLをハンドリングするメソッドとなる。
(通常は削除要求処理を実装だよね)

以上のようにかなり簡単にRESTful Web APIが実装できる。

詳しくは下記URLを参照
https://docs.microsoft.com/ja-jp/aspnet/core/web-api/?view=aspnetcore-3.1

カテゴリー: asp.net core, C#, dotnetcore, 技術系 | コメントする

blazor wasmとSignalR

blazor wasm版でSignalRを使用する場合に注意しなくてはならない事。
wasm版はバックエンドとしてブラウザのhttp送受信機能を使用するので、HUB側とドメインが異なる場合にHUB側でCORS設定をしておかないとHubConnection.StartAsyncを呼び出した時点で実行時エラーとなる。

どうやら、ヘッダに関しての物らしく、以下のようにAllowAnyHeader()を追加したところ、接続が完了し、クライアント側が正常に動作するようになった。(Originだけではエラー回避できない)

            services.AddCors(options => {
                options.AddPolicy("AllowAnyHostsPolicy",
                    builder => {
                        builder.WithOrigins(・・・)
                        .AllowAnyHeader();
                    });
            });

動かない理由を把握するの少々手こずったので、メモ。

カテゴリー: asp.net core, Blazor, C#, dotnetcore, SignalR, 技術系 | 3件のコメント

blazor WASM版をIISへ公開

blazor WASM版のIISへ公開するには、まず、URL Rewriteモジュールの導入が必要。導入されていない場合はWeb Platform Installer等でURL Rewrite 2.0モジュールをIISへ追加する。

後は、dotnet publishコマンドで作成された、bin\Relase\<フレームワーク>\publish\*.*をIISが認識できるフォルダーへコピーし、アプリケーションとして登録するだけ。

.wasm等のMIME設定はweb.configに含まれておりまた、URLリダイレクトの設定もこのファイルに含まれているため、URLを指定するだけでWASMアプリが動作する。

カテゴリー: asp.net core, Blazor, dotnetcore, Windows | 1件のコメント

asp.net coreアプリをIISへ公開する

asp.net coreアプリをWindows Serverの標準HTTPDである、IIS(Internet Information Server)へ公開する手順を調べて、実際に公開してみた。(Visual Studioではなく、手動)

まず、IISが動作するサーバに Windows Hosting Bundleをインストールする必要がある。dotnet core 3.1の場合は、このページのWindows Hoting Bundleをダウンロードし、インストール。

次に、asp.net core用のアプリケーションプールを作成。
「マネージコードなし」に指定するのを忘れずに。

後は、IISがアクセス可能なディレクトリを作成して、そこに、

dotnet publish <プロジェクト名> --configuration Release

で作成したファイル(bin\Release\<フレームワーク>\publish\*.*)をコピー。

そのディレクトリをIISのアプリケーションとして登録。
この時、先程作成した、アプリケーションプールを指定する。

これで、公開は完了。
ただし、一度アプリが動作すると、一部ファイルがオープンされっぱなしになるようで、再度コピーしようとすると、netcoreが使用中とのメッセージが出力される事があるが、runtime dllなので無視しても大丈夫だと思うけど、心配ならば、一度アプリケーションプールを再起動してからコピーすれば良い。

カテゴリー: asp.net core, Windows, 技術系 | コメントする

asp.net core Web API CORS

asp.net core Web APIではデフォルトでCORS (Cross Origin Resource Sharing) がディセーブルになっているため、別サイトからアクセスすると、クライアント側でエラーが発生してしまう。

CORSを有効にするには、Startup.csに以下のような、設定が必要となる。

public IConfiguration Configuration { get; }
public Startup(IServiceConfiguration configuration) {
  Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
  // CORSポリシーの追加
  services.AddCors(options =>
  {
    options.AddPolicy("AllowAllOriginsPolicy", // 名前は何でも良い
      builder =>
      {
        // この例では全ホストから受付け可能(どうせ、FWでブロックされるし・・・)
        // ホストを制限するには、.WithOriginsメソッドを使用
        // ヘッダを制限するには、.WithHeadersメソッドを使用
        // HTTPメソッドを制限するには、.WithMethodsメソッドを使用
        builder.AllowAnyOrigin();
       });
  });
  services.AddControllers();
}

↑の例では、全てのホストからの接続を許可している。
特定のホストだけ許可するには、.WithOriginsを使用する。

    builder.WithOrigins("http://boo.foo.com","http://www.boo.foo.com");

後は、Configuraメソッドの中で、全てのエンドポイントに適用するか、エンドポイント毎に適用するかによって、指定が異なる。
全てのエンドポイントに適用するには、Configureメソッドの中で、

  app.UseCors();

を呼び出す。

詳しくは、

https://docs.microsoft.com/ja-jp/aspnet/core/security/cors?view=aspnetcore-3.1

を参照。

カテゴリー: asp.net core, C#, dotnetcore, 技術系 | コメントする

SignalRについて

この間SignalRで云々というエントリを投稿したが、SignalRそのものの説明が無かったので、簡単に説明しておこうかと。

SignalRはasp.net coreアプリとして、HUB(サーバ)を作成することにより、複数のクライアントとHUB間でメッセージのやりとりを行う事ができる仕組み。

クライアント用ライブラリは.net,java,javascriptが用意されている。

クライアントから、HUBに接続し、下記のような事を行う事が可能。

  • サーバからのPush配信
  • クライアントからHUB経由で全クライアントまたはグループ内クライアントへメッセージ一斉送信
  • クライアントからHUB経由で特定のクライアントへメッセージ送信

実装想定例としては、

  • サーバからの高頻度の更新を必要とするアプリ、例えばGPSを利用した位置特定および周辺情報のリアルタイム表示
  • システム監視アプリ
  • チャットなどのコミュニケーションアプリ
  • ホワイトボードなどのコラボレーションアプリ

仕組みとしては、クライアント~HUB間の接続を行った後、RPCを用いて、クライアント側からHUBのプロシジャ(実装はメソッド)を実行したり、クライアント側でHUBからのメッセージ受信イベントハンドラ(メッセージ毎に定義可能)を定義して、特定処理を行う。

簡単な例を挙げると、以下のような感じでチャットアプリのようなものを作成することが可能。

HUB側
// HUBに接続されている、全てのクライアントにメッセージ送信
public async Task SendMessageAll(string user, string message) {
              await Clients.All.SendAsync("ClientMessge",user,message);
}
// HUB側からのPush通知
private async Task Notify(string message) {
              await Clients.All.SendAsync("SystemNotify", message);
}
Client側
HubConnection con = HubConnectionBuilder()
            .WithUrl("http://・・・")
            .Build();

// メッセージハンドラの登録
con.On<string,string>("ClientMessage",
      (user,message) => {
                    // 処理
      }
);
con.On<string>(""SystemNotify",
      (message) => {
                    // 処理
      }
);
・・・
// 現在HUBに接続している全てのクライアントにメッセージ送信要求
await con.InvokeAsync("SendMessageAll",MyUserName,Message);

HUB側ではClients.Allの他

  • Clients.Other                    要求元以外のクライアント
  • Clients.Group                   特定のグループ
  • Clients.User                     特定のユーザ
  • Clients.AllExcept             指定されたユーザ以外全て
  • Clients.Caller 呼出元のクライアント

等、送信先の指定が可能。

クライアント側は

  On<パラメータ型,[パラメータ型,…]>(メッセージID,メッセージハンドラ)

の形で複数種類のメッセージをハンドリングする事が可能。
※パラメータの型はHUB上の定義と合っていなければハンドリングされない。

blazor wasm版などと組み合わせると、結構面白いアプリを作成することができるのでは無いだろうか。

ちなみに、クライアント,HUB双方でメソッド名やメッセージ名を文字列で扱っているが、バグの温床となり得るので、Interfaceを作成して、nameof(メソッド名)やnameof(メッセージ名)等とすると良いだろう。

詳細は下記などを参照
https://docs.microsoft.com/ja-jp/aspnet/core/signalr/introduction?view=aspnetcore-3.1

カテゴリー: asp.net core, C#, dotnetcore, SignalR, 技術系 | 1件のコメント

asp.net core blazor(server side)で、SignalR

asp.net core blazor(server side)でSignalRのテストをしてみた。同じプロジェクト中にHubを作成して簡易チャットを作成。

接続や処理要求は良いのだが、問題が1つ。それは、ページを閉じたり、ページから移動した時にHub側で切断イベント(OnDisconnectedAsync)が発生しないこと。色々調べたんだけど、結局、クライアント側のアプリから明示的に切断しないと発生しないみたい。

Keepaliveとかのタイマー値をいじってみたが、つながっているのに切断イベントが上がったり・・・
多分、クライアントとHub双方で値を調整しなければいけないんだろうね。

じゃぁ、「ページ閉じた時に明示的に切断したれと」思い、blazorページにIDisposableインターフェースをImplementしてDisposableメソッドを定義、その中で明示的に切断するようにしたら、Hub側でイベントが発生するようになりました。

@implements System.IDisposable
・・・
    //
    //  ページ破棄時に明示的にSignalRを切断してみる
    //
    void IDisposable.Dispose() {
        // conはHubConnectionのインスタンス
        // 明示的に接続を破棄
        con.DisposeAsync();
    }
}

まぁ、これが正しい方法かどうかは分からないけど・・・

カテゴリー: asp.net core, Blazor, C#, dotnetcore, SignalR, 技術系 | 1件のコメント