我们有多个EpiServer站点,我们正在添加将JSON发布到站点监控API的功能。我能够在我们的EpiServer CMS 8.0.0版本站点上成功运行JSON帖子,但遇到了CMS版本8.8.1及更高版本的问题。
以下是我们成功的工作代码的样子。
private async Task SendMaintenanceEvent(object maintenanceEvent)
{
string endpoint = "https://OurEndpointURL.com/omitted/";
string endpointDirectory = "target";
// Provide basic authorization. Credentials must be base-64 encoded to be recognized.
string credentials = "AuthCredentialsOmitted";
string credentialsBase64 = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(credentials));
// Convert the maintenanceEvent object to consumable JSON.
string maintenanceEventJson = System.Web.Helpers.Json.Encode(maintenanceEvent);
StringContent content = new StringContent(maintenanceEventJson, Encoding.UTF8, "application/json");
using (HttpClient httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(endpoint);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentialsBase64);
HttpResponseMessage response = await httpClient.PostAsJsonAsync(endpointDirectory, content);
if (!response.IsSuccessStatusCode)
{
throw new System.Exception("Error sending maintenance event.");
}
}
}
上面的方法取决于几个using语句也在这个类中。
using System.Net.Http;
using System.Net.Http.Headers;
上述内容在我们的EpiServer CMS 8.0.0解决方案中取得了成功。但是当我们将相同的代码移植到一个较高的CMS版本时,帖子就会停留在这一行:
HttpResponseMessage response = await httpClient.PostAsJsonAsync(access.EndpointDirectory, content);
被卡住了#34;我的意思是Visual Studio调试器在该行停止,并且永远不会进入下一行。
研究这一点,我发现了使用PostAsync
代替PostAsJsonAsync
的建议。所以这是我对EpiServer 9解决方案的一次尝试。但最终会以text/plain
而不是application/json
发布。
private async Task SendMaintenanceEvent(object maintenanceEvent)
{
string endpointAddress = "https://OurEndpointURL.com/omitted/";
string endpointDirectory = "target";
// Provide basic authorization. Credentials must be base-64 encoded to be recognized.
string credentials = "AuthCredentialsOmitted";
string credentialsBase64 = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(credentials));
// Convert the maintenanceEvent object to consumable JSON.
//string maintenanceEventToPost = System.Web.Helpers.Json.Encode(maintenanceEvent);
//StringContent stringContent = new StringContent(maintenanceEventToPost, Encoding.UTF8, "application/json");
string jsonMaintenanceEvent = JsonConvert.SerializeObject(maintenanceEvent);
StringContent stringContent = new StringContent(jsonMaintenanceEvent, Encoding.UTF8, "application/json");
using (HttpClient httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(endpointAddress);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentialsBase64);
HttpResponseMessage httpResponseMessage = await httpClient.PostAsync(endpointDirectory, stringContent);
if (!httpResponseMessage.IsSuccessStatusCode)
{
throw new System.Exception("Error sending maintenance event to Monitor.");
}
}
}
比较Fiddler中的帖子,成功的代码的内容类型为application/json
。但是,不成功的代码块的Content-Type为text/plain
。我认为Content-Type基于StringContent
对象,我已按如下方式设置ContentType:
StringContent stringContent = new StringContent(jsonMaintenanceEvent, Encoding.UTF8, "application/json");
我不明白为什么PostAsync
无视这种设定。该对象的mediaType为application/json
。
如果我将帖子从PostAsync
更改为PostAsJsonAsync
,那么帖子就会卡住,如上所述。
最终我只需要让JSON帖子在高于8.0.0的EpiServer版本中工作。在这个工作了好几天后,这简直令人费解。谢谢你的帮助。
答案 0 :(得分:1)
我不知道调用代码是什么样的,但发生了什么是死锁,你可以通过.ConfigureAwait(false)
调用PostAsJsonAsync
来避免这种情况:
HttpResponseMessage response = await httpClient.PostAsJsonAsync(access.EndpointDirectory, content).ConfigureAwait(false);
在此处使用async / await时,您可以阅读有关死锁的更多信息:http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
他的例子看起来很像你的问题。
斯蒂芬列出了两种避免死锁的方法
- 顶级方法调用GetJsonAsync(在UI / ASP.NET上下文中)。
- GetJsonAsync(在UI / ASP.NET上下文中)。 GetJsonAsync通过调用HttpClient.GetStringAsync(仍然在上下文中)启动REST请求。
- GetStringAsync返回未完成的任务,表示REST请求未完成。
- GetJsonAsync等待GetStringAsync返回的任务。捕获上下文,稍后将用于继续运行GetJsonAsync方法。 GetJsonAsync返回未完成的Task,表示GetJsonAsync方法未完成。
- 顶级方法同步阻止GetJsonAsync返回的任务。 这会阻止上下文线程。
- ...最终,REST请求将完成。这样就完成了GetStringAsync返回的任务。
- GetJsonAsync的延续现在已准备好运行,它等待上下文可用,以便它可以在上下文中执行。
- 死锁。顶级方法是阻塞上下文线程,等待GetJsonAsync完成,GetJsonAsync正在等待上下文空闲,以便它可以完成。
醇>
在“库”异步方法中,尽可能使用 ConfigureAwait(false)。
和
不要阻止任务;一直使用async。
如果没有看到实际调用SendMaintenanceEvent
方法的代码,就很难分辨实际导致死锁的原因。