正确使用Azure持久功能-序列化复杂对象

时间:2018-10-10 10:36:47

标签: c# azure azure-functions azure-durable-functions

因此,我正在制作一些 Azure持久函数的原型,以尝试了解它们是否适合我们内部API系统的建议解决方案。

基于示例,我创建了一个 Orchestrator客户端HelloOrchestratorClient.cs),它可以响应HttpTrigger。该客户端从原始请求中提取了一些信息,然后继续执行 Orchestrator函数HelloOrchestrator.cs),传入了一些提取的信息:

复杂的HelloOrchestratorClient.cs:

[FunctionName("HttpSyncStart")]
public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, methods: "get", Route = "orchestrators/{functionName}/wait")]
    HttpRequestMessage req,
    [OrchestrationClient] DurableOrchestrationClient starter,
    string functionName,
    ILogger log)
{       
    HttpReq originalRequest = new HttpReq() {
            DeveloperId = GetDevKey(req,apiHeaderKey),
            QueryString = req.RequestUri.Query,
            APIName = GetQueryStringValue(req,APIName),
            APIVersion = GetQueryStringValue(req,APIVersion)

    };
    string instanceId =   await starter.StartNewAsync(functionName, originalRequest);

    TimeSpan timeout = GetTimeSpan(req, Timeout) ?? TimeSpan.FromSeconds(30);
    TimeSpan retryInterval = GetTimeSpan(req, RetryInterval) ?? TimeSpan.FromSeconds(1);

    return  await starter.WaitForCompletionOrCreateCheckStatusResponseAsync(
        req,
        instanceId,
        timeout,
        retryInterval);

}

暂时HelloOrchestrator.cs只是使用我们的一个内部API调用并返回一个JsonProduct负载(使用{{1},简单的POCO描述了标题), }命名为ActivityTigger来进行API调用。

复杂的HelloOrchestrator.cs:

HelloOrchestrator.APICall

侧注:该计划是,如果我能使它正常工作,那就是将一堆进程散开到不同的API,然后再次散开,合并JSON有效负载,然后将其返回到发起人。

正在遇到问题

因此,当我的 [FunctionName("E1_JsonProduct")] public static async Task<List<JsonProduct>> Run( [OrchestrationTrigger] DurableOrchestrationContextBase context, ILogger log) { List<JsonProduct> output = new List<JsonProduct>(); HttpReq r = context.GetInput<HttpReq>(); if(r != null) { if(r.DeveloperId == null) { return output; } output.Add(await context.CallActivityAsync<JsonProduct>("E1_CallAPI",r)); return output; } return output; } [FunctionName("E1_CallAPI")] public async static Task<JsonProduct> APICall([ActivityTrigger] HttpReq req, ILogger log) { JsonProduct products = null; string u = $"{baseAddress}{req.APIVersion}/{req.APIName}{req.QueryString}"; var request = new HttpRequestMessage(HttpMethod.Get, u); request.Headers.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json") ); request.Headers.Add("x-apikey",req.DeveloperId); log.LogInformation($"URL calling = '{request.RequestUri.AbsoluteUri}'."); HttpResponseMessage response = await client.SendAsync(request); // return await response.Content.ReadAsStringAsync(); if(response.IsSuccessStatusCode) { var formatter = new JsonMediaTypeFormatter { SerializerSettings = HelloProj.CosmosDB.Models.Products.Converter.Settings }; products = await response.Content.ReadAsAsync<JsonProduct>(new [] {formatter}); } return products; } List<JsonProduct>返回时,我收到了在此Gist上找到的以下HelloOrchestrator.Run(大堆栈跟踪),并且我收到了 Orchestrator客户端的> 500响应。

以下证明返回的NullReferenceException在运行时确实有一个对象:

Runtime Screen Grab of output

是否可能由于output的复杂性(再次找到模型类here)?我问,因为当我将我的 Orchestrator函数换成更简单的模型结构时,我 收到500,我收到了JSON有效载荷。

此示例显示了简单协调器函数 JsonProduct,返回了一个简单的HelloOrchestrator.csGist for model)平面对象,该对象没有错误

简单的HelloOrchestrator.cs:

TestToDo.cs

更多信息

如果您需要我的完整原型项目,可以在这里找到它们:

运行它时,请在Postman之类的文件中使用以下内容(在F5加载后):

  

http://localhost:7071/api/orchestrators/E1_JsonProduct/wait?timeout=20&retryInterval=0.25&api=products&apiVersion=v1&filterByImprints=W%26N&N

运行它时,请在Postman之类的东西中使用以下命令(在F5加载后):

  

http://localhost:7071/api/orchestrators/E1_Todo/wait?timeout=20&retryInterval=0.25

1 个答案:

答案 0 :(得分:1)

看看您发布的调用堆栈,NullReferenceException似乎是DurableOrchestrationClient类中的错误。查看代码(可以找到here)似乎是有可能的,如果无法正确解析您正在使用的查询字符串,则可以使用null-ref。

您提到您正在使用以下URL进行测试:

  

http://localhost:7071/api/orchestrators/E1_JsonProduct/wait?timeout=20&retryInterval=0.25&api=products&apiVersion=v1&filterByImprints=W%26N&N

我想知道最后两个字符(&N)是否是问题的根源。是否可以对&进行编码或将其完全删除以找出问题所在?

无论哪种方式,如果您可以在此处记录问题,那就太好了:https://github.com/Azure/azure-functions-durable-extension/issues