2017-06-20 7 views
0

コンストラクタを使用して初期化することによって設定される外部ログ用のクラスを作成したいとします。私は、このクラスをFunctionの全期間を通して複数回使用できるようにしたいと考えています。Azure関数でクラスを使用する

using System.Net; 

private static Logger logger; 

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, 
TraceWriter log, ExecutionContext executionContext) 
{ 
    log.Info("C# HTTP trigger function processed a request."); 

    string invocationId = executionContext.InvocationId.ToString(); 
    logger = new Logger(invocationId); 

    logger.Log("Start"); 

    // parse query parameter 
    string name = req.GetQueryNameValuePairs() 
    .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0) 
    .Value; 

    // Get request body 
    dynamic data = await req.Content.ReadAsAsync<object>(); 

    // Set name to query string or body data 
    name = name ?? data?.name; 

    logger.Log("Finish"); 

    return name == null 
    ? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body") 
    : req.CreateResponse(HttpStatusCode.OK, "Hello " + name); 
} 

public class Logger 
{ 
    private string _invocationId; 

    public Logger(string invocationId) 
    { 
     _invocationId = invocationId; 
    } 

    public void Log(string message) 
    { 
     message = $"{_invocationId} | {message}"; 
     // log to Splunk 
    } 
} 

Loggerクラスを関数全体で「グローバルに」使用する正しい方法はありますか?

private static Logger logger; 

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, 
TraceWriter log, ExecutionContext executionContext) 
{ 
    log.Info("C# HTTP trigger function processed a request."); 

    string invocationId = executionContext.InvocationId.ToString(); 
    logger = new Logger(invocationId); 

新しくクラスアップしたことは何ですか?

これは私が達成しようとしているものの簡略化されたバージョンです。

+1

ロガーを使用しているスレッドと別のスレッドとの間で競合状態が発生する可能性があるため、静的フィールドとしてはloggerを使用したくないと思います。 – stuartd

+0

@stuartdこんにちはスチュアート、返信いただきありがとうございます。 Runメソッドが静的でなければならないので、静的でないロガーを作成するとエラーが発生することがあります。 "非静的なフィールド、メソッド、またはプロパティにオブジェクト参照が必要です"。 – Chris

+0

@mikhailが彼の答えで示唆しているように、それをローカル変数にします。 – stuartd

答えて

3

コードはあまり意味がありません。静的なフィールドがありますが、呼び出すたびに割り当てます。 2番目の呼び出しは最初の呼び出しによって作成された値を上書きする可能性があるため、予期しない結果が得られる可能性があります。

フィールドは静的で、一度作成してから次のすべての呼び出しでインスタンスを使用するか、または、ローカル変数を作成して、それを今のように使用するだけです。

2つ目のオプションは、本当に何かリクエストを共有する必要がない限り、優先します。可能であれば共有状態を避けてください。

UPDATE:あなたのコメントからの質問に基づいて

は、ここにあなたが何ができるかです:

public static Task<HttpResponseMessage> Run(
    HttpRequestMessage req, ExecutionContext executionContext) 
{ 
    string invocationId = executionContext.InvocationId.ToString(); 
    var processor = new Processor(invocationId); 
    return processor.Process(req); 
} 

public class Processor 
{ 
    private Logger logger; 

    public Processor(string invocationId) 
    { 
     this.logger = new Logger(invocationId); 
    } 

    public async Task<HttpResponseMessage> Process(HttpRequestMessage req) 
    { 
     await this.logger.Log("Start"); 
     await this.DoStep1(); 
     await this.DoStep2(); 
     await this.logger.Log("Finish"); 
    } 

    private async Task DoStep1() 
    { 
     await this.logger.Log("Step 1"); 
     // ... 
    } 

    private async Task DoStep2() 
    { 
     await this.logger.Log("Step 2"); 
     // ... 
    } 
} 

私はこのスタイルの特定のファンではないんだけど、それはあなたが欲しいものだ場合は、それは正常に動作します。

+0

返事をありがとうMikhail。私がstuartdへのコメントで言ったように、Runメソッドは静的でなければならないので、静的でないロガーを作成するとエラーが発生する。 "非静的なフィールド、メソッド、またはプロパティにオブジェクト参照が必要です"。 私はそれをローカル変数にすることができますが、他のメソッドを作成してそれらのメソッドの内部にログインする必要がある場合は、渡す必要があります。とにかくその標準的な練習ですか? – Chris

+0

@chrisはい、「実行」は静的でなければなりません。実際に 'logger'をパラメータとして渡すことも、' Processor'クラスのようなものを作成して、 'Run'実行ごとにインスタンス化し、' logger'をそのクラスのフィールドにして、すべての処理機能をクラスの中に入れることができます。 – Mikhail

+0

あなたは私が理解しているかわからないので、あなたが意味するものを実証してください、謝罪することができますか? – Chris

関連する問題