ハロの外部記憶インターフェイス

そろそろ覚える努力が必要かも…

Api側のJson Serializeを標準からNewtonsoft.Jsonへ変更

標準JsonSerializeではNull項目などすべての項目をJsonにして返しているため、通信量に無駄が多くなる。

なのでNewtonsoft.Jsonを適用し通信量を節約する

Microsoft.AspNetCore.Mvc.NewtonsoftJsonを追加

Nugetから「Microsoft.AspNetCore.Mvc.NewtonsoftJson」を追加
ただし、.NETバージョンによって対応バージョンにちがいが存在。

.NET8では8.0.21をインストールする。
.NET9以降では最新で問題ないと思われる。

Program.cs

AddNewtonsoftJsonを追加し、シリアライズ設定を追加する。

builder.Services.AddControllers()
    .AddNewtonsoftJson(option =>
    {
        option.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
        option.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        option.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
    });

MS標準の場合、

{"menuId":1001,"menuName":"メニュー1","menuGroupCd":1,"displayOrder":1,"createdAt":"2025-10-06T00:00:00","createdBy":"SYSTEM","updatedAt":null,"updatedBy":null,"deletedAt":null,"deleteddBy":null,"versionNo":0}

NewtonsoftJsonの場合、

{"$id":"1","menuId":1001,"menuName":"メニュー1","menuGroupCd":1,"displayOrder":1,"createdAt":"2025-10-06T00:00:00","createdBy":"SYSTEM","versionNo":0}

SwaggerのVersionをUpしたらエラーになった件

Asp.net core Apiプロジェクトを作成してから、Nugetを見るとアップデートがあるとの知らせ!

もちろんアップだ

エラーになった

### Unable to render this definition

The provided definition does not specify a valid version field.

Please indicate a valid Swagger or OpenAPI version field. Supported version fields are `swagger: "2.0"` and those that match `openapi: 3.x.y` (for example, `openapi: 3.1.0`).

対策

色々調べると追加で色々設定してあげないとだめぽい。

とりあえず、成功したパターンの結果を残す。

Program.cs

// 省略
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo
    {
        Title = "MyPj.Api",
        Version = "v1"
    });
});
// 省略
if (app.Environment.IsDevelopment())
{
    app.UseSwagger(c =>
    {
        c.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi2_0;
    });
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyPj.Api V1");
}
// 省略

Versionによって色々違いがあるみたいだけど、とりあえず、9.0.6Versionではこれで解決した。

.net core でShift-JISでファイル出力

Asp.net core 開発でCsvhelperを利用して、Shift-JISで出力を試みた結果、Encodingが見つからないとエラーになる。

どうやら、.net coreからはUTF-8以外は拒否されるらしい

ネットを調べると以下のおまじないを実行してからだとかのうと出ていた。

System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);

早速CsvHelperで使ってみる

System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);

var config = new CsvConfiguration(System.Globalization.CultureInfo.CurrentCulture)
{
    HasHeaderRecord = true,
    Delimiter = ",",
    Encoding = Encoding.GetEncoding("Shift_JIS")
};

using TextWriter tw = new StreamWriter(filePath);
using var cw = new CsvWriter(tw, _config);
 foreach (var record in records)
 {
     cw.WriteRecord(record);
     cw.NextRecord();
 }

問題なく出力された

entityframework include実装

entityframeworkのinclude実装

Dbモデル

public class Author
{
    [Key]
    public int AuthorId { get; set; }
    public string Name { get; set; }
    public List<Book> Books { get; set; }
}
public class Book
{
    [Key]
    public int BookId { get; set; }
    public string Title { get; set; }
    public int AuthorId { get; set; }
    public Author Author { get; set; }
}

DbContext

public class MyDbContext : DbContext
{
    public DbSet<Book> Books { get; set; } = null!;
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Configure the model here if needed
        base.OnModelCreating(modelBuilder);
                modelBuilder.Entity<Book>()
                    .HasOne(r => r.Author)
                    .WithMany(p => p.Books)
                    .HasForeignKey(r => r.AuthorId );
    }
}

Contoller

var data= _context.Books.Include(r => r.Author).ToListAsync();

aspnet core apiでincudeするとcan't parse JSON.  Raw result:となる

aspnet core apiでincudeするとcan't parse JSON.  Raw result:となる

参照クラスの情報を取得するためincludeを実装したところ、apiのレスポンスが下記のエラーが発生

can't parse JSON.  Raw result:
An unexpected fault happened. Try again later.

調べたところJsonのSerialize処理でループ(親→子→親→子…)が発生してエラーになっているようだ 解決としてはループサイクルを無視するように設定したら動くようになった。

// Program.cs
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles;
    });

FileZilla serverを構築

概要

開発のテストFTPサーバーを構築する必要があったため、簡易的なFTPサーバー構築にFileZilla Serverを使ってみたので、簡単に手順をメモる。

リモート接続時にPassiveMode対応をしないまま、ディレクトリリストが取れずハマってしまった。

インストール

Download FileZilla Server for Windows (64bit x86)

基本設定で進めた。 2025.9月時点の最新バージョンは1.11.1のようだ

ユーザー追加

Usersから、ユーザーを追加する

Mount pointsにViryual pathに「/」、Native pathに物理パス「C:\ftproot」などを設定すると ログイン可能になる。

リモートからの接続のためPassiveMode有効化

リモートからは接続はできてもフォルダー情報のなどの送受信にPassiveModeを使うためブロックされてしいまう。(FTP用のPortだけ開けたら、ログインまでは成功する)

Use custom port rangeをチェックする。

Firewall設定

FirewallFtp用ポートNOとPassiveMode用のポートNoを「受信の規則」に追加する。

NLogを使ってみる

Aspnet core webでNLog導入

ログをファイル出力するにはやっぱり手っ取り早いサードパーティ、NLogを使ってみる

環境

  • VS2022
  • .NET 8 STD
  • Aspnet Core Web Application

Nuget

  • NLog.Web.AspNetCore
  • NLog.Extensions.Logging

nlog.config

NLogは独自のXML設定ファイルが必要。直下のLogsにログが出力される設定ファイルをルートにコピーする

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true"
      internalLogFile="internal-nlog.txt"
      internalLogLevel="Info">

  <targets>
    <target xsi:type="File" name="file" fileName="Logs/nlog-${shortdate}.log"
            layout="${longdate}|${level:uppercase=true}|${logger}|${message} ${exception:format=ToString}" />
  </targets>

  <rules>
    <logger name="*" minlevel="Info" writeTo="file" />
    <logger name="Microsoft.Hosting.Lifetime" minlevel="Info" final="true" />
  </rules>
</nlog>
<target>: 出力先(ターゲット)を定義します。fileNameでログファイルのパスを設定
<rules>: どのログをどのターゲットに出力するかを定義
name="*"はすべてのログを意味し、minlevel="Info"はInfoレベル以上のログを対象とする

Programs.cs

using NLog.Web;  // 追加
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseNLog();  // 追加

// サービスの追加
builder.Services.AddControllers();
// ...
app.Run();

ここまでで、logs直下のログ・ファイルが出力される。

ミドルウェアでトレース情報を追加する

    public class AppRequestLogger
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<AppRequestLogger> _logger;

        public AppRequestLogger(RequestDelegate next, ILogger<AppRequestLogger> logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            try
            {
                // Log Request
                var requestId = context.TraceIdentifier;
                _logger.LogInformation($"{DateTime.UtcNow} RequestId[{requestId}] {context.Request.Method} {context.Request.Path} Start");
                // Call the next middleware in the pipeline
                await _next(context);
                _logger.LogInformation($"{DateTime.UtcNow} RequestId[{requestId}] {context.Request.Method} {context.Request.Path} End");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "An unhandled exception occurred.");
                context.Response.StatusCode = 500;
                await context.Response.WriteAsync("An unexpected fault happened. Try again later.");
            }
        }
    }

Programs.cs

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Host.UseNLog();
builder.Services.AddControllers();
// ...
var app = builder.Build();
app.UseMiddleware<AppRequestLogger>();  // 追加
// ...
app.MapControllers();
app.Run();

これで、処理の前後でログが出力される。 出力例

2025-09-19 14:01:10.4676|INFO|MyProject1.AppRequestLogger|2025/09/19 5:01:10 UserCd[99999999] RequestId[0HNFN75U21601:00000001] GET /api/Sample/1 Start
2025-09-19 14:01:11.4521|INFO|MyProject1.AppRequestLogger|2025/09/19 5:01:10 UserCd[99999999] RequestId[0HNFN75U21601:00000001] GET /api/Sample/1 End

クライアントでの導入

環境

  • VS2022
  • .NET 8 STD
  • WPF Application

Nuget

  • NLog

nlog.config

NLogは独自のXML設定ファイルが必要。直下のLogsにログが出力される設定ファイルをルートにコピーする

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <!-- Targets: ログの出力先を定義 -->
    <targets>
        <!-- ファイル出力の例 -->
        <target name="file" xsi:type="File"
                fileName="Logs/clientlog-${shortdate}.log"
                layout="${longdate}|${level:uppercase=true}|${logger}|${message}" />

        <!-- コンソール出力の例 -->
        <target name="console" xsi:type="Console"
                layout="${longdate}|${level:uppercase=true}|${logger}|${message}" />
    </targets>

    <!-- Rules: ログレベルごとの出力先を指定 -->
    <rules>
        <!-- 全てのロガーから、Infoレベル以上のログをfileターゲットとconsoleターゲットに出力 -->
        <logger name="*" minlevel="Info" writeto="file,console" />
    </rules>
</nlog>

ログ出力

using NLog;
public class MyLogic
{
    public static readonly Logger Logger = LogManager.GetCurrentClassLogger();
    
    public void Method()
    {
        Logger.Info("Method()が実行された。");
    }
}

出力例

2025-09-19 14:01:10.4616|INFO|MyProject1.MyLogic|GMethod()が実行された。