Quantcast
Channel: かずきのBlog@hatena
Viewing all 1388 articles
Browse latest View live

C# vNextで、ReactivePropertyはすっきり書けるのか?

$
0
0

コンストラクタが長くなることで定評のある?ReactivePropertyですが、C# vNextでプロパティ初期化のところに書けば綺麗に書けるんじゃないか!?という淡い期待を持ってる人は少なからずいると思います。

残念ながら・・・

class Person
{
    public ReactiveProperty<string> Name { get; private set; } = new ReactiveProperty<string>();

    // コンパイルエラーpublic ReactiveProperty<string> Output { get; private set; } = Name
        .Select(s => s.ToUpper())
        .ToReactiveProperty();
}

理由はエラーメッセージの通り。

A field initializer cannot reference the non-static field, method, or property 'ConsoleApplication5.Person.Name'

初期化の順番が決まらないから仕方ないっちゃぁ仕方ないですね。

C# vNextの試し方

じんぐるさんのBlogを参照しましょう!

一度設定しておいて、ファイルメニューからプロジェクトテンプレートとしてエクスポートしておくと捗ります。


伝搬合体

$
0
0

C# vNextの個人的なNo1は、自動プロパティの初期化+プライマリーコンストラクタなのですが、null伝搬演算子も慣れないとキモくて好きです。

class Person
{
    publicstring Name { get; set; }
}

----------------------------
var p = new Person();
var result = p
    // 伝搬!
    ?.Name
    // 伝搬!
    ?.ToUpper()
    // 合体! 
    ?? "NULL";
Console.WriteLine(result);

null合体演算子と使うことで、最終的に途中にnullがあったときのデフォルト値まで用意できて至れり尽くせりです。

Microsoft MVP for Windows Platform Developmentを受賞しました

$
0
0

今までClient App Devだったカテゴリが変わってWindows Platform Developmentになりました。また一年マイペースでやっていけたらと思います。

よろしくお願いします。

Windows RuntimeのXAMLで、型に応じてDataTemplateを選択したい

$
0
0

id:tmytさんのアイデアです。

DataTemplateSelectorを実装して、状況に応じてDataTemplateを何個かの中から返すというのはよくやると思います。今回は、これの汎用実装的なかんじです。型名をキーにデータテンプレートを管理するという発想です。

/// <summary>/// DataTemplate保持用クラス/// </summary>
[ContentProperty(Name="DataTemplate")]
publicclass DataTemplateHolder
{
    publicstring TypeName { get; set; }
    public DataTemplate DataTemplate { get; set; }
}

/// <summary>/// 型名をキーにDataTemplateを管理して返すDataTemplateSelector/// </summary>
[ContentProperty(Name = "Templates")]
publicclass DataTypeDataTemplateSelector : DataTemplateSelector
{
    private List<DataTemplateHolder> templates = new List<DataTemplateHolder>();
    /// <summary>/// 型名とDataTemplateのリスト/// </summary>public List<DataTemplateHolder> Templates { get { returnthis.templates; } }

    protectedoverride DataTemplate SelectTemplateCore(object item)
    {
        if (item == null)
        {
            returnnull;
        }
        // 登録してるDataTemplateに、対応する型名のものがあったらそれを返す
        var r = this.Templates.FirstOrDefault(i => i.TypeName == item.GetType().Name);
        return r != null ? r.DataTemplate : null;
    }
}

使い方

例えば、こんな2種類のクラスがあったとします。

publicclass Person
{
    publicstring Name { get; set; }
}

publicclass Dog
{
    publicstring Name { get; set; }
}

ListViewに先ほどのDataTypeDataTemplateSelectorを設定します。

<ListView ItemsSource="{Binding}"><ListView.ItemTemplateSelector><local:DataTypeDataTemplateSelector><local:DataTemplateHolder TypeName="Person"><DataTemplate><StackPanel><TextBlock Text="Personだよ" /><TextBlock Text="{Binding Name}" /></StackPanel></DataTemplate></local:DataTemplateHolder><local:DataTemplateHolder TypeName="Dog"><DataTemplate><StackPanel><TextBlock Text="Dogだよ" /><TextBlock Text="{Binding Name}" /></StackPanel></DataTemplate></local:DataTemplateHolder></local:DataTypeDataTemplateSelector></ListView.ItemTemplateSelector></ListView>

ListViewのItemsSourceにデータを設定するため、ページのコンストラクタに以下のようなコードを書きます。

public MainPage()
{
    this.InitializeComponent();
    this.DataContext = Enumerable.Range(1, 100)
        .Select(i => i % 2 == 0 ?
            (object)new Person { Name = "にんげん" + i } :
            (object)new Dog { Name = "ぽち" + i });
}

実行すると、型に応じてテンプレートが切り替わってることが確認できます。

f:id:okazuki:20140706182946j:plain

こういうユーテリティ類は懐に用意しておくとよさげですね。

****Selector改良

$
0
0

改良といっても、本家のつもりんがちゃんとしたやつのコードを載せてくれた&そっちのほうが強力なので、そっちを使うといいとおもいます・・・!

私のやつは、XAMLの階層が深くなってださかったので、ResourceDictionaryを使うようにして普段DataTemplateを設定してるのと同じ要領で作れてx:Keyを型名にするようにしてみました。

[ContentProperty(Name = "Templates")]
publicclass DataTypeTemplateSelector : DataTemplateSelector
{
    private ResourceDictionary templates = new ResourceDictionary();

    public ResourceDictionary Templates
    {
        get { return templates; }
        set { templates = value; }
    }

    protectedoverride DataTemplate SelectTemplateCore(object item)
    {
        if (item == null)
        {
            returnnull;
        }

        var dict = (IDictionary<object, object>)this.Templates;
        object result = null;
        bool ignore = dict.TryGetValue(item.GetType().Name, out result);
        return result as DataTemplate;
    }
}

使い方はこんな感じ。

<ListView ItemsSource="{Binding}"><ListView.ItemTemplateSelector><local:DataTypeTemplateSelector><DataTemplate x:Key="Person"><StackPanel><TextBlock Text="にんげんです" /><TextBlock Text="{Binding Name}" /></StackPanel></DataTemplate><DataTemplate x:Key="Dog"><StackPanel Orientation="Horizontal"><TextBlock Text="いぬです" /><TextBlock Text="{Binding Name}" /></StackPanel></DataTemplate></local:DataTypeTemplateSelector></ListView.ItemTemplateSelector></ListView>

DataTemplate以外も置けてしまうのがメリットになるかデメリットになるか…。

セキュリティの10大脅威

Web健康診断という名前のセキュリティテストの仕様書みたいなの

HTTPのリクエストをかすめとって書き換えることができるツール

$
0
0

Burp suiteというのがあるみたい。フリーエディションでも基本的な機能は使えるみたいなのでメモメモ。


EnterpriseLibrary 6のException Handling Application Block

$
0
0

暫くストアアプリとかユニバーサルアプリとか見てたらEnterprise Libraryって6になってたんですね。

例外処理は、アプリケーションの花形!(コード量的に)なので、そこをサポートしてくれる基盤はきっちり作らないといけない。ということで、Enterprise LibraryにもException Handlling Application Blockというかたちで例外処理の部品がしっかり用意されてます。

使い方

Enterprise Library 6になって、コードでかちっと簡単に構成してインスタンス化が出来るようになったみたいですね。流れるようなインターフェースや、DIコンテナ中心の考え方はさようなら。それはそれでさみしい気はするけど、使おうと思えば使えるからいいよね。新しい書き方になれませふ。

Exception Handling Application Blockでは、IEnumerableをもとにExceptionManagerのインスタンス化が出来るようになってる。

var exManager = new ExceptionManager(new[]
{
    // ExceptionPolicyDefinitionの定義
});

ExceptionPolicyDefinitionでは、定義の名前と、どの例外をどんなふうに処理するのかを表すExceptionPolicyEntryの列挙を使って作ることができる。

ExceptionPolicyEntryは、処理する例外の型と、例外を処理した結果どうするのかというのを表すPostHandlingAction列挙体と、例外の処理を表すIExcpeitonHandlerの列挙で作ることができる。PostHandlingActionは以下の値を持ってる。

  • None: なにもしない
  • NotifyRethrow: 再度例外を投げることを通知する
  • ThrowNewException: 新しい例外を投げる

IExceptionHandlerは、例外を置き換えるReplaceHandlerや、例外をラップするWrapHandlerなんかがある。Logを処理するLogging Application Blockと連携するLoggingExceptionHandlerなんかも、用意されてたりするし、自分でIExcpetionHandlerを実装するのもあり。IExceptionHandlerは、メソッドが1つしかないので以下のように簡単に定義できる。

class MyExceptionHandler : IExceptionHandler
{
    public Exception HandleException(Exception exception, Guid handlingInstanceId)
    {
        Console.WriteLine("はんどりんぐしてログとった");
        return exception;
    }
}

長くなったけど、結局、DivideByZeroExceptionはログをとって続きの処理をやって、ExceptionはMyExceptionにラップして再度投げるという定義は以下のようになる。

var definitions = new List<ExceptionPolicyDefinition>
{
    new ExceptionPolicyDefinition("default", new[]
    {
        new ExceptionPolicyEntry(
            typeof(DivideByZeroException),
            PostHandlingAction.None,
            new[]
            {
                new MyExceptionHandler()
            }),
        new ExceptionPolicyEntry(
            typeof(Exception),
            PostHandlingAction.ThrowNewException,
            new[]
            {
                new WrapHandler("wrap", typeof(MyException))
            }),
    })
};

var exManager = new ExceptionManager(definitions);

ExceptionManagerにはProcessというメソッドが定義されていてラムダ式と、ExceptionPolicyDefinitionの名前を渡して呼び出すことができる。戻り値がある版(Func)と無い版(Action)があって、割といい感じになってると思う。

以下のような感じで使える.

// ラップしてスローしてくれる
exManager.Process(() =>
{
    Console.WriteLine("throw new Exception()");
    thrownew Exception();
}, "default");

Processで例外のリスローする場合はExceptionPolicyEntryでThrowNewExceptionを指定しておかないとダメみたい。NotifyRethrowとかは、HandleExceptionという、もっと細かな制御ができるメソッドで使う。

try
{
    // 例外が発生する可能性のあるコード
}
catch (Exception ex)
{
    Exception outEx = null;
    if (exManager.HandleException(ex, "default", out outEx))
    {
        throw outEx;
    }
    else
    {
        Console.WriteLine("例外投げなくていい");
    }
}

out引数を受け取らないバージョンのHandleExceptionメソッドもあって、こっちは例外投げないといけないときは勝手に投げてくれるらしい。

他のやつも今後みていってみようかなぁ。

EnterpriseLibrary 6のSemantic Logging Application Blockを触ってみた

$
0
0

Logging Application Blockというログのがあるにも関わらず、Semantic Logging Application Blockというのが追加されてます。こいつはタイプセーフにログのAPIが作れて、いい感じだぜ?みたいなノリっぽいけど、ちゃんとドキュメント読んでないのでよくわかりません。

因みにETW(Event Tracing for Windows)(イベントログじゃないYO)を裏で使うみたいです。ETWについては、以下のBlogが詳しい感じです。因みにわたしはETWが何なのかよく知りません。

ログAPIの作り方

これは、Semantic Logging Application Blockの機能というよりは.NET 4.5から追加されたEventSourceクラスの使い方になります。

こいつをちゃんと使うと、タイプセーフなロギングAPIができるって寸法ですね。例えばこんな感じ。

[EventSource(Name = "MyEventSource")]
class MyEventSource : EventSource
{
    /// <summary>/// キーワード/// </summary>publicstaticclass Keywords
    {
        publicconst EventKeywords Diagnostic = (EventKeywords)1;
        publicconst EventKeywords Lifecycle = (EventKeywords)2;
    }

    /// <summary>/// タスク/// </summary>publicstaticclass Tasks
    {
        publicconst EventTask DB = (EventTask)1;
        publicconst EventTask App = (EventTask)2;
    }

    private MyEventSource() { }

    // シングルトンのインスタンスprivatestatic MyEventSource instance = new MyEventSource();

    publicstatic MyEventSource Log { get { return instance; } }

    // 各種ログAPI
    [Event(1, Keywords = Keywords.Lifecycle, Level = EventLevel.Informational,
        Message = "Process start", Opcode = EventOpcode.Start, Task = Tasks.App)]
    publicvoid Start()
    {
        this.WriteEvent(1);
    }

    [Event(2, Keywords = Keywords.Lifecycle, Level = EventLevel.Informational,
        Message = "Process stop", Opcode = EventOpcode.Stop, Task = Tasks.App)]
    publicvoid Stop()
    {
        this.WriteEvent(2);
    }

    [Event(3, Keywords = Keywords.Diagnostic, Level = EventLevel.Verbose,
        Message = "Execute qyeru {0}", Opcode = EventOpcode.Info, Task = Tasks.DB)]
    publicvoid Query(string query)
    {
        this.WriteEvent(3, query);
    }
}

こいつで、以下のように使うと、ETWにログが出るっていう寸法です。

MyEventSource.Log.Start();
MyEventSource.Log.Query("select * from dual");
MyEventSource.Log.Stop();

Semantic Logging Application Blockを使う

ETWのに出たログを監視して、いろんなところに出してくれるのがSemantic Logging Application Blockみたいです。NuGetでEnterpriseLibrary Semanticあたりで検索してSemantic Logging Application Blockを追加します。

そして、アプリケーションの最初の初期化処理あたりで以下のようなコードを書きます。

// リスナー作って
var l = new ObservableEventListener();
// 監視するログの種類を設定して
l.EnableEvents(
    MyEventSource.Log,
    EventLevel.Verbose,
    MyEventSource.Keywords.Diagnostic | MyEventSource.Keywords.Lifecycle);
// 何処にログを出すか決める
l.LogToConsole();

こうすると、先ほどのコードで出力したログがETWを経由してコンソールに出るようになります。実行すると以下のような感じのログが出ます。

EventId : 1, Level : Informational, Message : Process start, Payload : , EventName : AppStart, Timestamp : 2014-07-12T14:56:50.0105184Z, ProcessId : 9736, ThreadId : 8384

EventId : 3, Level : Verbose, Message : Execute qyeru select * from dual, Payload : [query : select * from dual] , EventName : DBInfo, Timestamp : 2014-07-12T14:56:50.0265193Z, ProcessId : 9736, ThreadId : 8384

EventId : 2, Level : Informational, Message : Process stop, Payload : , EventName : AppStop, Timestamp : 2014-07-12T14:56:50.0265193Z, ProcessId : 9736, ThreadId : 8384

LogToConsoleには、どのような形式で出力するか設定するフォーマッターも設定できて、JSON形式なんかで出すこともできます。

l.LogToConsole(new JsonEventTextFormatter());

出力が以下のようになります。

{"ProviderId":"8983a2e6-c5d2-5a1f-691f-db243cb1f681","EventId":1,"Keywords":2,"L
evel":4,"Message":"Process start","Opcode":1,"Task":2,"Version":0,"Payload":{},"
EventName":"AppStart","Timestamp":"2014-07-12T14:58:30.2691727Z","ProcessId":124
08,"ThreadId":7540},{"ProviderId":"8983a2e6-c5d2-5a1f-691f-db243cb1f681","EventI
d":3,"Keywords":1,"Level":5,"Message":"Execute qyeru select * from dual","Opcode
":0,"Task":1,"Version":0,"Payload":{"query":"select * from dual"},"EventName":"D
BInfo","Timestamp":"2014-07-12T14:58:30.3161730Z","ProcessId":12408,"ThreadId":7
540},{"ProviderId":"8983a2e6-c5d2-5a1f-691f-db243cb1f681","EventId":2,"Keywords"
:2,"Level":4,"Message":"Process stop","Opcode":2,"Task":2,"Version":0,"Payload":
{},"EventName":"AppStop","Timestamp":"2014-07-12T14:58:30.3431778Z","ProcessId":
12408,"ThreadId":7540},

まとめ

とりあえずコンソールに出るようになりました。LogTo****メソッドでほかにファイルやAzureのテーブルやSQL Databaseなんかに出すこともできるみたいです。

コード全体

一応コード全体のせておきます。

using Microsoft.Practices.EnterpriseLibrary.SemanticLogging;
using Microsoft.Practices.EnterpriseLibrary.SemanticLogging.Formatters;
using System.Diagnostics.Tracing;

namespace ConsoleApplication7
{
    class Program
    {
        staticvoid Main(string[] args)
        {
            // リスナー作って
            var l = new ObservableEventListener();
            // 監視するログの種類を設定して
            l.EnableEvents(
                MyEventSource.Log,
                EventLevel.Verbose,
                MyEventSource.Keywords.Diagnostic | MyEventSource.Keywords.Lifecycle);
            // 何処にログを出すか決める
            l.LogToConsole(new JsonEventTextFormatter());

            MyEventSource.Log.Start();
            MyEventSource.Log.Query("select * from dual");
            MyEventSource.Log.Stop();
        }
    }

    [EventSource(Name = "MyEventSource")]
    class MyEventSource : EventSource
    {
        /// <summary>/// キーワード/// </summary>publicstaticclass Keywords
        {
            publicconst EventKeywords Diagnostic = (EventKeywords)1;
            publicconst EventKeywords Lifecycle = (EventKeywords)2;
        }

        /// <summary>/// タスク/// </summary>publicstaticclass Tasks
        {
            publicconst EventTask DB = (EventTask)1;
            publicconst EventTask App = (EventTask)2;
        }

        private MyEventSource() { }

        // シングルトンのインスタンスprivatestatic MyEventSource instance = new MyEventSource();

        publicstatic MyEventSource Log { get { return instance; } }

        // 各種ログAPI
        [Event(1, Keywords = Keywords.Lifecycle, Level = EventLevel.Informational,
            Message = "Process start", Opcode = EventOpcode.Start, Task = Tasks.App)]
        publicvoid Start()
        {
            this.WriteEvent(1);
        }

        [Event(2, Keywords = Keywords.Lifecycle, Level = EventLevel.Informational,
            Message = "Process stop", Opcode = EventOpcode.Stop, Task = Tasks.App)]
        publicvoid Stop()
        {
            this.WriteEvent(2);
        }

        [Event(3, Keywords = Keywords.Diagnostic, Level = EventLevel.Verbose,
            Message = "Execute qyeru {0}", Opcode = EventOpcode.Info, Task = Tasks.DB)]
        publicvoid Query(string query)
        {
            this.WriteEvent(3, query);
        }


    }
}

EnterpriseLibrary 6のSemantic Logging Application BlockでAzure Storageにログをはく

$
0
0

先日触ってみたSemantic Logging Application Blockですが、ちょっと手を加えるだけでAzureのStorageやSQL Serverにログが吐き出せます。今回は、AzureのStorageに吐き出してみたいと思います。

Azureに適当にストレージを作ったらVisual Studioのサーバーエクスプローラから接続文字列を取得しておきます。そして、NuGetでEnterpriseLibrary Semantic Azureあたりで検索して「Semantic Logginc Application Block - Azure Sink」を追加します。

前回のプログラムのLogToConsoleをLogToWindowsAzureTableに変えます。引数のインスタンス名は適当でOKで、第二引数に接続文字列を渡します。

プログラムはこんな感じ。

// リスナー作って
var l = new ObservableEventListener();
// 監視するログの種類を設定して
l.EnableEvents(
    MyEventSource.Log,
    EventLevel.Verbose,
    MyEventSource.Keywords.Diagnostic | MyEventSource.Keywords.Lifecycle);
// Windows Azure Storage ServiceのTableに出力する
l.LogToWindowsAzureTable("インスタンス名",
    // 接続文字列"DefaultEndpointsProtocol=https;AccountName=semanticsample;" +
    "AccountKey=IG4TJGmpV7Mt+VSwPACIuiVIYLrZQXyI9y98/m2O/excbpS6+GLNUDl2MyfB6K3z28IlevlTT7O/difd/ZGs/g==");

MyEventSource.Log.Start();
for (int i = 0; i < 1000; i++)
{
    MyEventSource.Log.Query("select * from dual");
    Thread.Sleep(10);
}
MyEventSource.Log.Stop();

実行すると、Azureのストレージのテーブルにちゃんとログが出てるのが確認できます。(クライアントでバッファリングしてるので、最後のほうのログは抜け落ちてます。今回みたいな単発Exeには向かないのでWebアプリとかで使うのがよさそうですね)

f:id:okazuki:20140713111944j:plain

Enterprise Library 6のSemantic Logging Application Block + Reactive Extensions

$
0
0

Semantic Logging Application Blockのログですが、こいつはRxを使ってフィルタリングとかが出来ます。例えば、これまで作ってきたやつでInformation以上のログだけ表示するようにするには以下のような感じ。

// リスナー作って
var l = new ObservableEventListener();
// 監視するログの種類を設定して
l.EnableEvents(
    MyEventSource.Log,
    EventLevel.Verbose,
    MyEventSource.Keywords.Diagnostic | MyEventSource.Keywords.Lifecycle);
// LINQで色々できる!
l.Where(e => e.Schema.Level <= EventLevel.Informational)
    .LogToConsole();

まぁこの例だとEnableEventsでInformation渡せば済む話ですが…。ドキュメントには指定した条件でフラッシュするコードが例示されてました。引用しておきます。

publicstatic IObservable<T> FlushOnTrigger<T>(
    this IObservable<T> stream, Func<T, bool> shouldFlush, int bufferSize) {  
    return Observable.Create<T>(observer =>
    {
        var buffer = new CircularBuffer<T>(bufferSize);
        var subscription = stream.Subscribe(newItem =>
            {
               if (shouldFlush(newItem))
               {
                   foreach (var buffered in buffer.TakeAll())
                   {
                       observer.OnNext(buffered);
                   }
                   observer.OnNext(newItem);
               }
               else
               {
                   buffer.Add(newItem);
               }
            },
            observer.OnError,
            observer.OnCompleted);
        return subscription;  
    });
}

引数でわたしたデリゲートがTrueになったタイミングでログの内容を後続に渡す感じですね。

var listener = new ObservableEventListener(); 
listener.EnableEvents(MyCompanyEventSource.Log,
    EventLevel.Informational,
    Keywords.All); 
listener.FlushOnTrigger(entry => entry.Schema.Level <= EventLevel.Error, bufferSize: 10)
    .LogToConsole();

こんな風に使うとエラーのあった直近10個のログだけを出すという、なんともありがたい感じになってます。これはいい・・・!(ドキュメントのコピーしただけですけど)

このほかには、指定した範囲の重要度とかだけに絞るとか1つのListenerから色々分派させることができそうです。

Enterprise Library 6のSemantic Logging Application Blockで独自の出力先に出力する方法

$
0
0

過去分

はじめに

ログ関係のライブラリを使いこんでいくうちに出てくる要求として出力先をカスタマイズしたいというのはよくあると思います。Semantic Logging Application Blockでも当然そこは拡張できるように作られてるのでやってみました。

****Sinkというクラスを作る

Semantic Logging Application BlockはRxと相性がいいだけあって、ログの出力する人はEventEntryのIObserverです。OnNextを処理すればOKというわかりやすい設計。今回はコンソールに出すだけの簡単なものを作ってみました。フォーマッティングはIEventTextFormatterにお任せしてます。

// 独自の出力先class MyConsoleSink : IObserver<EventEntry>
{
    private IEventTextFormatter formatter;
    public MyConsoleSink(IEventTextFormatter formatter = null)
    {
        this.formatter = formatter ?? new EventTextFormatter();
    }

    publicvoid OnCompleted()
    {
    }

    publicvoid OnError(Exception error)
    {
    }

    publicvoid OnNext(EventEntry value)
    {
        // 値がわたってきたときだけif (value == null)
        {
            return;
        }

        // formatterで整形して出力するusing (var w = new StringWriter())
        {
            this.formatter.WriteEvent(value, w);
            Console.Write(w);
        }
    }
}

そして、IObservableと接続するための拡張メソッドを定義します。LogTo****という名前で作るのが一般的っぽいです。

// MyConsoleSink購読用拡張メソッドstaticclass MyConsoleSinkExtensions
{
    publicstatic SinkSubscription<MyConsoleSink> LogToMyConsole(this IObservable<EventEntry> self, IEventTextFormatter formatter = null)
    {
        var sink = new MyConsoleSink(formatter);
        var d = self.Subscribe(sink);
        returnnew SinkSubscription<MyConsoleSink>(d, sink);
    }
}

Subscribeして、SinkSubscriptionというものを返すのがお約束っぽいのでそれに従ってます。Semantic Logging Application BlockのログがIObservableから発行されたものをIObserverで監視して出力するだけということがわかれば、間にRxのLINQ挟み込めるのも納得ですね。

使い方

// リスナー作って
var l = new ObservableEventListener();
// 監視するログの種類を設定して
l.EnableEvents(
    MyEventSource.Log,
    EventLevel.Verbose,
    MyEventSource.Keywords.Diagnostic | MyEventSource.Keywords.Lifecycle);
// 自前のログ出力先へ出力する
l.LogToMyConsole();

MyEventSource.Log.Start();
MyEventSource.Log.Query("select * from dual");
MyEventSource.Log.Stop();

とても簡単ですね。

EnterpriseLibrary 6のValidation Application Blockを触ってみた

$
0
0

恐らく、一番機能が豊富だと思われるオブジェクトの検証機能を持ったライブラリです。標準のDataAnnotationsよりも、機能は多い(ともに使うこともできる)です。

個人的にプロパティに属性を追加して使うのが好みなので、その使い方について紹介したいと思います。

使い方

NuGetでEnterpriseLibrary Validationあたりで検索して"EnterpriseLibrary - Validation Application Block"を追加します。

Microsoft.Practices.EnterpriseLibrary.Validation.Validators名前空間にある各種****ValidatorAttributeを使ってプロパティに検証の条件を追加します。例えば名前が必須入力で、1~10文字の間の場合は以下のように定義します。

publicclass Person
{
    [NotNullValidator(MessageTemplate = "名前を入力してください")]
    [StringLengthValidator(1, 10, MessageTemplate = "名前は1~10文字です")]
    publicstring Name { get; set; }
}

バリデーションを行うには以下のようなコードになります。

// バリデーターを作成する
var validator = ValidationFactory.CreateValidator<Person>();
// 引数で渡されたオブジェクトの検証
var validationResults = validator.Validate(new Person());

// 検証結果を確認
Console.WriteLine(validationResults.IsValid); // False// OKなケース
var validationResults2 = validator.Validate(new Person { Name = "tanaka" });
Console.WriteLine(validationResults2.IsValid); // True

プロパティを増やして、属性をつけることでValidateメソッドで全プロパティの検証結果がValidationResultsという形で返ってきます。

込み入ったオブジェクトの検証

これが、ほかの奴であまり見ない機能です。例えば、先ほどのPersonクラスの名前をFirstNameとLastNameを持ったオブジェクトにしてみます。

// 名前を表すオブジェクトpublicclass NameObject
{
    [NotNullValidator(MessageTemplate = "FirstNameは必須です")]
    publicstring FirstName { get; set; }

    [NotNullValidator(MessageTemplate = "LastNameは必須です")]
    publicstring LastName { get; set; }
}

// NameObjectを持つオブジェクトpublicclass Person
{
    [NotNullValidator(MessageTemplate = "名前は必須です")]
    // ObjectValidatorをつけるとオブジェクトのプロパティも妥当性検証の対象になる
    [ObjectValidator]
    public NameObject Name { get; set; }
}

ObjectValidatorをつけると、NameObjectの中も妥当性検証を行ってくれるようになります。

// バリデーターを作成する
var validator = ValidationFactory.CreateValidator<Person>();
// 引数で渡されたオブジェクトの検証
var validationResults = validator.Validate(new Person());

// 検証結果を確認
Console.WriteLine(validationResults.IsValid); // False// OKなケース
var validationResults2 = validator.Validate(new Person 
{ 
    Name = new NameObject 
    { 
        FirstName = "taro", 
        LastName = "tanaka" 
    } 
});
Console.WriteLine(validationResults2.IsValid); // True

エラー情報を取得する

エラーの情報の取得はValidationResultsにコレクションとして入ってるのでループ回したりしてとることができます。例えば列挙する場合は以下のようになります。

// バリデーターを作成する
var validator = ValidationFactory.CreateValidator<Person>();
// 引数で渡されたオブジェクトの検証
var validationResults = validator.Validate(new Person { Name = new NameObject() });

// 検証結果を確認
Console.WriteLine(validationResults.IsValid); // Falseforeach (var r in validationResults)
{
    Console.WriteLine("プロパティ {0}: メッセージ {1}", r.Key, r.Message);
}

実行すると以下のようになります。

プロパティ FirstName: メッセージ FirstNameは必須です
プロパティ LastName: メッセージ LastNameは必須です

これは、全部のプロパティのエラーが入ってるので、特定のプロパティのみ検証したい場合は、PropertyValueValidatorを使います。こいつは属性じゃなくて、手組で検証ルールを組まないといけないです。例えばNullじゃなくてオブジェクトの検証をやる場合は以下のようになります。

var propertyValidator = new PropertyValueValidator<Person>("Name", 
    new AndCompositeValidator(
        new NotNullValidator(),
        new ObjectValidator())
    );
// 引数で渡されたオブジェクトの検証
var validationResults = propertyValidator.Validate(new Person { Name = new NameObject() });

// 検証結果を確認
Console.WriteLine(validationResults.IsValid); // Falseforeach (var r in validationResults)
{
    Console.WriteLine("プロパティ {0}: メッセージ {1}", r.Key, r.Message);
}

これでNameプロパティのみ検証が行われます。

プロパティにつけた属性を有効活用したい場合は、全体を検証したあとLINQあたりでしぼったりしないといけないと思います。

// バリデーターを作成する
var validator = ValidationFactory.CreateValidator<Person>();
// 引数で渡されたオブジェクトの検証
var validationResults = validator.Validate(new Person { Name = new NameObject() });

// 検証結果を確認
Console.WriteLine(validationResults.IsValid); // False

var result = validationResults.FirstOrDefault(r => r.Key == "Name");
if (result == null)
{
    // エラーがない
}
else
{
    // エラーがある
}

まとめ

とまぁ走り書きですが、結構豊富な機能があるんじゃないんでしょうか。

EnterpriseLibrary 6のSemantic Logging Application Blockの感想

$
0
0

過去分

既存のロギングライブラリとの個人的な比較

Semantic Logging Application Blockを触ってみた主観的な感想になります。

ログAPIの独自実装が前提

EventSourceを継承した独自のタイプセーフなログAPIの実装が必須になります。これは、ぱっと使うには少しだけめんどくさいところではありますが、汎用的なログAPIをラップして業務アプリに特化したログAPIを作ることって結構あると思います。それなら、はじめからEventSourceクラスを継承して独自APIを作ることを前提としているSemantic Logging Application Blockって、現実的なのではないかと思います。

ログのAPI

独自実装なので、好きにできます。はい。

実装のときも、固定のパラメータはアトリビュートで指定できたりと、楽できる仕組みがそろっています。

ログ出力の設定

一般的なログイングAPIでは、構成ファイルにログの設定を記述します。これはこれでいいと思うのですが、構成ファイルで決められた内容しか制御できません。Semantic Logging Application Blockでは、ログがIOとして上がってくるので、Rxを使って柔軟にフィルタリングが出来ます。これ最高に強みだと思います。コードで柔軟に設定するのって個人的には好きです。

その他カスタマイズ可能な部分

一般的なログイングライブラリでカスタマイズ可能な、出力先やフォーマットなどは一通り独自クラスを定義することで簡単に拡張可能なようになっています。ここら辺は、普通のライブラリと一緒ですね。

まとめ

ということで、とっつきにくいと感じてたSemantic Logging Application Blockは、触ってみると意外といいやつなことがわかりました。ライブラリ好きに選んでいいという.NETの話しがあったら、ちょっと使ってみようかなと思います。


Surface Pro 3でマウスカーソルが消える

$
0
0

という症状に悩まされていました。というか現在も起きてます。購入してからこの現象が起きるまでにやったことは以下。

  • Windows Update完全適用
  • Visual Studio 2013 Update 2導入

おきている状態は以下のような感じ。

  • 画面のテキストのサイズを小に設定
  • デュアルディスプレイ環境

症状としては以下のような感じ。

  • ログイン後、マウスカーソルの下に○がついてる状態が終わるとマウスカーソルが消える
  • 右クリックなどは普通にできるので位置を知ろうと思えば知れるけど目隠ししてるみたいでとてもじゃないけど操作できない

解決策として以下のような運用で回避してます。

  • Win + Pでサブディスプレイをいったん切断。
  • マウスカーソルが何故か復活する
  • Win + Pでサブディスプレイを拡張に変更
  • マウスカーソルが復活した状態で使えるようになる。

謎なうえにちょっとめんどくさいですが、現状これしか回避策が見つからなかったのでこの運用でいくしかない…!画面は広く使いたいしね。

Surface Pro 3に入れたアプリ #SurfaceJP

$
0
0

個人的にSurface Pro 3に入れて使ってるアプリのリストです。 タブレットとしてSurface Pro 3を使いたい人のためのストアアプリのリストにもなるかな?中には最初から入っているアプリもあります。

  • Flipboard
    • ニュースをざっと眺めるのに使ってます。
  • Facebook
    • Facebookの公式クライアント。PeopleでFacebookを読むことができますが、フル機能にアクセスするには、やはり純正のアプリが必要だと思います。なので、これは必須。
  • Fresh Paint
    • Surface Pro 3のペンをたしなむ程度に使うくらい。なくてもいいかも?
  • KAMIGRA
    • ノートアプリ。図形と図形をつなげるコネクタが強力です。和製アプリ。
  • OneNote
    • Surface Pro 3と切っても切れないノートアプリ。ペンをカチッとするだけで起動するお手軽さはやばいです。
  • Mevy
    • 2カラムのTwitterクライアント。長時間起動してても安定していて、画面の端にスナップや2カラムぎりぎり表示される幅で出しておくと凄くTwitterが捗ります。何かをしながらTwitterをするときの定番。
  • Aristea
    • マルチカラムの高機能Twitterクライアント。かなり高機能なので、全画面表示にしてTwitterに没頭したいときに最適です。かなり安定してる上に、強力なクエリ機能もあって好みのタイムラインをさくっと作れる点も高評価です。
  • LINE
    • まぁね。Windows 8.1対応してないけど、使えなくないから仕方ないよね。
  • Nextgen Reader
    • Feedlyを使ってるので、そのクライアント。基本機能は一通りそろってます。
  • Bing翻訳
    • 翻訳アプリ。Windows 8の共有機能を使ってリーダーアプリで英単語を選択して共有からBing翻訳を選ぶとその場で翻訳してくれます。こういう共有機能を使ってアプリを連携できるのもWindows 8.1の強み(Androidには劣りますが)

とまぁ、少ないですが、普段使ってるアプリの紹介でした。まじで使ってるアプリだけなので、結構いい感じのがそろってるのではないかと思います。

Xamarin.AndroidでHello worldというかひな形プログラムを見てみる

$
0
0

長らくReactivePropertyの検証用にしか使ってなかったXamarinですが、Genymotionを入れて現実的な速さでAndroidのエミュレータが動くようになったので、ちょいと試してみようと思います。

Xamarinを入れるとVisual StudioでAndroidのプロジェクトが作れます。

f:id:okazuki:20140723201002p:plain

新規作成すると、以下のような構造のプロジェクトが作られます。

f:id:okazuki:20140723201224p:plain

とりあえず、今回使いファイルだけ手早く説明すると以下のようになっています。 - Main.axml - メイン画面の見た目の定義 - Strings.xml - 文字列リソースを定義するXML - MainActivity.cs - Main.axmlを表示するためのアクティビティ

Strings.xml

文字列をstringタグで定義していきます。ここで定義した文字列はaxml内で、@string/nameで使うことができます。例えば、以下のファイルでApp6の文字列を使う場合は@string/ApplicationNameになります。

<?xml version="1.0" encoding="utf-8"?><resources><string name="Hello">Hello World, Click Me!</string><string name="ApplicationName">App6</string></resources>

コードから文字列を取得する場合は、Activityを継承したクラスなどで以下のように記述すると文字列をとってこれます。

this.GetString(Resource.String.ApplicationName)

Resourceクラスは、文字列リソースや画面定義などから必要な定数が自動生成されるクラスになります。Strings.xmlの内容はResource.Stringの下に定義されます。

Main.axml/MainActivity.cs

このプログラムではMain.axmlは、MainActivityで表示されるようになっています。これは自動で紐づけられるわけではなくて、MainActivityクラスのOnCreateメソッドで明示的にコードで書かれています。

OnCreateは、Androidの画面を表すActivityが作られたときに呼ばれるクラスで、ここでActivityの初期化処理なんかをやるみたいです。OnCreateで、以下のようにResourceクラスを使って、自分自身の表示コンテンツにMain.axmlを指定しています。

protectedoverridevoid OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);

    // Set our view from the "main" layout resource
    SetContentView(Resource.Layout.Main);

    // ...省略...
}

axmlファイルは、Resource.Layoutの下にaxmlファイル名で定数が定義されます。SetContentViewのメソッドに、この定数を渡すことで、画面に表示させることが出来ます。

Main.axmlは、ちょっとまだよくわかりませんが、ボタンが置いてある風なことは理解できます。

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><Buttonandroid:id="@+id/MyButton"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="@string/Hello" /></LinearLayout>

Buttonに定義されているandroid:id属性の@+id/MyButtonを使ってプログラムからボタンをひっぱってくることが出来るようになっています。@+id/MyButtonのように書くと、Resource.Idの下にMyButtonという定数が生成されるようになります。この定数を使ってActivityのFindViewByIdメソッドを使ってコントロールのインスタンスを取得できます。OnCreateの中では、以下のようにしてボタンのインスタンスを取得しています。

// Get our button from the layout resource,// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.MyButton);

個人的にはここはvar使いたいですね。なので以下のようになおしました。

// Get our button from the layout resource,// and attach an event to it
var button = FindViewById<Button>(Resource.Id.MyButton);

ボタンを取得したら、あとはクリックの処理なんかを付け足したり好きなようにできます。初期状態では、クリックしたらボタンのテキストを書き換える処理が入っています。

button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); };

個人的にdelegate使ってるのが気に入らないので以下のようにラムダ式に置き換えました。

button.Click += (_, __) => button.Text = string.Format("{0} clicks!", count++);

あと文字列リソースがあるにも関わらず、文字列をハードコーディングしているのが気に入らないのでStrings.xmlに以下の定義を追加します。

<?xml version="1.0" encoding="utf-8"?><resources><string name="Hello">Hello World, Click Me!</string><string name="ApplicationName">App6</string><string name="ClickMessage">{0} clicks!</string></resources>

そして、Clickイベントハンドラの中身を以下のようにします。

button.Click += (_, __) => button.Text = string.Format(this.GetString(Resource.String.ClickMessage), count++);

これでちょっと満足。GetStringメソッドには、書式付文字列に値を埋め込むオーバーライドがあるので、もっとすっきりかけるように感じますが、とりあえず深追いはやめておくことにします。(java.lang.Objectとかちょっと怖いので後回し)

実行して動作確認

実行すると、以下のようにボタンがあるだけの画面が出てきます。

f:id:okazuki:20140723203435p:plain

ボタンをクリックするとボタンのテキストが更新されます。

f:id:okazuki:20140723203543p:plain

まとめ

Androidというより、C#の書き方が気に入らなかったですね。

Xamarin.Androidでデバッグログを出す方法

$
0
0

Log.Debugを使います。例えば新規作成したひな形のボタンクリックのイベントハンドラを以下のように書き換えて

button.Click += (_, __) =>
{
    button.Text = string.Format(this.GetString(Resource.String.ClickMessage), count++);
    Log.Debug("App6", "{0} click!", count);
};

デバッグ実行するとボタンをおすたびにデバッグの出力ウィンドウに以下のようなメッセージが出てきます。

f:id:okazuki:20140723204115p:plain

Xamarin.Androidで、とりあえずアプリのデータが消えないようにする方法

$
0
0

最近はそうでもないのかもしれませんが、Androidに限らずモバイル向けアプリってメモリ節約のために裏側にまわるといつ落ちてもおかしくない状況になるものですよね。 そんな状態に対応する方法として、Androidは、ActivityのOnSaveInstanceStateメソッドを使うみたいです。

保存先は、BundleというクラスでPutというメソッドでデータを保存して、Getというメソッドでデータを取得できる。ということで、超簡単なコードはこんな感じになるっぽい。

using Android.App;
using Android.OS;
using Android.Widget;
using System;

namespace App10
{
    [Activity(Label = "App10", MainLauncher = true, Icon = "@drawable/icon")]
    publicclass MainActivity : Activity
    {
        private DateTime createdTime;

        protectedoverridevoid OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            if (bundle == null)
            {
                this.createdTime = DateTime.Now;
            }
            else
            {
                this.createdTime = DateTime.ParseExact(bundle.GetString("createdTime"), "yyyy/MM/dd HH:mm:ss", null);
            }

            SetContentView(Resource.Layout.Main);
            var label = this.FindViewById<TextView>(Resource.Id.Main_LabelTimeStamp);
            label.Text = this.createdTime.ToString("yyyy/MM/dd HH:mm:ss");
        }

        protectedoverridevoid OnSaveInstanceState(Bundle outState)
        {
            outState.PutString("createdTime", this.createdTime.ToString("yyyy/MM/dd HH:mm:ss"));
            base.OnSaveInstanceState(outState);
        }
    }
}

これで、Activityがメモリ不足とかで消えても、復帰時にちゃんと値が復活するという寸法。

Viewing all 1388 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>