コーヒー飲みながら仕事したい

仕事で使う技術的なことの備忘録とか


Wordpress に引っ越しました!

自作の nuget package に xml コメントを付加する

以下、 .NET Standard の話です。

.NET Standard では、 nuget package の作成方法は、 *.nuspec を使用しなくても、 *.csproj に以下のように記載すれば *.nupkg が出力されます。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>latest</LangVersion>
    <NeutralLanguage>ja-JP</NeutralLanguage>
    <Version>1.0.0</Version>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
  </PropertyGroup> <!--←これを true にする-->

</Project>

ただし、これだけでは、ソース内に記述した xml コメントが反映されません。
(例えば「定義へ移動」とやっても、コメントが書かれていない)

そこで、以下のようにプロジェクト設定を変更してやると、xml コメントが付加された nuget package が出力されるようになります。

f:id:tassi-yuzukko:20181127091850p:plain

Visual Studio 2017 でデフォルトの using を設定する【項目テンプレート使用】

Visual StudioC# でアプリケーションを開発中に個人的によく思うのが、例えば using System.Linq とか using System.Threading.Tasks とか、毎回毎回手で書くの面倒くさいなぁというところです。
using System とかは最初から記述してあるので、それと同じようにデフォルトの using をカスタマイズできないかなぁと思って見つけた解決策の備忘録です。

項目テンプレート

作成方法

結果的には、「項目テンプレート」というのを使用すると解決します。
項目テンプレートの作成方法については、↓こちらが参考になります。

qiita.com

ただし、こちらに書かれている内容は、あくまで項目テンプレートの作成についてであり、デフォルトの using 設定には触れておりません。 そこで、デフォルトの using の設定ですが、「C# Item Template」のプロジェクトで、以下のように設定を行います。

*.vstemplate

そのまま自分が作ったのをコピペしてみます。ここでは、プロジェクト名を MyTemplate で作ったものとします。

<?xml version="1.0" encoding="utf-8"?>
<VSTemplate Version="3.0.0" Type="Item" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" xmlns:sdk="http://schemas.microsoft.com/developer/vstemplate-sdkextension/2010">
  <TemplateData>
    <Name>MyTemplate</Name>
    <Description>MyTemplate</Description>
    <Icon>MyTemplate.ico</Icon>
    <TemplateID>bf7d40b0-1363-4e9f-a155-657b5ca5ed03</TemplateID>
    <ProjectType>CSharp</ProjectType>
    <RequiredFrameworkVersion>2.0</RequiredFrameworkVersion>
    <NumberOfParentCategoriesToRollUp>1</NumberOfParentCategoriesToRollUp>
    <DefaultName>Class.cs</DefaultName>
    <AppliesTo>CSharp</AppliesTo>
  </TemplateData>
  <TemplateContent>
    <!--<References>
      <Reference>
        <Assembly>System</Assembly>
      </Reference>
    </References>-->
    <ProjectItem ReplaceParameters="true">Class.cs</ProjectItem>
  </TemplateContent>
</VSTemplate>

ポイントとしては以下です。

  • <AppliesTo>CSharp</AppliesTo> を追加する
  • <References></References> を削除(コメントアウト)する
    • これしなくても目的は達成できるが、クラスファイルを作るたびに警告が出てくるようになる
Class.cs

これも、そのまま自分が作ったのをコピペしてみます。

using LanguageExt;
using static LanguageExt.Prelude;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace $rootnamespace$
{
    class $safeitemrootname$
    {
    }
}

ポイントとしては以下です。

  • デフォルトで using するものを、単純に列挙するだけ
  • ただし、参照サイトにも注意書きがあるが、 Class.cs のプロパティで、ビルドアクションを「コンパイル」から「コンテンツ」にしないとエラーが出てコンパイルが通らない
    • $rootnamespace$ の部分はどうしても赤線が出てエラーっぽく表示されるが、コンパイルには問題なし

コンパイル

項目テンプレートをそのままコンパイルすると、 zip ファイルが出力されます。
(参考サイトでは VISX で拡張として Visual Studio にインストールする方法が記載されていましたが、私の環境ではどうも拡張のインストールに時間がかかるので、 zip のまま使うようにしています。)

zip ファイルは、私の開発環境では プロジェクトフォルダ\bin\Debug | Release\ItemTemplates\CSharp\1033 に出力されました。

配置

生成された zip を、 Visual Studio のテンプレート置き場である C:\Users\XXXXX\Documents\Visual Studio 2017\Templates\ItemTemplates に zip のままコピーします。
その後、 Visual Studio を起動すると、「追加」から作成したテンプレートを選択できるようになっています。

もし変更したくなったら、変更後の zip をコピーしなおすと、次回起動時から変更が反映されるみたいです。

.net standard で nuget package (*.nupkg) を生成する方法

.net framework 等では、 *.nuspec というファイルを経由して *.nupkg を作る方法があるみたいですが、.net standard では異なるみたいです。(もしかしたら .net core も同様かもしれませんが、試していません)
というかかなり楽で、 *.csproj から生成することができます。

例えば *.csproj は、デフォルトでは以下のように記述になっているはずです。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

</Project>

ここで、最低限 *.nupkg を生成するだけなら、*.csproj に以下の行を追加するだけで *.nuspec 相当のものになります。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <Version>1.0.0</Version> <!--これ!-->
  </PropertyGroup>

</Project>

あとは、*.csproj が存在するディレクトリで以下を実行します。

dotnet pack -c Release
# または dotnet pack -c Debug でも可

これで、.\bin\Release 内に *.nupkg が出来上がります。

mosquitto でブローカーのログをファイル出力する方法(Windows10 にて)

主題の通り、Windows10 の環境にて、 mosquitto のブローカーのログをファイルに出力する方法です。

公式な手順(ただし Windows10 ではうまくいかない・・・)

まず、公式にログ出力に関する設定方法が書かれています。
大まかな手順としては

  1. mosquitto.conflog_dest 属性に出力するファイルパスを設定する
  2. ブローカーを mosquitto -c <mosquitto.confのパス> で起動する

という感じっぽいです。

しかし、肝心の log_dest に記載する内容ですが、syslog というオプションがありますが、これは調べた感じ Windows では有効にならない?のか、どこかに出力されているのかわかりませんでした。
他に file *****.txt という方法があるみたいですが、こちらもうまくいきませんでした。

実際に以下のように mosquitto.conf を設定してみました。

(mosquitto.conf の抜粋)
log_dest file C:\Users\XXXX\Documents\mosquitto.log

しかし、ブローカー起動時に以下のように起こられてしまいました。

C:\Program Files (x86)\mosquitto>mosquitto -c mosquitto.conf
1540507934: Error: Unable to open log file C:\Users\XXXX\Documents\mosquitto.log for writing.

権限系なのかといろいろ試しましたが、やっぱりうまくいきませんでした。

ググってみると、windows 以外ではそこそこ情報がみつかるのですが、 windows に関する情報は有力なものはみつけられませんでした・・・

他の手法

そこで、代替手段となりますが、 StackOverflow に Windows 環境での ログ出力手段について情報がありました。

iot.stackexchange.com

これは、ブローカーのログ出力というよりは、全メッセージを受信するクライアントを立ち上げて、そのクライアントがメッセージをファイル出力という感じっぽいです。
これはあくまでトピックのみを対象としたログになるので、ブローカーの動作ログとは程遠いものですが・・・

一応手順的には以下の感じです。(そのまま日本語にしているだけですが)

  1. 以下の内容を timestampLog.vbs に記述して保存する
Dim str
Do While Not WScript.StdIn.AtEndOfStream
  str = WScript.StdIn.ReadLine
  WScript.StdErr.WriteLine "[" & now & "]" & str
Loop
  1. ブローカーを起動する

  2. クライアントを、以下の通りにして起動する

C:\Program Files\mosquitto>mosquitto_sub -t +/# -v | cscript //nologo timestampLog.vbs 2> C:\*USER*\Desktop\logfile.txt

これで、上記であれば C:\*USER*\Desktop\logfile.txt にトピックのログが出力されるようになります。

うーん、これがしたかったわけじゃないんだけどなぁ・・・

追記

Windows でログのファイル出力ができないことは既知の問題だったみたいです。

github.com

なんか読んだ感じ、対応されないっぽい感じします。
残念です・・・

.NET Standard で EntityFrameworkCore の Scaffold を実行する

前回、 .NET Core で Scaffold しましたが、

tassi-yuzukko.hatenablog.com

クラスライブラリ側に Scaffold して DTO クラスを自動生成したくなりました。

しかし、単純ではなかったので、こちらも備忘録として残しておきます。

はじめに

単純に .NET Standard で Scaffold しようとすると、以下のエラーが出力されます。
(あらかじめ、前回の .Net Core コンソールアプリケーション用の環境を nuget 済みという前提です)

> dotnet ef dbcontext scaffold "Data Source=192.168.XXX.XXX\XXXX;I
nitial Catalog=XXXDb;Persist Security Info=True;User ID=XXX;Password=XXXXXXXXXXX" Microsoft.EntityFrameworkCore.Sql
Server -o Models
#  ↓このエラー
Startup project 'ClassLibrary1.csproj' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the Entity Framework Core .NET Command-line Tools with this project, add an executable project targeting .NET Core or .NET Framework that references this project, and set it as the startup project using --startup-project; or, update this project to cross-target .NET Core or .NET Framework.

どうやら.NET Standard は Scaffold 対応してないみたいです ><

ということで、対応策を調べてみました。

対応策

StackOverflow にありました。

stackoverflow.com

今回は、一番上の回答で提示されている Workaround 2 - Cross-target a runnable framework で対応します。

ちょっとトリッキーな気がしますが、クラスライブラリを .NET Standard と .Net Core の両方で出力するように設定するということみたいです。

.csproj ファイルは以下のような記載になります。

  <PropertyGroup>
-   <TargetFramework>netstandard2.0</TargetFramework>
+   <TargetFrameworks>netcoreapp2.1;netstandard2.0</TargetFrameworks>
  </PropertyGroup>

これで、前回のやり方を実行すると、 Scaffold が成功しました。

このやり方だったら、このクラスライブラリを .NET Standard の別のクラスライブラリに読み込ませることが可能になります。
(.NET Core => .NET Standard および .NET Standard => .NET Standard の依存は OK なのですが、.NET Standard => .NET Core は不可能なので)

EntityFrameworkCore で Scaffold 使ってデータベースファーストする方法

主題の件ですが、ハマった部分もあったので備忘録として残しておきます。

先に注意点ですが、 .NET Core コンソールアプリケーションと、 ASP.NET Core では Scaffold の条件が異なる というのが今回ハマったところです。

前提事項

  • 恐らく現状(dotnet core 2.1)では、CUI でのみしか Scaffold ができないと思われます。なので、操作は PowerShell で行いました。
  • あらかじめ dotnet ef が実行できることを前提に話を進めます。
  • 今回はデータベースファーストですので、あらかじめデータベース上にテーブル等が定義済みであり、それらのテーブルから DTO クラスを自動生成することを目的とします。

Scaffold の仕方

*.csproj のあるフォルダ内で、以下のコマンドを実行します。

> dotnet ef dbcontext scaffold "Data Source=192.168.XXX.XXX\XXXX;I
nitial Catalog=XXXDb;Persist Security Info=True;User ID=XXX;Password=XXXXXXXXXXX" Microsoft.EntityFrameworkCore.Sql
Server -o Models

コマンドの解説です。

  • ダブルクオーテーションで囲んだ中身("Data Source~" のところ)は、データベースの接続先情報になります。
    接続先情報は、次の通り取得できます。
    VisualStudio 上の「サーバーエクスプローラー」ウィンドウから、「データ接続」の項目を選び、そこに表示される接続先(コンセントみたいなのが右下についているアイコンのやつ)を右クリックして、プロパティを表示します。プロパティの「接続文字列」欄にあるやつです。
    よく dbcontext scaffold というキーワードでググったら、 Server=~ の例が多いので、 Data Source=~ じゃダメなのかと思ったけど、そうじゃないみたいです。
  • Microsoft.EntityFrameworkCore.Sql はとりあえずおまじないです。(接続先が SQLServer の場合に限る)
  • -o Models で、Models フォルダ内に、データベース上のテーブルの DTO クラスが自動生成されます。

とりあえず Scaffold の方法は上記の通りシンプルなのですが、条件がありますので、それを以下に述べます。

ASP.NET Core の場合

こちらは単純です。というか条件はありません。

.NET Core コンソールアプリケーションおよびクラスライブラリの場合

こちらが問題です。
なぜか ASP.NET Core の場合は何も nuget しなくて良いのに、コンソールアプリケーションやクラスライブラリになると、以下のライブラリを nuget する必要があります。

.csproj ファイル的には以下の感じです。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.3" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.3" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.3" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.3">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
    </PackageReference>
  </ItemGroup>

</Project>

とりあえず、以上で Scaffold により、データベース上のテーブルに対応する DTO クラスが自動生成できました。

mosquitto でパスワード認証の設定をする

概略手順

  1. ブローカー側で保持するパスワードファイルを作成
  2. 作成したパスワードファイルを、config ファイルに登録する
  3. config ファイルを起動オプションに指定して、ブローカーを起動する
  4. クライアント側でもオプションにユーザー名とパスワードを指定して起動する

サーバー側

パスワードファイルの作成

コマンドプロンプトにて以下のように入力します。

C:\Program Files (x86)\mosquitto> mosquitto_passwd -b pwfile username password 
  • pwfile は、パスワードファイルのパス名です
  • username は、作成するユーザー名です
  • password は、作成するパスワードです

上記のコマンドを入力すると、指定したパスに pwfile というファイルが生成されます。

config ファイルの設定

ブローカーアプリ(mosquitto.exe)のあるフォルダ内にある mosquitto.config をメモ帳等で開きます。

(デフォルトでは C:\Program Files (x86)\mosquitto にあるはず)

最終行に以下を追記します。

allow_anonymous false
password_file ./pwfile

ここで、 ./pwfile は、作成したパスワードファイルのパスです。相対パスまたは絶対パスどちらでもいいです。
なお、 allow_anonymous false は、パスワードなしのクライアント接続を弾くというオプションです。これを記載しないと、パスワード認証するけど、パスワードなしのアクセスも受け付けるという謎挙動になります。

ブローカーの起動

コマンドプロンプトにて以下のように入力して、ブローカーを起動します。

mosquitto -v -c mosquitto.conf

ここで、-c mosquitto.conf は、 config ファイルのパスになります。デフォルトでは上記の通りでいいはずです。

クライアント側

mosquitto に同梱されているクライアントアプリを例にします。

接続時に、以下のようにオプションをつけるとパスワード認証で接続できます。
(注:-P は大文字です)

C:\Program Files (x86)\mosquitto> mosquitto_sub -t なんかのトピック -u ユーザー名 -P パスワード

‐‐‐

以上で、パスワード認証ができるはずです。

参考

qiita.com