きな粉もち.net

初級開発者の備忘録[c#]

Text Analytics × Http Client × Sample Code

せっかくHttpClientについてと、Cognitive ServicesのText Analyticsを知ったので、サンプルコードを書いてみました。

特に何もないですが、今後も使っていけそうなコードなので、TFSだけでなくこっちでもメモしておきます!
整理したTextAnalyticsUtilのコードはべ別途Gitに公開します!
Gitの登録しないと・・・

なお、Newtonsoft.Jsonを使っているので、NugetでNewtonsoftの最新版を取得してから利用してください。

using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

class TextAnalyticsUtil
    {
        private static readonly string uri = "https://eastasia.api.cognitive.microsoft.com/text/analytics/v2.0/keyPhrases";
        private HttpClient aClient = new HttpClient();

             public async Task ExecuteTextAnalyticsSample(string targetMessage)
        {
            aClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "サブスクリプションキー");

            // JSON としてシリアライズし POST するデータ 
            var model = new RequesttModel.Rootobject();
            model.documents = new List<RequesttModel.Document>();
            model.documents.Add(new RequesttModel.Document()
            {
                id = "1",
                language = "ja",
                text = targetMessage
            });

            HttpResponseMessage aResponse = null;
            byte[] byteData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(model));
            using (var content = new ByteArrayContent(byteData))
            {
                content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                aResponse = await aClient.PostAsync(uri, content);
            }

            if (aResponse.IsSuccessStatusCode)
            {
                using (var readst = await aResponse.Content.ReadAsStreamAsync())
                using (var stream = new StreamReader(readst))
                {
                    var result =
                        JsonConvert.DeserializeObject<ResponseModel.Keyphrases>(stream.ReadToEnd());
                }
            }
        }


    }


ModelはJsonを貼り付けただけのものですが、以下のものを使っています。

    public class RequesttModel
    {

        public class Rootobject
        {
            public List<Document> documents { get; set; }
        }

        public class Document
        {
            public string language { get; set; }
            public string id { get; set; }
            public string text { get; set; }
        }

    }
    public class ResponseModel
    {

        public class Rootobject
        {

            public Languagedetection languageDetection { get; set; }
            public Keyphrases keyPhrases { get; set; }
            public Sentiment sentiment { get; set; }
        }

        public class Languagedetection
        {
            public List<Document> documents { get; set; }
            public List<object> errors { get; set; }
        }

        public class Document
        {
            public string id { get; set; }
            public List<Detectedlanguage> detectedLanguages { get; set; }
        }

        public class Detectedlanguage
        {
            public string name { get; set; }
            public string iso6391Name { get; set; }
            public float score { get; set; }
        }

        public class Keyphrases
        {
            public List<Document1> documents { get; set; }
            public List<object> errors { get; set; }
        }

        public class Document1
        {
            public string id { get; set; }
            public List<string> keyPhrases { get; set; }
        }

        public class Sentiment
        {
            public List<Document2> documents { get; set; }
            public List<object> errors { get; set; }
        }

        public class Document2
        {
            public string id { get; set; }
            public float score { get; set; }
        }
    }

Cognitive Service × Json × 自動Model生成

Visual Stuidioには、Json(もしくはXML)からプロパティを自動で生成してくれる機能があります。
今回はその機能の使い方をまとめていきたいと思います。


例えば、CognitiveService*1APIを呼び出して操作を行う場合、Newtonsoft.Jsonなどのライブラリを使いながら、Jsonデータをentityに変換してから操作を行います。
そうなったとき、自分は今までJsonを横において、使いたいプロパティを定義していく・・・という途方もない作業をしていました。

しかし、素晴らしいVisual Stuidioでは、こんな作業しなくてもよかったのです。

その機能が、「形式を選択して貼り付け」機能です!

どんなものかということを、Text Analyticsを例に紹介します。
まず、Text AnalyticsのサンプルJsonをコピーしてみます。
f:id:kinakomotitti:20171110220356p:plain

次に、Visual Studioで適当な名前のクラスを作成します。
f:id:kinakomotitti:20171110220614p:plain

そして、先ほどコピーしたJsonを形式を選択して貼り付けます。
Visual Studioの[編集] - [形式を選択して貼り付け]を選択し、[Jsonクラスとして貼り付け]をクリックします。
f:id:kinakomotitti:20171110221214p:plain

すると、以下の画像のように、Jsonで定義されている情報がプロパティを持ったクラスファイルとして出力されます!
f:id:kinakomotitti:20171110221048p:plain

クラスの中はこんな感じです。一部気になるところはありますがw*2
f:id:kinakomotitti:20171110222022p:plain


はてしなく便利な機能ですね!
今後たくさん使っていこうと思います!

ちなみに、英語では[Paste Special]って名前だそうです。

*1:例えばText Analyticsとか→ Text Analytics API | Microsoft Azure

*2:プロパティの名前の先頭が小文字になってしまっているので、コードチェックの警告が出てますね・・・

log4net × Lock Model × Mutex(続き)

InterProcessLockというModelクラスの実装についての記事の続きです。

 

どのようにしてMutexを使ってロックをかけているかを順番に見ていきます。

順番は以下の通りです。

  1. ファイルオープン
  2. ロック要求 ←特にここ
  3. ロック解除  ←特にここ
  4. ファイルクローズ

1.ファイルオープン

f:id:kinakomotitti:20171104213503p:plain

特別なことはありませんが、前に紹介したStreamを生成するメソッドを実行しているだけです。

例外処理が特殊で理解が追い付いていません・・・

ただ、メッセージは個人的にしたのコメントアウトしたような書き方が好きですね。。。(どうでもいいw)

f:id:kinakomotitti:20171104213910p:plain

 

2.ロック要求

続いて、ロックを要求する処理です。

TODOが残っているあたり、今後変更されるかもしれませんね。

f:id:kinakomotitti:20171104214004p:plain

mutexのインスタンスがnull出ないときだけ処理を行い、mutexがないときは例外処理を行います。

ここで、mutexのインスタンスに処理が許可されるまで待ち続けるWaitOneメソッドを利用しています。

こうやってロックの制御を実行しているのですね!

 

3.ロック解除

f:id:kinakomotitti:20171104220940p:plain

特に気になるところがありません。。。

しっかりとMutexリリース前にフラグの制御をしているというところがあるだけでしょうか。。。

 

4.ファイルクローズ

f:id:kinakomotitti:20171104221003p:plain

シンプルですが、Streamをクローズし、Streamを格納していた変数にnullを代入して処理を終えています。

処理の最後にはロックを解除するメソッド(3.のやつ)を実行します。

 

・・・順番が微妙でしたが、ファイルを開くところと、ロックをかけるところの実装が一通り確認できました!

今後は、FileAppenderの起動処理 をメインに見ていこうと思います!

HttpClient × WebClient × HttpWebRequest

十分に理解していないためか、よく3つの違いを忘れてしまうので、戒めのためにも3つの違いをまとめておきます。

  1. System.Net.HttpWebRequest/HttpWebRespons
  2. System.Net.WebClient
  3. System.Net.Http.HttpClient

実装編

実装シナリオ:

あるURLにGETリクエストを投げて、レスポンスのコンテンツをStringの変数に格納する。

1の場合 

f:id:kinakomotitti:20171108224443p:plain

 

2の場合

f:id:kinakomotitti:20171108220216p:plain

 

3の場合

f:id:kinakomotitti:20171108220153p:plain

 (多分あってるよね・・・)

使い方の話

 WebClientはHttpWebRequestをラップして使いやすくしたクラスです。

ラップしているため、HttpWebRequestに比べてパフォーマンスは低下しているそうですが、通信のためのコード量を減らすことができます。

HttpClientは、.NET Framework 4.5で追加されたクラスで、WebClientよりもよりHTTPの仕様に近づいたものになります。

GET、POSTなど、よりわかりやすいメソッドが提供されていますが、バグのような仕様があるそうなので注意して使う必要があります。

 

開発者を苦しめる.NETのHttpClientのバグと紛らわしいドキュメント

 

My two cents on WebClient vs HttpClient vs HttpWebRequest | InfoWorld

 

 

 

 

 

 

log4net × FileStream × Using

log4netでは、ファイルの排他制御にLockModelクラスを利用しています。

そのLockModelクラスでは、ファイルの出力操作にFileStreamを使って出力を行います。(LockModelには3つの種類がありますが、どのModelを使ってもFileStreamを利用します。)

 

出力の準備処理の実装がこれです!

f:id:kinakomotitti:20171103235500p:plain

呼び出し元から、File名と、ファイルに上書きするか、追記するかのフラグと、アクセス制御に関するEnumを受け取り、FileStreamを呼び出し元に返す処理を実行します。

 

実装から見てわかる通り、log4netでは、指定されたファイル名から、ディレクトリ名を取り出し、そのディレクトリがなければ生成してくれるようです。

確かに、いつの間にかLogフォルダがbinフォルダに生成されたりしますね!

 

仕様を軽く見たところで、実装面で気になった所を見ていくことにします。

今回特に気になった実装は・・・ここの部分!

 

 

f:id:kinakomotitti:20171104000203p:plain

 

 

・・・ではなく、ここです!

f:id:kinakomotitti:20171104000326p:plain

上記の実装も、IFで実装するより、シンプルにわかりやすく実装されているので、とても参考になりますが、このUsingの使い方は初めてみたので、こちらを見ていくことにしました。

そもそも、usingのメリットは大きく2つあると思います。

 1)usingで宣言した変数を確実にDisposableしてくれる。

 2)Try~Finallyと同じ効果(例外を握りつぶす)

今回の実装では、Usingしている変数は以下のように定義されている抽象クラスのものになるので、2)の目的で利用されているのではないかと考えています。

f:id:kinakomotitti:20171104002726p:plain

IDisposableはそのままではusingで宣言できないので、上記のようにすることでimpersonate(偽装)しているのだと思います。

今までusingしたいけど、IDisposableを継承した変数がなかったときは仕方なくtryを書いていました。

しかし、この実装テクニックがあれば今後はより気軽にUsingを使っていけると思いました!

Thinkpad x1 carbon (2014) × タッチパット換装 × Fall Creators Update

備忘録として残しておきます。

以前Thinkpad x1 carbon のタッチパットを換装しました。

 

最近まで順調に動作していたのですが、Windows 10 Fall Creators Updateを適用した後、急にクリックができなくなりました。。。

 

換装時に変更したタッチパットのレジストリの値が、アップデートの際に元に戻ってしまったことが原因っぽいです。

 

自分の環境では、以下の手順で解決しました。

1)対象のレジストリの値を以下の情報に修正

  特に、これマークがついているやつ。

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SynTP\Parameters]
"SuppressPossibleJumps"=dword:0000007b  ←これ
"LidOpenCloseFlags"=dword:00000001
"ExtraCapabilities7Add"=dword:00010000   ←これ
"ExtraCapabilities7Mask"=dword:ffffffff  ←これ
"LidCloseKey"=dword:0000e058
"LidOpenKey"=dword:0000e059

2)再起動

 

レジストリにはあまり詳しくないので、これでよかったのかはわかりませんが、動いたのでとりあえずよいかなw

 

 

log4net × Lock Model × Mutex

 log4netの起動処理の追っかけは難しかったので、いったん飛ばしておきます。

とりあえず、次のステップのFileAppenderの処理について細かくみていきます・・・

 

FileAppenderクラスはこんな感じに実装されています!

f:id:kinakomotitti:20171031222941p:plain

 

ということで、上から見ていきます。

ロックモデルについて。

ロックモデルは、FileAppenderを使ってログを出力するときに、出力中のファイルに対して、どのように排他制御を行うかを決める方法のようなものです。

実行環境によって使えるモデルと使えないモデルがありますが、.NET Frameworkを利用するばあいは、3つのモデルを利用することができます。

それぞれは以下の通り。

1)InterProcessLock

ファイル名を使った名前のmutexインスタンスを使ってロックを管理。

2)MinimalLock

出力するときだけファイルをロックする。

複数プロセスから1つのログファイルに対してログを出力しようとするときなどに利用する。

(複数スレッドから1つのログファイルに出力するのは、3)のロックでも可能)

3)ExclusiveLock

初期値。ひとたびログファイルをOpenしたら、Closeされるまでロックをかけ続けるわかりやすいロック。

ロック中にサクラエディタとかを使ってファイルを開こうとすると、「他のプロセスによって・・・」の警告がでて、読み取り専用でしか開けなくなる。

 

個々の実装はそれぞれ読み解くとして、まず気になるのは、1)で使われている多重起動禁止用の実装についてです。

Mutex。初めて知りました。

System.Threading名前空間にあるクラスで、多重起動を抑制する機能を持っているようです。

多重起動を禁止するアプリを作るときは、プロセスの名前を取得して比較するしか方法がないと思っていたので、とても勉強になりました!

このMutexクラスでは、基本的に、ユーザーごとの多重起動を禁止することができるようですが、MutexNameの先頭に「Global\」をつけることですべてのユーザーに対して多重起動を禁止することができるようになります。

 

以上をふまえてlog4netを見てみると・・・

f:id:kinakomotitti:20171031230920p:plain

log4netでは、ファイル名を使ってMutexNameを作成している。

・Globalをつけていないので、ユーザーごとに多重起動を禁止する。

という仕様のようです。

~~~~~~~~~~~~~~~~~~~~~~~~~~~

長くなってきたので、分割します!