我正在尝试将 XML 文件的内容从手持设备(Compact Framework/Windows CE)发送到我的服务器应用程序中的 Web API 方法,如下所示(客户端代码):
public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(xmlFilepath))
{
String line;
while ((line = sr.ReadLine()) != null)
{
// test to see if it's finding any lines
//MessageBox.Show(line); <= works fine
sb.AppendLine(line);
}
byte[] postBytes = Encoding.UTF8.GetBytes(sb.ToString());
if (timeout < 0)
{
request.ReadWriteTimeout = timeout;
request.Timeout = timeout;
}
request.ContentLength = postBytes.Length;
request.KeepAlive = false;
request.ContentType = "application/xml";
try
{
Stream requestStream = request.GetRequestStream();
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
using (var response = (HttpWebResponse)request.GetResponse())
{
return response.ToString();
}
}
catch (Exception ex)
{
MessageBox.Show("SendXMLFile exception " + ex.Message);
request.Abort();
return string.Empty;
}
}
}
正如您在注释掉的代码中看到的(“<= 工作正常”),我已经对其进行了测试,并且我想要的数据正在添加到 StringBuilder。没有抛出异常(我没有看到“SendXMLFile 异常”)。
但是,当调用相应的服务器代码时:
[Route("api/DeliveryItems/PostArgsAndXMLFileAsStr")]
public async void PostArgsAndXMLFileAsStr([FromBody] string stringifiedXML, string serialNum, string siteNum)
{
string beginningInvoiceNum = string.Empty;
string endingInvoiceNum = string.Empty;
XDocument doc = XDocument.Parse(stringifiedXML);
...“serialNum”和“siteNum”参数符合预期(包含有效的预期值),但正文(stringifiedXML)为空。为什么?
更新
我也在客户端中添加了这个:
request.ContentLength = postBytes.Length;
// Did the sb get into the byte array?
MessageBox.Show(request.ContentLength.ToString());
...并且字节数组确实有数据,因为它向我显示“112”(XML 文件非常小)。
更新 2
现在我添加了另一个调试消息:
try
{
Stream requestStream = request.GetRequestStream();
// now test this:
MessageBox.Show(string.Format("requestStream length is {0}", requestStream.Length.ToString()));
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
using (var response = (HttpWebResponse)request.GetResponse())
{
return response.ToString();
}
}
catch (Exception ex)
{
MessageBox.Show("SendXMLFile exception " + ex.Message);
request.Abort();
return string.Empty;
}
...而且我什至没有看到“requestStream length is”消息;相反,我看到了“SendXMLFileException NotSupportedException”......???
更新 3
我想这是山楂效应或类似的一个例子。一旦我注释掉了那个调试 (MessageBox.Show()) 语句,我就会回到服务器应用程序中,但是 [FromBody] val 为空。
然后客户端收到消息“无法从传输连接中读取数据”
更新 4
stringifiedXML 在这里仍然为空:
public async void PostArgsAndXMLFileAsStr([FromBody] string stringifiedXML, string serialNum, string siteNum)
{
string beginningInvoiceNum = string.Empty;
string endingInvoiceNum = string.Empty;
XDocument doc = XDocument.Parse(stringifiedXML);
...即使在我修改了客户端中的代码之后,对这个问题的回应如下:
public static string SendXMLFile(string xmlFilepath, string uri)
{
MessageBox.Show(string.Format("In SendXMLFile() - xmlFilepath == {0}, uri == {1}", xmlFilepath, uri));
string strData = GetDataFromXMLFile();
HttpWebRequest request = CreateRequest(uri, HttpMethods.POST, strData, "application/xml");
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
try
{
using (var response = (HttpWebResponse)request.GetResponse())
{
return response.GetResponseStream().ToString();
}
}
catch (Exception ex)
{
MessageBox.Show("SendXMLFile exception " + ex.Message);
request.Abort();
return string.Empty;
}
}
private static string GetDataFromXMLFile()
{
// test data - if it works, get the (same, for now) data from the file
return @"<?xml version=1.0?><LocateAndLaunch><Tasks></Tasks><Locations></Locations></LocateAndLaunch>"; //had to remove "s from version num
}
// Based on code from Andy Wiggly (the owner of Wiggly Field in Chicago and the Wiggly chewing gum company?)
public static HttpWebRequest CreateRequest(string uri, HttpMethods method, string data, string contentType)
{
WebRequest request = HttpWebRequest.Create(uri);
request.Method = Enum.ToObject(typeof(HttpMethods), method).ToString();
request.ContentType = contentType;
((HttpWebRequest)request).Accept = contentType;
if (method != HttpMethods.GET && method != HttpMethods.DELETE)
{
Encoding encoding = Encoding.UTF8;
request.ContentLength = encoding.GetByteCount(data);
request.ContentType = contentType;
request.GetRequestStream().Write(
encoding.GetBytes(data), 0, (int)request.ContentLength);
request.GetRequestStream().Close();
}
else
{
// If we're doing a GET or DELETE don't bother with this
request.ContentLength = 0;
}
// Finally, return the newly created request to the caller.
return request as HttpWebRequest;
}
注意:我不知道这是否只是关闭服务器的误导性副作用,但我随后在客户端/手持应用程序中看到了这个错误消息:
""System.Net.ProtocolVi..." "提交请求后无法执行此操作。"
更新 5
对于那些想要堆栈跟踪的人,&c:
serNum 和 siteNum 是连接到 uri 中的简单值,如下所示:
string uri = string.Format("http://192.168.125.50:28642/api/FileTransfer/GetHHSetupUpdate?serialNum={0}&clientVersion={1}", serNum, clientVer);
我试图像这样获得堆栈跟踪:
catch (Exception ex)
{
MessageBox.Show(string.Format("Msg = {0}; StackTrace = {1)", ex.Message, ex.StackTrace));
request.Abort();
return string.Empty;
}
...但现在我只看到“提交请求后无法执行此操作。”
更新 6
我将方法签名更改为:
public static HttpWebResponse SendXMLFile(string xmlFilepath, string uri)
...以及相应的代码:
try
{
using (var response = (HttpWebResponse)request.GetResponse())
{
return response;
}
}
catch (Exception ex)
{
MessageBox.Show(string.Format("Msg = {0}; StackTrace = {1)", ex.Message, ex.StackTrace));
request.Abort();
return null;
}
...但它没有任何区别(而且我没有看到“StackTrave =”消息,所以它一定是失败的 erstwheres)
更新 7
我在里面放了两个调试字符串:
0)
public static HttpWebRequest CreateRequestNoCredentials(string uri, HttpMethods method, string data, string contentType)
{
//test:
MessageBox.Show(string.Format("In CreateRequestNoCredentials(); data passed in = {0}", data));
1) 在 SendXMLFile() 中:
//test:
MessageBox.Show(string.Format("After calling CreateRequestNoCredentials(), request contentLen = {0}, headers = {1}, requestUri = {2}",
request.ContentLength, request.Headers, request.RequestUri));
...我看到了这个:
...但是在第二个有机会向我展示血淋淋的细节之前,服务器收到 null 正文值,因此崩溃,然后客户端发出相同的旧“此操作无法在之后执行”请求已提交”投诉。
更新 8
针对建议,“我怀疑如果您在 CreateRequest 调用之后删除 KeepAlive 和 ProtocolVersion 的设置,异常就会消失。 ”,我从这里更改了我的代码:
HttpWebRequest request = CreateRequestNoCredentials(uri, HttpMethods.POST, strData, "application/xml");
//test:
MessageBox.Show(string.Format("After calling CreateRequestNoCredentials(), request contentLen = {0}, headers = {1}, requestUri = {2}",
request.ContentLength, request.Headers, request.RequestUri));
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
public static HttpWebRequest CreateRequestNoCredentials(string uri, HttpMethods method, string data, string contentType)
{
//test:
MessageBox.Show(string.Format("In CreateRequestNoCredentials(); data passed in = {0}", data));
WebRequest request = HttpWebRequest.Create(uri);
request.Method = Enum.ToObject(typeof(HttpMethods), method).ToString();
request.ContentType = contentType;
((HttpWebRequest)request).Accept = contentType;
if (method != HttpMethods.GET && method != HttpMethods.DELETE)
{
Encoding encoding = Encoding.UTF8;
request.ContentLength = encoding.GetByteCount(data);
request.ContentType = contentType;
request.GetRequestStream().Write(
encoding.GetBytes(data), 0, (int)request.ContentLength);
request.GetRequestStream().Close();
}
else
{
// If we're doing a GET or DELETE don't bother with this
request.ContentLength = 0;
}
// Finally, return the newly created request to the caller.
return request as HttpWebRequest;
}
...对此:
HttpWebRequest request = CreateRequestNoCredentials(uri, HttpMethods.POST, strData, "application/xml");
//test:
MessageBox.Show(string.Format("After calling CreateRequestNoCredentials(), request contentLen = {0}, headers = {1}, requestUri = {2}",
request.ContentLength, request.Headers, request.RequestUri));
public static HttpWebRequest CreateRequestNoCredentials(string uri, HttpMethods method, string data, string contentType)
{
//test:
MessageBox.Show(string.Format("In CreateRequestNoCredentials(); data passed in = {0}", data));
WebRequest request = HttpWebRequest.Create(uri);
request.Method = Enum.ToObject(typeof(HttpMethods), method).ToString();
request.ContentType = contentType;
((HttpWebRequest)request).Accept = contentType;
// moved from elsewhere to here:
((HttpWebRequest)request).KeepAlive = false;
((HttpWebRequest)request).ProtocolVersion = HttpVersion.Version10;
if (method != HttpMethods.GET && method != HttpMethods.DELETE)
{
Encoding encoding = Encoding.UTF8;
request.ContentLength = encoding.GetByteCount(data);
request.ContentType = contentType;
request.GetRequestStream().Write(
encoding.GetBytes(data), 0, (int)request.ContentLength);
request.GetRequestStream().Close();
}
else
{
// If we're doing a GET or DELETE don't bother with this
request.ContentLength = 0;
}
// Finally, return the newly created request to the caller.
return request as HttpWebRequest;
}
...但我仍然得到相同的错误消息(“提交请求后无法执行此操作”),并且 stringifiedXML 在到达服务器时仍然为空。
更新 9
这是我通过 Fiddler 2 发送我理解的内容时得到的结果(如果您没有视觉超能力,请右键单击图像并在新选项卡中打开):
...但我不知道我在看什么...它有用吗?它失败了吗?“body == 0”列让我暂停/让我认为它失败了,但“204”似乎意味着“服务器成功处理了请求,但没有返回任何内容”......
更新 10
这是修复 uri 后的 Fiddler 尖叫声,我确实到达了服务器应用程序中的断点,并发送了良好的数据:
更新 11
通过更改此代码:
string strData = sb.ToString();
HttpWebRequest request = CreateRequestNoCredentials(uri, HttpMethods.POST, strData, "application/xml");
...对此:
string strData = @sb.ToString(); // GetDataFromXMLFile();
string body = String.Format("\"{0}\"", strData);
HttpWebRequest request = CreateRequestNoCredentials(uri, HttpMethods.POST, body, "application/json");
...我现在在 stringifiedXML 中得到这个:“
...所以我现在得到:“ System.Xml.XmlException 未由用户代码 HResult=-2146232000 处理消息 = 文件意外结束。第 1 行,第 15 位... ”
反正就是进步了。。。
更新 12
根据 Fiddle 中作为“请求正文”传递的字符串的确切组成/格式,结果完全不同。
以此作为请求正文:
<?xml version="1.0"?><LocateAndLaunch><Tasks></Tasks><Locations></Locations></LocateAndLaunch>
...stringifiedXML 为空
以此作为请求正文:
"<?xml version=1.0?><LocateAndLaunch><Tasks></Tasks><Locations></Locations></LocateAndLaunch>"
...stringifiedXML 完全相同 ("")
...但有一个例外:
System.Xml.XmlException 未被用户代码处理 HResult=-2146232000 Message='1.0' 是一个意外的标记。预期的标记是 '"' 或 '''。第 1 行,位置 15。Source=System.Xml LineNumber=1 LinePosition=15 SourceUri="" StackTrace: at System.Xml.XmlTextReaderImpl.Throw(Exception e) at System。 Xml.XmlTextReaderImpl.Throw(String res, String[] args) 在 System.Xml.XmlTextReaderImpl.ThrowUnexpectedToken(String expectedToken1, String expectedToken2) 在 System.Xml.XmlTextReaderImpl.ParseXmlDeclaration(Boolean isTextDecl) 在 System.Xml.XmlTextReaderImpl.Read( )在 System.Xml.Linq.XDocument.Parse(字符串文本,LoadOptions 选项)在 System.Xml.Linq.XDocument 的 System.Xml.Linq.XDocument.Load(XmlReader 阅读器,LoadOptions 选项)。
以此作为请求正文:
"<?xml version="1.0"?><LocateAndLaunch><Tasks></Tasks><Locations></Locations></LocateAndLaunch>"
...stringifiedXML 是“
倒数第二个,以此作为请求正文:
"<?xml version=\"1.0\"?><LocateAndLaunch><Tasks></Tasks><Locations></Locations></LocateAndLaunch>"
...stringifiedXML 是完全一样的东西 ("")
...但我得到了这个例外:
System.InvalidOperationException 未被用户代码处理 HResult=-2146233079 Message=Sequence 不包含任何元素 Source=System.Core StackTrace: at System.Linq.Enumerable.First[TSource](IEnumerable`1 source) at HandheldServer.Controllers.DeliveryItemsController.d__2 c:\HandheldServer\HandheldServer\Controllers\DeliveryItemsController.cs 中的 .MoveNext():第 109 行 InnerException:
最后,如果我通过这个,在角度内使用(尽管是虚假的)vals:
"<?xml version=\"1.0\"?><LocateAndLaunch><Tasks>Some Task</Tasks><Locations>Some Location</Locations></LocateAndLaunch>"
...我仍然得到“序列不包含任何元素”
这种方法比Rachel Canning还要挑剔!它想要什么——啤酒里有鸡蛋?!?
更新 13
使用此代码:
public async void PostArgsAndXMLFileAsStr([FromBody] string stringifiedXML, string serialNum, string siteNum)
{
XDocument doc = XDocument.Parse(await Request.Content.ReadAsStringAsync());
...或这个:
. . .XDocument doc = XDocument.Load(await Request.Content.ReadAsStreamAsync());
...这作为传入的 stringifiedXML:
“一些任务一些位置”
...我收到异常: “System.Xml.XmlException 未被用户代码 HResult=-2146232000 处理=缺少根元素。”
使用此代码(相同的 stringifiedXML):
XDocument doc = XDocument.Parse(stringifiedXML);
...我得到,“ System.InvalidOperationException 未由用户代码 HResult=-2146233079 处理消息=序列不包含元素 Source=System.Core StackTrace: at System.Linq.Enumerable.First[TSource](IEnumerable`1 source) at HandheldServer.Controllers.DeliveryItemsController.d__2.MoveNext() 在 c:\HandheldServer\HandheldServer \Controllers\DeliveryItemsController.cs:line 109 InnerException:"
IOW,根据我解析传入字符串的方式,我得到“缺少根元素”或“序列不包含元素”
什么Deuce McAlistair MacLean Virginia Weeper?!?“ <LocateAndLaunch
>”不是根元素吗?不是“某些任务”和“某些位置”元素吗?