2017-06-20 27 views
0

我想創建一個外部日誌記錄類,它通過構造函數初始化來設置。然後我希望能夠在整個函數生命週期中多次使用這個類。在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 
    } 
} 

這是在整個函數中使用我的記錄器類「全局」的正確方法嗎?

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

您的代碼沒有多大意義:您有一個靜態字段,但您在每次調用時都指定它。第二次調用可能會覆蓋第一次調用創建的值,因此您可能會得到不可預知的結果。

您應該選擇:或者您的字段是靜態的,您可以創建一次,然後在每個後續調用中使用該實例;或者您只需製作一個局部變量並按現在的方式使用它。

第二種選擇是首選,除非您確實需要跨請求共享某些內容。如果可能,避免共享狀態。

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