C# 试图通过C编写文件下载的Web服务器端实现,其中消息体是文件内容
我的问题/挑战非常类似于几个不同的堆栈溢出帖子,但我已经详细阅读了它们,并且仍然在努力让最基本的应用程序正常工作。具体地说,我相信并且都非常接近我想要实现的目标 为了给您提供上下文,我正在尝试编写/存根一个简单的固件OTA(无线)服务器。我最初的目标似乎很简单,但我花了很多时间,几乎没有任何进展。我想提供一个可以从浏览器(以及最终在IoT设备上运行的一些固件)点击的URL,该URL将接收一些参数(通过URL参数或通过标题)。如果固件更新可用,则调用应返回一个文件作为响应主体;如果当前没有可用的更新,则调用应返回一个合适的HTTP响应代码(或仅返回一个空消息主体) 我在VisualStudio的网站应用程序方面不是很有经验,但在C#方面却很舒服,而且它似乎是一个很好的环境,可以让它快速运行。我对其他实现持开放态度,但我认为编写控制器是最简单的方法。我了解到,这个Web API似乎主要用于.Net到.Net的通信,所以如果有更好的平台,我很高兴被指向更好的方向。以下是我总结的内容(充分利用了上面的链接,因此没有我的功劳!): } 当我输入URLC# 试图通过C编写文件下载的Web服务器端实现,其中消息体是文件内容,c#,asp.net,asp.net-web-api,asp.net-web-api2,C#,Asp.net,Asp.net Web Api,Asp.net Web Api2,我的问题/挑战非常类似于几个不同的堆栈溢出帖子,但我已经详细阅读了它们,并且仍然在努力让最基本的应用程序正常工作。具体地说,我相信并且都非常接近我想要实现的目标 为了给您提供上下文,我正在尝试编写/存根一个简单的固件OTA(无线)服务器。我最初的目标似乎很简单,但我花了很多时间,几乎没有任何进展。我想提供一个可以从浏览器(以及最终在IoT设备上运行的一些固件)点击的URL,该URL将接收一些参数(通过URL参数或通过标题)。如果固件更新可用,则调用应返回一个文件作为响应主体;如果当前没有可用的更
http://localhost:2265/api/ota
,我在屏幕上看到以下原始输出:
{"version":{"major":1,"minor":1,"build":-1,"revision":-1,"majorRevision":-1,"minorRevision":-1},"content":{"headers":[{"key":"Content-Disposition","value":["attachment; filename=hello-world.bin"]},{"key":"Content-Type","value":["application/octet-stream"]},{"key":"Content-Length","value":["407904"]}]},"statusCode":200,"reasonPhrase":"OK","headers":[],"requestMessage":null,"isSuccessStatusCode":true}
在Fiddler2中捕获的整个响应如下所示:
HTTP/1.1200正常
传输编码:分块
内容类型:application/json;字符集=utf-8
服务器:红隼
X-SourceFiles:=?UTF-8?B?YzpcdXNlcnNcZG91Z2NcZG9jdW1lbnRzXHZpc3VhbCBzdHVkaW8gMjAxNVxQcm9qZWN0c1xPdmVyVGhl QWLYQXBXHNYY1XPDMVYVGHLQWLYQXBPXGFWAVxVDGE=?=
X-Powered-By:ASP.NET
日期:2017年2月28日星期二16:43:01 GMT
192
{version:
{“major”:1,“minor”:1,“build”:-1,“revision”:-1,“minorRevision”:-1},“content”:{“headers”:[{“key”:“content Disposition”,“value”:[“attachment;filename=hello world.bin”]},{“content Type”,“value”:[“application/octet stream”]},{“key”:“content Length”,“value”:[“407904”}],“statusCode”:200,“reasonPhrase”:“OK”,“headers”:[],“requestMessage”:null,“isSuccessStatusCode”:true}
0
(如果格式有点难看,很抱歉,我想我还需要一些使用MD进行HTTP响应的教程!)
再一次,我的目标是编写C#代码,返回一个HTTP响应,其中头表示文件是附件,消息体只是文件本身
再次感谢您可能提供的任何帮助/见解
谢谢-道格。这是我向浏览器发送文件的标准方法。该方法包含两个参数,一个是文件内容,另一个是客户端将接收的默认文件名。请欣赏
/// <summary>
/// Sends the fileData to the browser and prompts the visitor to save it with the
/// name specified in fileName.
/// </summary>
/// <param name="defaultFilename">File name to use when browser prompts visitor (spaces will be replaced with dashes)</param>
/// <param name="data">Data to be sent to visitor's browser</param>
/// <param name="errorMsg"></param>
// Mod 08/04/09 Ron C - Reworked code to work right in modern browsers.
public static bool DownloadToBrowser(string data, string defaultFilename, out string errorMsg){
errorMsg = "";
System.Web.HttpResponse response = HttpContext.Current.Response;
try {
defaultFilename = defaultFilename.Replace(' ', '-'); //firefox will cut the name off at the space if there is one, so get rid of 'em
response.Clear();
response.ContentType = "application/octet-stream";
response.AddHeader("Content-Disposition", "attachment; filename=" + defaultFilename);
//8/5/09 Adding a "Content-Length" header was cutting off part of my file. Apparently
// it would need to factor in the length of the headers as well as the conent.
// since I have no easy way to figure out the length of the headers, initially I was gonna
// eliminate "Content-Length" header. Doing so works great in IE 7 and FireFox 3, but not
// in Safari 3 or 4(which doesn't download the file without the "Content-Length" header. So I
// resorted to a cludge of using the header tag and setting it to content length + 1000 for headers.
// I'd love to have a better solution, but his one works and I've already wasted 6+ hours to get to this
// solution. Cross broswer downloading of a file shouldn't have to be so hard. -Ron
int len = data.Length + 1000;
response.AddHeader("Content-Length", len.ToString()); //file size for progress dialog
response.Write(data);
response.Flush();
response.Close(); //Close() needed to prevent html from page being streamed back after the file data we sent.
//Don't use response.End() cause it throws a thread abort exception that can't be caught! Actually you can
//catch it but then it rethrows after the catch block! (What bozo thought that up?). I found lots of threads on this.
} catch (Exception ex) {
errorMsg = "Unable to download file to browser.";
//Add code here to log the error in your environment
return false;
}
return true;
}
//
///将文件数据发送到浏览器,并提示访问者使用
///文件名中指定的名称。
///
///浏览器提示访问者时使用的文件名(空格将替换为破折号)
///要发送到访问者浏览器的数据
///
//Mod 08/04/09 Ron C-重新编写的代码在现代浏览器中正常工作。
public static bool DownloadToBrowser(字符串数据、字符串defaultFilename、输出字符串errorMsg){
errorMsg=“”;
System.Web.HttpResponse response=HttpContext.Current.response;
试一试{
defaultFilename=defaultFilename.Replace(“”,“-”);//如果有名字,firefox会在空格处删掉它,所以把它们去掉
response.Clear();
response.ContentType=“应用程序/八位字节流”;
response.AddHeader(“内容处置”、“附件;文件名=“+defaultFilename”);
//2009年8月5日添加“内容长度”标题会切断我的部分文件
//它需要考虑头的长度和内容。
//因为我没有简单的方法来计算头球的长度,最初我想
//消除“内容长度”标题。这样做在IE 7和FireFox 3中效果很好,但不是很好
//在Safari3或4中(如果没有“Content Length”头文件,则不会下载文件)
//求助于使用header标记并将其设置为content-length+1000作为标题。
//我很想有一个更好的解决方案,但他的解决方案很有效,我已经浪费了6个多小时来解决这个问题
//解决方案。跨兄弟下载文件不应该这么难。-罗恩
int len=数据长度+1000;
response.AddHeader(“Content Length”,len.ToString());//进度对话框的文件大小
响应。写入(数据);
response.Flush();
response.Close();//需要Close()来防止html页面在我们发送的文件数据之后被流回。
//不要使用response.End(),因为它会抛出一个无法捕获的线程中止异常!实际上您可以
//接住它,但它在接住挡块后会重新旋转!(博佐怎么想的?)。我在这上面发现了很多线。
}捕获(例外情况除外){
errorMsg=“无法将文件下载到浏览器。”;
//在此处添加代码以在您的环境中记录错误
返回false;
}
返回true;
}
Ron先生-感谢您的回复。我感谢您的帮助!您是否建议我将其与我执行的Web Api调用结合使用
/// <summary>
/// Sends the fileData to the browser and prompts the visitor to save it with the
/// name specified in fileName.
/// </summary>
/// <param name="defaultFilename">File name to use when browser prompts visitor (spaces will be replaced with dashes)</param>
/// <param name="data">Data to be sent to visitor's browser</param>
/// <param name="errorMsg"></param>
// Mod 08/04/09 Ron C - Reworked code to work right in modern browsers.
public static bool DownloadToBrowser(string data, string defaultFilename, out string errorMsg){
errorMsg = "";
System.Web.HttpResponse response = HttpContext.Current.Response;
try {
defaultFilename = defaultFilename.Replace(' ', '-'); //firefox will cut the name off at the space if there is one, so get rid of 'em
response.Clear();
response.ContentType = "application/octet-stream";
response.AddHeader("Content-Disposition", "attachment; filename=" + defaultFilename);
//8/5/09 Adding a "Content-Length" header was cutting off part of my file. Apparently
// it would need to factor in the length of the headers as well as the conent.
// since I have no easy way to figure out the length of the headers, initially I was gonna
// eliminate "Content-Length" header. Doing so works great in IE 7 and FireFox 3, but not
// in Safari 3 or 4(which doesn't download the file without the "Content-Length" header. So I
// resorted to a cludge of using the header tag and setting it to content length + 1000 for headers.
// I'd love to have a better solution, but his one works and I've already wasted 6+ hours to get to this
// solution. Cross broswer downloading of a file shouldn't have to be so hard. -Ron
int len = data.Length + 1000;
response.AddHeader("Content-Length", len.ToString()); //file size for progress dialog
response.Write(data);
response.Flush();
response.Close(); //Close() needed to prevent html from page being streamed back after the file data we sent.
//Don't use response.End() cause it throws a thread abort exception that can't be caught! Actually you can
//catch it but then it rethrows after the catch block! (What bozo thought that up?). I found lots of threads on this.
} catch (Exception ex) {
errorMsg = "Unable to download file to browser.";
//Add code here to log the error in your environment
return false;
}
return true;
}