C# 通过POST httprequest将文件传输到hololens(错误429)
我使用桌面应用程序通过httprequest与hololens眼镜进行通信(hololens通过USB连接),尤其是我想读写文件。为此,我使用以下代码:C# 通过POST httprequest将文件传输到hololens(错误429),c#,.net,httprequest,hololens,C#,.net,Httprequest,Hololens,我使用桌面应用程序通过httprequest与hololens眼镜进行通信(hololens通过USB连接),尤其是我想读写文件。为此,我使用以下代码: class BuildDeployPortal { // Consts public static readonly string API_FileQuery = @"http://{0}/api/filesystem/apps/file"; // Classes & Structs public st
class BuildDeployPortal
{
// Consts
public static readonly string API_FileQuery = @"http://{0}/api/filesystem/apps/file";
// Classes & Structs
public struct ConnectInfo
{
public ConnectInfo(string ip, string user, string password)
{
IP = ip;
User = user;
Password = password;
}
public string IP;
public string User;
public string Password;
}
public async static void GetFile(ConnectInfo connectInfo, string knownfolderid, string filename, string packagefullname, string path)
{
try
{
// Query
string query = string.Format(API_FileQuery, connectInfo.IP);
query += "?knownfolderid=" + Uri.EscapeUriString(knownfolderid);
query += "&filename=" + Uri.EscapeUriString(filename);
query += "&packagefullname=" + Uri.EscapeUriString(packagefullname);
query += "&path=" + Uri.EscapeUriString(path);
// Create http request
var httpRequest = new HttpClient();
httpRequest.DefaultRequestHeaders.Clear();
httpRequest.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic",
EncodeTo64(connectInfo.User + ":" + connectInfo.Password));
HttpResponseMessage resp = await httpRequest.GetAsync(query);
byte[] responseMessage = await resp.Content.ReadAsByteArrayAsync();
}
catch (Exception ex)
{
//log some problems
}
}
public async static void UploadFile(ConnectInfo connectInfo, string knownfolderid, string packagefullname, string path, string filePath)
{
try
{
// Query
string query = string.Format(API_FileQuery, connectInfo.IP);
query += "?knownfolderid=" + Uri.EscapeUriString(knownfolderid);
query += "&packagefullname=" + Uri.EscapeUriString(packagefullname);
query += "&path=" + Uri.EscapeUriString(path);
// Create http request
var httpRequest = new HttpClient();
httpRequest.DefaultRequestHeaders.Clear();
httpRequest.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic",
EncodeTo64(connectInfo.User + ":" + connectInfo.Password));
byte[] data = File.ReadAllBytes(filePath);
ByteArrayContent byteContent = new ByteArrayContent(data);
HttpResponseMessage resp = await httpRequest.PostAsync(query, byteContent);
var responseMessage = await resp.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
//log some problems
}
}
// Helpers
private static string EncodeTo64(string toEncode)
{
byte[] toEncodeAsBytes = Encoding.ASCII.GetBytes(toEncode);
string returnValue = Convert.ToBase64String(toEncodeAsBytes);
return returnValue;
}
}
要运行它,我打电话给
BuildDeployPortal.ConnectInfo co = new BuildDeployPortal.ConnectInfo("127.0.0.1:10080", "user", "pass");
//get file
BuildDeployPortal.GetFile(co, "LocalAppData", "2017-01-25-09-04-21_TestFile.csv", "app_full_package_name", "\\LocalState");
//upload file
BuildDeployPortal.UploadFile(co, "LocalAppData", "app_full_package_name", "\\LocalState",
"C:\\Users\\myuser\\Desktop\\info.json");
GetFile方法工作正常,并为我提供了所需的文件,但UploadFile方法为我提供了以下响应:StatusCode:429,ReasonPhase:“请求太多”。如果在执行期间只运行其中一个,则结果相同
我真的不明白为什么我会有这个错误,我只是发送了一个请求(或者我遗漏了什么)
有关信息,可以找到RESTAPI定义
谢谢我没有真正回答我的问题(为什么会出现这个错误429),但我给出了一个上传文件的替代解决方案 我下载以获取WindowsDevicePortalWrapper库。 然后我调用以下代码来上传文件:
IDevicePortalConnection connection = new DefaultDevicePortalConnection("http://127.0.0.1:10080", "user", "password");
DevicePortal dp = new DevicePortal(connection);
//write file
await dp.UploadFileAsync("LocalAppData", "C:\\Users\\ng1dd32\\Desktop\\info.json", "\\LocalState", "Lexington_1.0.0.0_x86__ph1m9x8skttmg");
调试问题
问题是Chrome 62发送了一个空的内容类型
标题,而Chrome 61则将内容类型
标题作为多部分/表单数据
正确发送
原因是微软自己的FileExplorer.js代码调用了jQuery.ajax(…)
和contentType:“
,因此浏览器只能解释一个空字符串
摘自FileExplorer.js
$.ajax({url:"/api/filesystem/apps/file?"+$.param(r),cache:!1,contentType:"",processData:!1,data:n,type:"post"}).done(...)
无法指定任何请求头,也无法指定请求正文,因此没有用于确定正确的头和正文集的规范
FWIW,Microsoft自己的始终发送内容类型标题:
string contentType = string.Format("multipart/form-data; boundary={0}", boundaryString);
解决方案
我已经创建了一个bookmarklet,它可以在设备门户的FileExplorer页面上正确上传文件
扩展版
可复制的小型bookmarklet版本(也适用于inspector/debugger控制台)
(我为Hololens开发了一年多,在我的每台电脑分别升级到Chrome 62时发现了这一点。)我得到了同样的东西。我已经在HoloLens论坛上重复了这个代码/问题:-但也没有看到回复。我真的很希望这个问题能得到解决。哎呀,我看这也是你的帖子。我有一个比这个稍早一点的,没有回应。如果你得到答案,请把它贴在这里谢谢。抱歉,丹,我没有答案,只有一个选择…这是正确的-这已经在设备门户的更高版本中修复,但全息镜头尚未进行更新。为了避免这种情况,您可以使用尚未更新的IE,它将发送一个“正确”编码的请求。如果有帮助解决此问题的文档,请告诉我,我会在MSDN上编辑这些文档。@HirschSinghal感谢您的确认和内部信息。最好让REST API文档声明
POST
to/API/filesystem/apps/file
需要多部分/表单数据的ContentType
头,并且需要这样发送有效负载。(也可能需要一个查询参数?)此外,对空ContentType
头响应429个太多请求的API可以替换为更合适的状态代码,例如400个错误请求或412个前置条件失败。@HirschSinghal不幸,Edge将XHR调用解释为与Chrome和Firefox相同,并且不更正空字符串中的内容类型。我在我的解决方案中添加了一个bookmarklet,它可以在Chrome上工作,并且可以跨浏览器工作。编辑:如果设备门户支持JSONP就太好了,那么我可能已经能够使用其他解决方法了。FileExplorer.js中的所有对象实例和方法都是在闭包中创建的,所以我不能对其进行修补。而且,由于CSRF令牌位于cookie/头中,加上设备门户RESTAPI不支持CORS,CORS也被淘汰了。
(function(jQuery) {
var pathLinkData = jQuery(".pathLink:last-child").data(),
path = pathLinkData.path,
packagename = pathLinkData.packagename,
knownfolderid = pathLinkData.knownfolderid,
url = '/api/filesystem/apps/file?knownfolderid=' + knownfolderid + '&packagefullname=' + packagename + '&path=%5C%5C' + path,
file_data = jQuery('#fileToUpload')[0].files[0],
form_data = new FormData();
form_data.append('file', file_data, file_data.name);
jQuery.ajax({
url: url,
dataType: 'text',
cache: false,
contentType: false,
processData: false,
data: form_data,
type: 'POST',
error: function(xhr, textStatus, error) { console.error(error) },
success: function(res){
alert('uploaded');
console.log(res);
}
});
})(jQuery);
javascript:(function(jQuery){var pathLinkData=jQuery('.pathLink:last-child').data(),path=pathLinkData.path,packagename=pathLinkData.packagename,knownfolderid=pathLinkData.knownfolderid,url='/api/filesystem/apps/file?knownfolderid='+knownfolderid+'&packagefullname='+packagename+'&path=%5C%5C'+path,file_data=jQuery('#fileToUpload')[0].files[0],form_data=new FormData();form_data.append('file',file_data,file_data.name);jQuery.ajax({url:url,dataType:'text',cache:false,contentType:false,processData:false,data:form_data,type:'POST',error:function(xhr,textStatus,error){console.error(error)},success:function(res){alert("uploaded");console.log(res);}});})(jQuery);