VSTO Outlook 插件 - HttpClient.PostAsync 在没有提琴手的情况下失败
VSTO Outlook Plugin - HttpClient.PostAsync fails without fiddler
不幸的是,我在插件中开发此功能的整个过程中一直使用 Fiddler 运行ning,自从部署到客户端后,我发现它对任何人都不起作用 - 除非他们 运行 fiddler还有!如果我停止 运行ning Fiddler,它也无法在我的开发机器上运行。
主要错误是Error while copying content to a stream.
。所以我调查了我正在 POST
ing 的数据在到达服务器之前被 GC 释放的可能性(对我来说,这解释了为什么 运行ning Fiddler 解决了它——我相信请求首先发送到 Fiddler,然后 Fiddler 将其发送到服务器)。但是我找不到任何支持这可能是问题的证据。我已经尝试确保它保留数据,但我觉得我走的路不对。
代码大致是这样的:
HttpClientHandler httpHandler = new HttpClientHandler { UseDefaultCredentials = true };
var client = new HttpClient(httpHandler, false);
client.BaseAddress = new Uri(BaseUrl + "api/job/PostTest");
var content = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(System.Globalization.CultureInfo.InvariantCulture));
content.Add(new StringContent(mailItem.HTMLBody, Encoding.UTF8), "BodyHtml");
// content.Add()'s... Omitted for brevity
var response = client.PostAsync(BaseUrl + "api/job/PostTest", content);
response.ContinueWith(prevTask => {
if (prevTask.Result.IsSuccessStatusCode)
{
System.Diagnostics.Debug.WriteLine("Was success");
}
else
{
System.Diagnostics.Debug.WriteLine("Was Error");
}
}, System.Threading.Tasks.TaskContinuationOptions.OnlyOnRanToCompletion);
response.ContinueWith(prevTask =>{
MessageBox.Show(prevTask.Exception.ToString());
}, System.Threading.Tasks.TaskContinuationOptions.OnlyOnFaulted);
完整的异常详细信息是:
System.AggregateException: One or more errors occurred. ---> System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.IO.IOException: The read operation failed, see inner exception. ---> System.Net.WebException: The request was aborted: The request was canceled.
at System.Net.ConnectStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.BeginRead(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state)
--- End of inner exception stack trace ---
at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.BeginRead(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state)
at System.Net.Http.StreamToStreamCopy.StartRead()
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
---> (Inner Exception #0) System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.IO.IOException: The read operation failed, see inner exception. ---> System.Net.WebException: The request was aborted: The request was canceled.
at System.Net.ConnectStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.BeginRead(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state)
--- End of inner exception stack trace ---
at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.BeginRead(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state)
at System.Net.Http.StreamToStreamCopy.StartRead()
--- End of inner exception stack trace ---<---
如果有人能指出一些对我有帮助的资源或指出我哪里出错了,那将大有帮助!
经过大量搜索和混乱后,我无法使用 HttpClient
解决此问题,所以我所做的是使用 WebClient
。以防将来其他人遇到此问题,我将发布我最终使用的内容:
System.Net.WebClient wc = new System.Net.WebClient();
wc.Headers.Add("Content-Type", String.Format("multipart/form-data; boundary=\"{0}\"", multipartFormBoundary));
wc.UseDefaultCredentials = true;
try
{
var wcResponse = wc.UploadData(BaseUrl + "api/job/PostJobEmailNote", byteArray);
}
catch(Exception e)
{
// response status code was not in 200's
}
我认为问题可能在于使用 returns 无效的匿名函数。他们有点问题。将我的 lambda 更改为 returns bools 为我解决了这个问题。
在开发我们的 IronBox Outlook 插件时,我们 运行 解决了这个问题。我们发现,在 VSTO 上下文中,ServicePointManager 支持的安全协议只有 Tls 和 Ssl3(这不适用于我们仅支持 TLS 1.2 或更高版本的 API)。
您可以像这样从您的 VSTO 代码中轻松检查这一点(这是我们连接到 Application.ItemSend 事件时的示例):
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
// Handle event when item is sent
this.Application.ItemSend += Application_ItemSend;
}
private void Application_ItemSend(object Item, ref bool Cancel)
{
foreach (var c in (SecurityProtocolType[])Enum.GetValues(typeof(SecurityProtocolType)))
{
if (ServicePointManager.SecurityProtocol.HasFlag(c))
{
Debug.WriteLine(c.ToString());
}
}
Cancel = false;
}
我们通过设置 ServicePointManager.SecurityProtocol 属性 来支持 Tls12 来解决这个问题:
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
希望有一天这对某人有所帮助,
凯文
不幸的是,我在插件中开发此功能的整个过程中一直使用 Fiddler 运行ning,自从部署到客户端后,我发现它对任何人都不起作用 - 除非他们 运行 fiddler还有!如果我停止 运行ning Fiddler,它也无法在我的开发机器上运行。
主要错误是Error while copying content to a stream.
。所以我调查了我正在 POST
ing 的数据在到达服务器之前被 GC 释放的可能性(对我来说,这解释了为什么 运行ning Fiddler 解决了它——我相信请求首先发送到 Fiddler,然后 Fiddler 将其发送到服务器)。但是我找不到任何支持这可能是问题的证据。我已经尝试确保它保留数据,但我觉得我走的路不对。
代码大致是这样的:
HttpClientHandler httpHandler = new HttpClientHandler { UseDefaultCredentials = true };
var client = new HttpClient(httpHandler, false);
client.BaseAddress = new Uri(BaseUrl + "api/job/PostTest");
var content = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(System.Globalization.CultureInfo.InvariantCulture));
content.Add(new StringContent(mailItem.HTMLBody, Encoding.UTF8), "BodyHtml");
// content.Add()'s... Omitted for brevity
var response = client.PostAsync(BaseUrl + "api/job/PostTest", content);
response.ContinueWith(prevTask => {
if (prevTask.Result.IsSuccessStatusCode)
{
System.Diagnostics.Debug.WriteLine("Was success");
}
else
{
System.Diagnostics.Debug.WriteLine("Was Error");
}
}, System.Threading.Tasks.TaskContinuationOptions.OnlyOnRanToCompletion);
response.ContinueWith(prevTask =>{
MessageBox.Show(prevTask.Exception.ToString());
}, System.Threading.Tasks.TaskContinuationOptions.OnlyOnFaulted);
完整的异常详细信息是:
System.AggregateException: One or more errors occurred. ---> System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.IO.IOException: The read operation failed, see inner exception. ---> System.Net.WebException: The request was aborted: The request was canceled.
at System.Net.ConnectStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.BeginRead(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state)
--- End of inner exception stack trace ---
at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.BeginRead(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state)
at System.Net.Http.StreamToStreamCopy.StartRead()
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
---> (Inner Exception #0) System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.IO.IOException: The read operation failed, see inner exception. ---> System.Net.WebException: The request was aborted: The request was canceled.
at System.Net.ConnectStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.BeginRead(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state)
--- End of inner exception stack trace ---
at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.BeginRead(Byte[] buffer, Int32 offset, Int32 count, AsyncCallback callback, Object state)
at System.Net.Http.StreamToStreamCopy.StartRead()
--- End of inner exception stack trace ---<---
如果有人能指出一些对我有帮助的资源或指出我哪里出错了,那将大有帮助!
经过大量搜索和混乱后,我无法使用 HttpClient
解决此问题,所以我所做的是使用 WebClient
。以防将来其他人遇到此问题,我将发布我最终使用的内容:
System.Net.WebClient wc = new System.Net.WebClient();
wc.Headers.Add("Content-Type", String.Format("multipart/form-data; boundary=\"{0}\"", multipartFormBoundary));
wc.UseDefaultCredentials = true;
try
{
var wcResponse = wc.UploadData(BaseUrl + "api/job/PostJobEmailNote", byteArray);
}
catch(Exception e)
{
// response status code was not in 200's
}
我认为问题可能在于使用 returns 无效的匿名函数。他们有点问题。将我的 lambda 更改为 returns bools 为我解决了这个问题。
在开发我们的 IronBox Outlook 插件时,我们 运行 解决了这个问题。我们发现,在 VSTO 上下文中,ServicePointManager 支持的安全协议只有 Tls 和 Ssl3(这不适用于我们仅支持 TLS 1.2 或更高版本的 API)。
您可以像这样从您的 VSTO 代码中轻松检查这一点(这是我们连接到 Application.ItemSend 事件时的示例):
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
// Handle event when item is sent
this.Application.ItemSend += Application_ItemSend;
}
private void Application_ItemSend(object Item, ref bool Cancel)
{
foreach (var c in (SecurityProtocolType[])Enum.GetValues(typeof(SecurityProtocolType)))
{
if (ServicePointManager.SecurityProtocol.HasFlag(c))
{
Debug.WriteLine(c.ToString());
}
}
Cancel = false;
}
我们通过设置 ServicePointManager.SecurityProtocol 属性 来支持 Tls12 来解决这个问题:
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
希望有一天这对某人有所帮助,
凯文