c# - RestSharp“获取响应流时出错(ReadAsync):ReceiveFailure 值不能为空。参数名称:src”
问题描述
大家好,我正在尝试使用 RestSharp 登录我的 xamarin api,如果身份验证有效,API 应该返回状态码 200 OK,如果身份验证失败(密码错误)和其他代码,则返回状态码,具体取决于具体情况,但相反,当身份验证通过(状态代码 200 ok)时,我在所有其他情况下都得到状态代码 0,下面的源代码是我如何实现的
//payload am sending to the api
RequestPayload res = new RequestPayload();
res.appid = appid;
res.data = data;
res.method = "Login";
//convert to json object
var MySerializedObject = JsonConvert.SerializeObject(res);
string APIUrl = ""http://142.168.20.15:8021/RouteTask";
//create client
RestClient client = new RestClient(APIUrl);
//create request
RestRequest request = new RestRequest(Method.POST);
// set request headeer
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
//request.AddJsonBody(MySerializedObject); --i have also tried this
request.AddParameter("application/json", MySerializedObject, ParameterType.RequestBody);
request.JsonSerializer.ContentType = "application/json; charset=utf-8";
request.AddParameter("RequestSource", "Web", "application/json", ParameterType.QueryString);
client.Timeout = 2000000;
var response = client.Execute(request); // where the issue appears
//RestResponse response = client.Execute(request); // i have tried this
//IRestResponse response = client.Execute(request); // i have tried this
if (response.IsSuccessful)
{
//use response data
}
在所有场景中,它返回一个 StatusCode: 0, Content-Type: , Content-Length: 0) 和 errorMessage
“获取响应流(ReadAsync)时出错:ReceiveFailure 值不能为空。参数名称:src”
解决方案
我终于能够找到解决方法。忍受冗长的回应。
标签提到了 Xamarin,这也是我正在使用的 - 特别是 iOS。我认为这实际上可能是 Mono 的一个错误,但我没有采取那么远来确认。
问题在于复制响应缓冲区的默认方式。在 RestSharp 代码中,这是通过 MiscExtensions.cs 中名为 ReadAsBytes 的扩展方法完成的。似乎对于某些响应缓冲区,对 Stream.Read 方法的调用失败。发生这种情况时,异常会导致 RestSharp “快捷方式”处理响应的其余部分,因此状态代码永远不会被填写,因为它发生在调用 ReadAsBytes 之后。
好消息是 RestSharp 确实提供了一种方法来用您自己的方法替换对 ReadAsBytes 的调用。这是通过 IRestRequest 对象上的 ResponseWriter 属性完成的。如果它定义了一个函数,它将绕过 ReadAsBytes 调用并调用你给它的函数。问题是,这被定义为一个动作,你没有得到完整响应对象的副本,所以它有点没用。相反,您必须使用 AdvancedResponseWriter 属性。这包括响应对象和响应流。但是您仍然必须设置 ResponseWriter 属性,否则它不会绕过默认处理程序,您仍然会收到错误消息。
好的,那么你是如何做到这一点的呢?我最终将它实现为 RestClient 的包装器,因此我不必到处实现代码。这是基本设置:
public class MyRestClient : RestClient
{
public MyRestClient(string baseUrl) : base(baseUrl)
{ }
public override IRestResponse Execute(IRestRequest request)
{
request.ResponseWriter = s => { };
request.AdvancedResponseWriter = (input, response) => response.RawBytes = ReadAsBytes(input);
return base.Execute(request);
}
private static byte[] ReadAsBytes(Stream input)
{
var buffer = new byte[16 * 1024];
using (var ms = new MemoryStream())
{
int read;
try
{
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{ ms.Write(buffer, 0, read); }
return ms.ToArray();
}
catch (WebException ex)
{ return Encoding.UTF8.GetBytes(ex.Message); }
};
}
}
ReadAsBytes 方法实际上只是 RestSharp ReadAsBytes 方法的复制/粘贴,并添加了 try/catch。如果失败,它将异常原因返回到响应缓冲区。这可能是也可能不是您想要的,因此请根据需要进行修改。您可能还需要为 Execute 覆盖其他方法,但在我的情况下,这是我们唯一使用的方法,因此就足够了。
到目前为止,这似乎对我有用。也许如果有人有野心,他们可以一直追踪到 Mono 来尝试看看它不喜欢流的什么,但我目前没有时间。
祝你好运!
推荐阅读
- php - 如何通过多行选择以x开头并以y结尾的子字符串并替换它
- php - 使用 Drive Api (PHP) 从特定文件夹获取文件
- google-sheets - Google 表格返回已发布文档的随机版本
- rest - 使用 ALM API 11.52 更新测试实例时出错
- ruby - Ruby 需要导致未定义的局部变量
- javascript - 更改 Javascript 数组中的对象值
- javascript - 单击时避免菜单切换关闭
- excel-formula - 在 Excel 中格式化科学计数法
- ios - 如何在 UITableViewCell 中删除右填充
- google-cloud-platform - 在到达截止确认时间之前,Google Cloud PubSub 消息多次传递