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

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


Wordpress に引っ越しました!

Visual Studio Code で markdown のスニペットを登録する

Visual Studio Codemarkdown を使用して plantuml を書くことが多いのですが、

```plantuml
@startuml
skinparam backgroundColor #FEFEFE

~

@enduml
```

というようなのを毎回手入力するのが面倒です。

何かいい方法はないかなぁと思ってたら、スニペットを使用したら解決することがわかったので、その備忘録です。

Visual Studio Codemarkdownスニペットを登録する

スニペット利用準備

私の環境では、デフォルトで markdownスニペットが無効になっていたので、有効にします。

基本設定を開き、以下の項目をユーザー設定に追加します。

"[markdown]":  {
    "editor.wordWrap": "on",
    "editor.quickSuggestions": true,
    "editor.snippetSuggestions": "top"
}

スニペットの登録

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

上記のように、ユーザースニペットを選択します。

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

markdown と入力します。

すると、 markdown.json が開きます。

デフォルトでは以下のような内容になっていました。

{
    // Place your snippets for markdown here. Each snippet is defined under a snippet name and has a prefix, body and 
    // description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
    // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the 
    // same ids are connected.
    // Example:
    // "Print to console": {
    //   "prefix": "log",
    //   "body": [
    //       "console.log('$1');",
    //       "$2"
    //   ],
    //   "description": "Log output to console"
    // }
}

これを、以下のように変更します。

{
    "Plantuml": {
        "prefix": "plantuml",
        "body": [
            "```plantuml",
            "@startuml",
            "skinparam backgroundColor #FEFEFE",
            "skinparam componentBorderColor #000000",
            "hide footbox",
            "",
            "@enduml",
            "```",
     ],
        "description": "Using PlantUML"
    }
}

これで、markdown 編集中に p と打てば、スニペット候補が表示されるようになり、tab キーでテンプレートを挿入できるようになりました。

参考記事

qiita.com

Microsoft.Extensions.DependencyInjection の DI コンテナの挙動について

ASP.NET Core でよく使われる(?) Microsoft.Extensions.DependencyInjection をクラスライブラリやコンソールアプリケーションで使用したときの挙動についての備忘録です。

Microsoft.Extensions.DependencyInjection の DI コンテナの依存性の注入方法

主に以下の3パターンがあります。

  • AddTransient
  • AddScoped
  • AddSingleton

AddSingleton はその名前の通りなのでいいのですが、残り2つがぱっと見わからないので、それを今回確認しました。

わかったこと

stackoverflow.com

stackoverrun.com

どうやら、AddTransientAddScoped はスコープ設定をするかどうかで挙動がかわるみたいです。

実際に以下のように試してみました。

試したこと

まず、適当にDTOを用意します。

interface ISingleton
{
    string Hoge { get; set; }
}

class Singleton : ISingleton
{
    public Singleton()
    {
        Hoge = Guid.NewGuid().ToString();
    }

    public string Hoge { get; set; }
}

interface IScoped
{
    string Piyo { get; set; }
}

class Scoped : IScoped
{
    public Scoped()
    {
        Piyo = Guid.NewGuid().ToString();
    }

    public string Piyo { get; set; }
}

interface ITransient
{
    string Fuga { get; set; }
}

class Transient : ITransient
{
    public Transient()
    {
        Fuga = Guid.NewGuid().ToString();
    }

    public string Fuga { get; set; }
}

テスト用のソースとして以下を用意しました。

public void GetServiceTest()
{
    var services = new ServiceCollection();

    // 依存性の注入
    services.AddSingleton<ISingleton, Singleton>();
    services.AddScoped<IScoped, Scoped>();
    services.AddTransient<ITransient, Transient>();

    // DIコンテナの生成
    var serviceProvider = services.BuildServiceProvider();

    Console.WriteLine("スコープなし1回目: Singleton:" + serviceProvider.GetRequiredService<ISingleton>().Hoge);
    Console.WriteLine("スコープなし1回目: Scoped:" + serviceProvider.GetRequiredService<IScoped>().Piyo);
    Console.WriteLine("スコープなし1回目: Transient:" + serviceProvider.GetRequiredService<ITransient>().Fuga);

    Console.WriteLine("スコープなし2回目: Singleton:" + serviceProvider.GetRequiredService<ISingleton>().Hoge);
    Console.WriteLine("スコープなし2回目: Scoped:" + serviceProvider.GetRequiredService<IScoped>().Piyo);
    Console.WriteLine("スコープなし2回目: Transient:" + serviceProvider.GetRequiredService<ITransient>().Fuga);

    using (var scope = serviceProvider.CreateScope())
    {
        Console.WriteLine("スコープあり: Singleton:" + scope.ServiceProvider.GetRequiredService<ISingleton>().Hoge);
        Console.WriteLine("スコープあり: Scoped:" + scope.ServiceProvider.GetRequiredService<IScoped>().Piyo);
        Console.WriteLine("スコープあり: Transient:" + scope.ServiceProvider.GetRequiredService<ITransient>().Fuga);
    }
}

これを実行した結果です。

スコープなし1回目: Singleton:3a3fdfd6-50d7-4c9b-9dcf-9a316a554b06
スコープなし1回目: Scoped:f6c3fe39-b608-4083-aff5-98dc6b66b8de
スコープなし1回目: Transient:b209bf1d-c83f-434a-8957-9bc528e9405c
スコープなし2回目: Singleton:3a3fdfd6-50d7-4c9b-9dcf-9a316a554b06
スコープなし2回目: Scoped:f6c3fe39-b608-4083-aff5-98dc6b66b8de
スコープなし2回目: Transient:84d37074-17dc-4f93-845b-4e7125361955
スコープあり: Singleton:3a3fdfd6-50d7-4c9b-9dcf-9a316a554b06
スコープあり: Scoped:990c5065-586c-4e11-b8e7-094a59c1b511
スコープあり: Transient:e10ebd8c-2f23-42c2-ba0d-7d1b2e2cb7f5

まとめ

時間がないのできなりまとめですが、以下の通りです。

ASP.NET Core では、デフォルトで以下のように動作します。

依存性の注入方法 GetSerivece()を実行したときの振る舞い
AddTransient 同一リクエストであっても、常に新しいインスタンスが生成される
AddScoped 同一のリクエストであれば、同じインスタンスが返ってくる。ただし、異なるリクエストならば新しいインスタンスが生成される
AddSingleton 異なるリクエストであっても、常に同じンスタンスが返ってくる

コンソールアプリやクラスライブラリでは以下のように動作します。

依存性の注入方法 GetSerivece()を実行したときの振る舞い
AddTransient 常に新しいインスタンスが生成される
AddScoped スコープを自身で設定する必要がある。何もスコープを設定しないときは、グローバルスコープとなり常に同じインスタンスが返ってくる
AddSingleton 常に同じンスタンスが返ってくる

スコープを設定するために IServiceScopeFactory なるものがあるらしく、自前でそれを使用することでスコープの制御ができるみたいです。

たぶんですけど、ASP.NET Core ではそのスコープ制御を隠蔽して勝手にやってくれているのだと思います。

参考サイト

stackoverflow.com

stackoverrun.com

Linux Mint から Windows10 へリモートデスクトップ接続する

私の環境(Linux Mint 19.1 MATE)では、標準で Windows へのリモートデスクトップができなかったので、その備忘録です。

前提

  • 接続元: Linux Mint 19.1 MATE
  • 接続先: Windows10

ただし、Windows10 側は Pro エディションでないとそもそもリモートデスクトップ接続を許可できません。
Home の場合、「RDP Wrapper Library」等を利用して細工する必要があります。(こちら参照)

Remmina のインストール

sudo apt-get update
sudo apt-get install remmina

これで Remmina 自体は取得できるのですが、デフォルトでは SFTP と SSHプロトコルしか対応していないので、プラグインを取得します。

sudo apt-get install remmina-plugin-rdp
# なお、 VNC で接続する場合は以下もあるそうです
# sudo apt-get install remmina-plugin-vnc

Remmina を使ってみる

インストール後、メニューから Remmina を起動します。
もしプラグインを入れる前に Remmina を一度でも起動している場合は、OS の再起動が必要なようです。(私の環境では、一度再起動が必要でした。)

起動後、画面左上側にある「新規」をクリックします。
そうすると、「リモートデスクトップの接続」画面が表示されますので、画面内で以下のように入力します。

  • プロトコル: RDP を選択
  • サーバー: Windows10 側の IP アドレス
  • ユーザー名: Windows10 側のログインアカウント(マイクロソフトアカウント、つまりメールアドレスとか)
  • パスワード: マイクロソフトアカウントのパスワード

それ以外は変更不要です。

これで、「接続」を押すと、私の場合は Windows10 へリモートデスクトップ接続成功しました。

参考

なお、今回はこちらの記事を参考にさせていただきました。

バッチファイルで % とかをエスケープする方法

所用で、 git log -n 1 --format=%H をバッチファイル上で実行しようとしたのですが、うまくいかなかったので備忘録として残しておきます。

バッチファイルでは、% は特別な意味を持つので、エスケープが必要なのはわかるのですが、何故か後ろに付ける ^ にハマりました。

結果的には以下の通りです。

git log -n 1 --format=%%^H

よくわかってませんが・・・

Fire TV Stick で IEEE802.11ac 接続できないときの対処法

仕事とは全く関係ないですが、今回の Amazon Cyber Monday にて、 Fire TV Stick を買いました。

買って、さっそくセッティングしたのですが、我が家の Wi-Fi の 11ac (5GHz 帯)のネットワークを認識しませんでした。 一応 11g は認識して、速度もフル HD で見る分には問題なかったので「まぁいっか・・・」と妥協しようと思いましたが・・・
やっぱりなんか電子レンジとかで接続が不安定になるのはシャクだし、せっかく 5GHz 帯で接続できる能力が無線 LAN ルーターにあるのにそれを持て余すのも悔しいので、ちょっと調べてみました。

ググってみたら、以下の記事がヒットしました。

chamapoco.com

チャンネルの設定が正しくないと、 5GHz 帯は接続できないようです。
ちゃんと接続するようにするには W52 の 36, 40, 44, 48 の4チャンネルのいずれかを使用する 必要があるみたいです。

無線 LAN ルーターの設定方法

で、ここからが備忘録ですが、私の家で使用している NEC無線LANルーターでの設定方法を残しておきます。
使用している機種は「WG1200HP」というやつです。が、たぶん NEC 系ならほとんど同じかなと思います。

ルーターの管理画面で設定を行います。

変更前

f:id:tassi-yuzukko:20181209231208p:plain
変更前

変更後

f:id:tassi-yuzukko:20181209231006p:plain
変更後

「自動」になっているのを「W52」に指定してやると、無事 Fire TV Stick で 11ac が認識するようになりました。

たぶん無線 LAN ルーターの設定はいじってないはずなので、デフォルトは「自動」だと思うのですが、そのままではつながらないというのは、結構初見殺しの感じします・・・

以上、備忘録です。


ちなみに、 4k 対応の次世代 Fire TV Stick は 12/12 頃に発売みたいですね。

我が家は 4k なんてシロモノない(´;ω;`)ので、今回は安くなってる現世代を買いました。

CentOS で samba の設定をする

Windows10 から CentOS7 へエクスプローラーを使ってアクセスしたかったので、 ssamba による設定を行いました。
かなり苦戦したので、苦戦したところを備忘録として残します。

samba の準備

usado.jp

↑を参考にさせてもらいました。
基本的にはこの通りでよいです。

リモートデスクトップ

CentOS 上で vi でテキストファイルを編集するのはかなりキツイので、 VNCリモートデスクトップで操作を行いました。

qiita.com

↑を参考にしました。 VNC でのリモートデスクトップのポート番号は 5901 です。

SELinux の無効化

こいつのせいでかなり手間取りました。
全部設定もできているはずなのに、何故か Windows からアクセスして書き込みができない・・・

いろいろググって、↓にたどり着きました。

void-asterisk.blogspot.com

本当は SELinux は有効にすべきなんでしょうが、今回は社内のクローズな環境に限定されていたので、無効にしてやりました。

無効にする方法は↓を参考にしました。

qiita.com

WPF で外部のプロジェクトからユーザーコントロールとかを参照する方法

地味にかなりハマったので、備忘録として残しておきます。

シチュエーションとしては、以下の感じです。

ここで、プロジェクトAの MainWindow にて最初は単純に以下のように記述していました。

<Window x:Class="ProjectA.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ProtobufAnalyzer.DebugWpf"
        xmlns:pb="clr-namespace:ProjectB"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <pb:MyUserCtrl>
        </pb:MyUserCtrl>
    </Grid>
</Window>

コンパイルすると以下のようにコンパイルエラーになります。

error MC3074: タグ 'MyUserCtrl' は、XML 名前空間 'clr-namespace:ProjectB' にありません。

ちゃんと xmlns:pb="clr-namespace:ProjectB" というように名前空間を追加しているのに!
名前空間 ProjectBMyUserCtrl はあるのに!
間違いなくプロジェクトBの参照にプロジェクトAを追加しているのに!

どうしろというのだ・・・

ググってもググり方が悪いのか、特に有力な情報は得られず・・・
30分以上格闘して、自分が作った過去の wpf アプリのソースを見ていたら解決策が見つかりました。(というか、過去のアプリは無意識のうちに?ちゃんとできてました)

結果的には、以下のように名前空間の後に assembly=*** を追加しなければならないようです。

<Window x:Class="ProjectA.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ProtobufAnalyzer.DebugWpf"
        xmlns:pb="clr-namespace:ProjectB;assembly=ProjectB"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <pb:MyUserCtrl>
        </pb:MyUserCtrl>
    </Grid>
</Window>

こんなんわかるわけないやん・・・
せめてエラーとかもうちょっと直感的にわかるようなやつが出てくれれば・・・
と恨み節ですが。