需要帮助 JSON post 适用于高于 8.0.0 的 EpiServer CMS 版本
Need help getting JSON post working for EpiServer CMS version higher than 8.0.0
我们有多个 EpiServer 站点,我们正在将 post JSON 的功能添加到站点监控 API。我能够让 JSON post 在我们的 EpiServer CMS 8.0.0 版网站上成功运行,但在 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语句也在class.
using System.Net.Http;
using System.Net.Http.Headers;
以上在我们的 EpiServer CMS 8.0.0 解决方案中取得成功。但是,当我们将相同的代码移植到更高版本的 CMS 之一时,posts 会卡在这一行:
HttpResponseMessage response = await httpClient.PostAsJsonAsync(access.EndpointDirectory, content);
"gets stuck" 我的意思是 Visual Studio 调试器在该行停止并且永远不会继续到下一行。
研究这个,我发现了使用 PostAsync
而不是 PostAsJsonAsync
的建议。所以这是我对 EpiServer 9 解决方案的尝试之一。但这最终 posting 为 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中的post,成功代码的Content-Type为application/json
。但是不成功的代码块的 Content-Type 为 text/plain
。我认为 Content-Type 是基于 StringContent
对象,我将 ContentType 设置如下:
StringContent stringContent = new StringContent(jsonMaintenanceEvent, Encoding.UTF8, "application/json");
我不明白为什么 PostAsync
忽略该设置。该对象的媒体类型为 application/json
。
如果我将 post 从 PostAsync
更改为 PostAsJsonAsync
,post 就会卡住,如上所述。
最终我只需要让 JSON post 在高于 8.0.0 的 EpiServer 版本中工作。 在为此工作了几天之后,这真是莫名其妙。感谢您的帮助。
我不知道调用代码是什么样的,但发生的是死锁,您可以通过在 PostAsJsonAsync
调用中使用 .ConfigureAwait(false)
来避免这种情况,如下所示:
HttpResponseMessage response = await httpClient.PostAsJsonAsync(access.EndpointDirectory, content).ConfigureAwait(false);
您可以在此处阅读有关使用 async/await 时的死锁的更多信息:http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
他的例子看起来很像你的问题。
- The top-level method calls GetJsonAsync (within the UI/ASP.NET context).
- GetJsonAsync (within the UI/ASP.NET context).
GetJsonAsync starts the REST request by calling HttpClient.GetStringAsync (still within the context).
- GetStringAsync returns an uncompleted Task, indicating the REST request is not complete.
- GetJsonAsync awaits the Task returned by GetStringAsync. The context is captured and will be used to continue running the GetJsonAsync method later. GetJsonAsync returns an uncompleted Task, indicating that the GetJsonAsync method is not complete.
- The top-level method synchronously blocks on the Task returned by GetJsonAsync.
This blocks the context thread.
- … Eventually, the REST request will complete. This completes the Task that was returned by GetStringAsync.
- The continuation for GetJsonAsync is now ready to run, and it waits for the context to be available so it can execute in the context.
- Deadlock. The top-level method is blocking the context thread, waiting for GetJsonAsync to complete, and GetJsonAsync is waiting for the context to be free so it can complete.
Stephen 列出了 2 种避免死锁的方法
In your “library” async methods, use ConfigureAwait(false) wherever possible.
和
Don’t block on Tasks; use async all the way down.
在没有看到实际调用您的 SendMaintenanceEvent
方法的代码的情况下,很难判断真正导致死锁的原因。
我们有多个 EpiServer 站点,我们正在将 post JSON 的功能添加到站点监控 API。我能够让 JSON post 在我们的 EpiServer CMS 8.0.0 版网站上成功运行,但在 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语句也在class.
using System.Net.Http;
using System.Net.Http.Headers;
以上在我们的 EpiServer CMS 8.0.0 解决方案中取得成功。但是,当我们将相同的代码移植到更高版本的 CMS 之一时,posts 会卡在这一行:
HttpResponseMessage response = await httpClient.PostAsJsonAsync(access.EndpointDirectory, content);
"gets stuck" 我的意思是 Visual Studio 调试器在该行停止并且永远不会继续到下一行。
研究这个,我发现了使用 PostAsync
而不是 PostAsJsonAsync
的建议。所以这是我对 EpiServer 9 解决方案的尝试之一。但这最终 posting 为 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中的post,成功代码的Content-Type为application/json
。但是不成功的代码块的 Content-Type 为 text/plain
。我认为 Content-Type 是基于 StringContent
对象,我将 ContentType 设置如下:
StringContent stringContent = new StringContent(jsonMaintenanceEvent, Encoding.UTF8, "application/json");
我不明白为什么 PostAsync
忽略该设置。该对象的媒体类型为 application/json
。
如果我将 post 从 PostAsync
更改为 PostAsJsonAsync
,post 就会卡住,如上所述。
最终我只需要让 JSON post 在高于 8.0.0 的 EpiServer 版本中工作。 在为此工作了几天之后,这真是莫名其妙。感谢您的帮助。
我不知道调用代码是什么样的,但发生的是死锁,您可以通过在 PostAsJsonAsync
调用中使用 .ConfigureAwait(false)
来避免这种情况,如下所示:
HttpResponseMessage response = await httpClient.PostAsJsonAsync(access.EndpointDirectory, content).ConfigureAwait(false);
您可以在此处阅读有关使用 async/await 时的死锁的更多信息:http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
他的例子看起来很像你的问题。
- The top-level method calls GetJsonAsync (within the UI/ASP.NET context).
- GetJsonAsync (within the UI/ASP.NET context). GetJsonAsync starts the REST request by calling HttpClient.GetStringAsync (still within the context).
- GetStringAsync returns an uncompleted Task, indicating the REST request is not complete.
- GetJsonAsync awaits the Task returned by GetStringAsync. The context is captured and will be used to continue running the GetJsonAsync method later. GetJsonAsync returns an uncompleted Task, indicating that the GetJsonAsync method is not complete.
- The top-level method synchronously blocks on the Task returned by GetJsonAsync. This blocks the context thread.
- … Eventually, the REST request will complete. This completes the Task that was returned by GetStringAsync.
- The continuation for GetJsonAsync is now ready to run, and it waits for the context to be available so it can execute in the context.
- Deadlock. The top-level method is blocking the context thread, waiting for GetJsonAsync to complete, and GetJsonAsync is waiting for the context to be free so it can complete.
Stephen 列出了 2 种避免死锁的方法
In your “library” async methods, use ConfigureAwait(false) wherever possible.
和
Don’t block on Tasks; use async all the way down.
在没有看到实际调用您的 SendMaintenanceEvent
方法的代码的情况下,很难判断真正导致死锁的原因。