koudenpaのブログ

趣味のブログです。株式会社はてなでWebアプリケーションエンジニアをやっています。職業柄IT関連の記事が多いと思います。

Blazor WebAssemblyのログ

がどうなってんのか気になったので少し見ていたメモ。

Blazor WebAssemblyのプロジェクトで依存しているDLLで無造作に.AddDebug()してデバッグログを見ていたのだけれど、Blazor WebAssembly上では特にコンソール上に何か出るわけでも、エラーするわけでもなく動作していたので気になった次第。

とりあえずドキュメントを見てもイマイチ分からなかったので試したりソースを眺めたりした。

バージョンは 5.0.3 で、ここでいうログはサードパーティのものではなく Microsoft.Extensions.Logging です。

基本的にはログレベルだけ設定( builder.Logging.SetMinimumLevel(LogLevel.XXX) )すればいいようだった。それだけでWebAssemblyConsoleLoggerというブラウザのコンソールにログ出力するロガーが構成されるようになっている。

Debugレベル以下はブラウザ*1の側でフィルタされているので、それらを見たい場合は『すべてのレベル』を表示するように設定する必要はあった。

f:id:koudenpa:20210228233354g:plain
Debugレベル以下はブラウザの既定ではフィルタされている

未対応のログプロバイダを追加すると動作しないので、変な設定をしてしまったらその設定を消せばよい。スクリーンショット.AddConsole() してみた場合のもの。

f:id:koudenpa:20210228233317p:plain
未対応のProviderを追加すると例外する

この記事の段階のお試し結果を転記しておく。

public class Program
{
  public static async Task Main(string[] args)
  {
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    builder.RootComponents.Add<App>("#app");
    // Document: https://docs.microsoft.com/ja-jp/aspnet/core/blazor/fundamentals/logging?view=aspnetcore-5.0&pivots=webassembly
    // ドキュメントからだと分かりづらいが、
    // 既定で WebAssemblyConsoleLoggerProvider が構成されており ILogger を注入するだけでコンソールにログ出力を行えるようになっている。
    // https://github.com/dotnet/aspnetcore/blob/d827c653b787c07de908240b7746ce34d3e6271e/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHostBuilder.cs#L227-L230
    builder.Logging
      // Chromeの開発者ツールの既定では Info レベル以上を表示するようになっている。
      // Debug 以下のレベルを表示するにはブラウザ側の設定も変更が必要。
      .SetMinimumLevel(LogLevel.Trace)
      // 事実上他のプロバイダーは設定しても動かなかったり、設定した瞬間に(ちゃんと)未対応である旨の例外が発生する。
      // 例えばローカルストレージにログを出力する CustomLoggingProvider を実装する、のようなことはできなくもないようだ。
      .AddDebug()
      //.AddConsole()
      //.AddSimpleConsole()
      ;
    builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
    await builder.Build().RunAsync();
  }
}
@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    [Inject]
    private ILogger<Counter> logger { get; set; }

    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
        logger.LogTrace($"LogTrace Count: {currentCount}");
        logger.LogDebug($"LogDebug Count: {currentCount}");
        logger.LogInformation($"LogInformation Count: {currentCount}");
        logger.LogWarning($"LogWarning Count: {currentCount}");
        logger.LogError($"LogError Count: {currentCount}");
    }
}

例えばローカルストレージにログを出力する CustomLoggingProvider を実装する、のようなことはできなくもないようだ。

これはクラッシュログとか貯めておけて使える場面はあるかもしれない。

後は、Application Insights プロバイダの対応状況は普通に気になるな。これは別途試してみるかもしれないけれど、ログというよりは統合的なApplication Insights対応のほうが気になる。

そんな感じだった。

*1:ChromeやEdgeはそうだったが他のブラウザでどうかは定かではない

C#でバイト単位でファイルを読んでみる

社内の勉強会でGoのメモリアロケーションの話があって、最後に『チャレンジ問題』があった。

こんなの。

チャレンジ問題 ファイルの内容すべてをバイト列に読み込む関数 ReadFile(*File).Read などを用いて実装してください ヒント: リアロケーションが起きないようにするにはどうすればいいだろうか

そういえばC#書いててもファイル読み込みとかStreamReaderとか使ってて低レベルな読み込みしないなぁ、どんな感じになのかなぁ、と思ったのでちょっと見てみた。

結果、.NETでIOに使う Stream には Length っていう身もふたもないプロパティがあったのでその分だけメモリを確保すればよかった。

面白みはなかった。

気が向いたらソースコード眺めてみようかな、とは思った*1

Length プロパティはSeekできないStreamだと例外を吐く模様。ローカルファイルの読み込みならSeekできるだけで、ネットワーク越しのアクセスだと多分使えない。IOは奥が深い。

using System;
using System.IO;
using System.Text;

namespace dotnet_sandbox
{
    // ファイルの内容すべてをバイト列に読み込む関数 `ReadFile` を `(*File).Read` などを用いて実装してください
    // ヒント: リアロケーションが起きないようにするにはどうすればいいだろうか
    // 答え合わせは `os.ReadFile` を確認してください
    // Go 1.15 (ioutil) と1.16の実装の違いを確認し、ベンチマークしてみましょう。
    // PrometheusはGo 1.16でテストが落ちるようになりました ([https://github.com/prometheus/prometheus/issues/8403 #8403])。理由を調べてみましょう。
    class Program
    {
        static byte[] ReadToEnd(Stream stream)
        {
            var buf = new Byte[stream.Length];
            var i = 0;
            int b;
            // ReadByte はStreamが終端だと -1 を返すという現代とは思えないレガシーな仕様
            while ((b = stream.ReadByte()) >= 0)
            {
                // アンセーフにしてポインタを進めていったほうが早いのか? 分からん
                // そもそも長さが分かっているなら Read メソッドに buf  を渡せば一気に読めそう
                buf[i++] = (byte)b;
            }
            return buf;
        }

        static void Main(string[] args)
        {
            using (var stream = new FileStream(args[0], FileMode.Open))
            {
                var bytes = ReadToEnd(stream);
                Console.WriteLine($"{args[0]} length = {bytes.Length}");
                Console.WriteLine(Encoding.UTF8.GetString(bytes));
            }
        }
    }
}

*1:こういう時は大体眺めない

MySql.EntityFrameworkCore で ASP.NET Identity

.NET(Entity Framework Core)を使うならSQL Serverを使っておけ、というのが正直なところなのだけれど、MySQLを使ってみたいと思うこともあるだろう。

ので試した。ASP.NETにはASP.NET Identityという認証ライブラリがあって、Webアプリケーション作成時にチェックボックスを入れるだけでその基本的な構成が行われる。僕が一番好きなIdentiyです。

が、そうすると当然ながらSQL Server向けになっており、MySQLで使うにはちょっと手を加えなくてはならない。

とりあえずユーザー登録とログインができるようになるためにやったことをメモしておく。

Entity Framework Coreのコードファーストマイグレーションを使うのが前提です。

続きを読む

Visual Basic のプログラムを C# に移植してる感想

Visual Basicは.NETではないやつ。

具体的にはVB5から.NET5 Windows Forms。奇しくも同じ5。

趣味でやっている(完遂しなくてもいい)のでめちゃくちゃ場当たり的だし、仕事で今後やることもないだろうから完全な感想。

移植をこんな風に試してる人がいますよ。といった記事。

  • 動機・やってること
  • やり方
  • ラッキーポイント
  • 困りポイント
続きを読む

キャリアプラン2021

半期の評価、査定を機にキャリアプランでも考えてみるか。と思って社内の共有スペースに書いていたもの。当たり障りのない内容(本当か?)なので何となくブログに転記しておく。

大体半年くらい前に似たような系統の記事を書いている。 評価の時期はそういう気分になるんだろう。

koudenpa.hatenablog.com

キャリアプランと言っているけれど、プラン立てるのは難しくてお気持ちを書いただけになった。

つまりこの記事はタイトル詐欺です。

キャリアをプランできずにこのくらいのお気持ちでソフトウェアエンジニアやってるオッサン(2021年で多分39歳)もいますよって感じ。

続きを読む