ASP.NET Web API 应用教程(一) ——数据流使用
相信已经有很多文章来介绍asp.net web api 技术,本系列文章主要介绍如何使用数据流,https,以及可扩展的web api 方面的技术,系列文章主要有三篇内容。
主要内容如下:
i 数据流
ii 使用https
iii 可扩展的web api 文档
项目环境要求
- vs 2012(sp4)及以上,
- .net 框架4.5.1
- nuget包,可在packages.config 文件中查寻
本文涉及的知识点
- actionfilter
- authorizationfilter
- delegatehandler
- different web api routing 属性
- mediatypeformatter
- owin
- self hosting
- web api 文档及可扩展功能
.net 框架
- async/await
- .net reflection
- serialization
- asp.net web api/mvc error handling
- iis ,https 及certificate
- 设计准则及技术
前言
自从asp.net mvc 4之后.net 框架开始支持asp.net web api ,asp.net web api 基于http 协议建立的,是构建 restful 服务和处理数据的理想平台,旨在使用http 技术实现对多平台的支持。
asp.net web api 以request-response 的消息转换模式为主,客户端向服务器发送请求,服务器端响应客户端请求。响应可同步或异步。
个人认为使用web api创建应用需要注意的三个关键点:
- 采用服务及方法满足的目标
- 每个方法的输入,如请求
- 每个方法的输出,如响应
通常情况下,asp.net web api 定义method语法与http方法一一对应的,如自定义方法名
getpysicians(),则与http中get 方法匹配。下图是常用匹配表。
但是此方法在很多情况下,并不实用,假如你想在单个api controller 类中定义多个get 或post 方法,在这种情况下,需要定义包含action 的路径,将action 作为uri 的一部分。以下是配置代码:1: public static void register(httpconfiguration config)
2: {
3: // web api configuration and services
4: // web api routes
5: config.maphttpattributeroutes();
6:
7: config.routes.maphttproute(name: physicianapi,
8: routetemplate: {controller}/{action}/{id},
9: defaults: new { id = routeparameter.optional });
10: }
但是此方法不足以应对所有情况,如果想实现从*仓库删除文件,并且想调用同一个方法来获取文件,这种情况下,web api 框架需要伪装get 及delete对应的http 方法属性。如图所示:
removefile 方法可被delete(
httpdelete
) 或 get(httpget
)方法同时调用,从某种程度来说,http 方法使开发人员命名 api“方法”变得简单而标准。web api框架也提供了一些其他功能来处理路径方面的问题,与mvc 的路径处理方法相似。因此可定义不同类型的action方法。
数据流
网络app 最常见的执行操作就是获取数据流。asp.net web api 能够处理客户端与服务器端传输的重量级的数据流,数据流可来源于目录文件,也可是中的二进制文件。本文主要介绍两种方法“download”和“upload”实现数据流相关的功能,download是从服务器下载数据操作,而upload则是上传数据到服务器。
相关项目
webapidatastreaming
webapiclient
-
pocolibrary
在对代码解释之前,首先来了解如何配置iis(7.5)和web api 服务web.config 文件。
1. 保证downloads/uploads 涉及的文件具有读写权限。
2. 保证有足够容量的内容或因*空间处理大文件。
3. 如果文件较大
a. 配置web.config 文件时,保证
maxrequestlength 时响应时间
executiontimeout 合理。具体的值主要依赖于数据大小,允许一次性上传的最大数据为2 gb
b. 保证
maxallowedcontentlength 在
requestfiltering部分配置下正确设置,默认值为30mb,最大值4gb
一旦完成预先配置,那么创建数据流服务就非常简单了,首先 需要定义文件流“
apicontroller
”,如下:1: ///
2: /// file streaming api
3: ///
4: [routeprefix(filestreaming)]
5: [requestmodelvalidator]
6: public class streamfilescontroller : apicontroller
7: {
8: ///
9: /// get file meta data
10: ///
11: ///filename value
12: /// filemeta data response.
13: [route(getfilemetadata)]
14: public httpresponsemessage getfilemetadata(string filename)
15: {
16: // .........................................
17: // full code available in the source control
18: // .........................................
19:
20: }
21:
22: ///
23: /// search file and return its meta data in all download directories
24: ///
25: ///filename value
26: /// list of file meta datas response
27: [httpget]
28: [route(searchfileindownloaddirectory)]
29: public httpresponsemessage searchfileindownloaddirectory(string filename)
30: {
31: // .........................................
32: // full code available in the source control
33: // .........................................
34: }
35:
36: ///
37: /// asynchronous download file
38: ///
39: ///filename value
40: /// tasked file stream response
41: [route(downloadasync)]
42: [httpget]
43: public async task downloadfileasync(string filename)
44: {
45: // .........................................
46: // full code available in the source control
47: // .........................................
48: }
49:
50: ///
51: /// download file
52: ///
53: ///filename value
54: /// file stream response
55: [route(download)]
56: [httpget]
57: public httpresponsemessage downloadfile(string filename)
58: {
59: // .........................................
60: // full code available in the source control
61: // .........................................
62: }
63:
64: ///
65: /// upload file(s)
66: ///
67: ///an indicator to overwrite a file if it exist in the server
68: /// message response
69: [route(upload)]
70: [httppost]
71: public httpresponsemessage uploadfile(bool overwrite)
72: {
73: // .........................................
74: // full code available in the source control
75: // .........................................
76: }
77:
78: ///
79: /// asynchronous upload file
80: ///
81: ///an indicator to overwrite a file if it exist in the server
82: /// tasked message response
83: [route(uploadasync)]
84: [httppost]
85: public async task uploadfileasync(bool overwrite)
86: {
87: // .........................................
88: // full code available in the source control
89: // .........................................
90: }
91: }
download 服务方法首先需要确认请求的文件是否存在,如果未找到,则返回错误提示“file is not found”,如果找到此文件,内容则转换为字节附加到响应对象,为“application/octet-stream” mimi 内容类型。
1: ///
2: /// download file
3: ///
4: ///filename value
5: /// file stream response
6: [route(download)]
7: [httpget]
8: public httpresponsemessage downloadfile(string filename)
9: {
10: httpresponsemessage response = request.createresponse();
11: filemetadata metadata = new filemetadata();
12: try
13: {
14: string filepath = path.combine(this.getdownloadpath(), @, filename);
15: fileinfo fileinfo = new fileinfo(filepath);
16:
17: if (!fileinfo.exists)
18: {
19: metadata.fileresponsemessage.isexists = false;
20: metadata.fileresponsemessage.content = string.format({0} file is not found !, filename);
21: response = request.createresponse(httpstatuscode.notfound, metadata, new mediatypeheadervalue(text/json));
22: }
23: else
24: {
25: response.headers.acceptranges.add(bytes);
26: response.statuscode = httpstatuscode.ok;
27: response.content = new streamcontent(fileinfo.readstream());
28: response.content.headers.contentdisposition = new contentdispositionheadervalue(attachment);
29: response.content.headers.contentdisposition.filename = filename;
30: response.content.headers.contenttype = new mediatypeheadervalue(application/octet-stream);
31: response.content.headers.contentlength = fileinfo.length;
32: }
33: }
34: catch (exception exception)
35: {
36: // log exception and return gracefully
37: metadata = new filemetadata();
38: metadata.fileresponsemessage.content = processexception(exception);
39: response = request.createresponse(httpstatuscode.internalservererror, metadata, new mediatypeheadervalue(text/json));
40: }
41: return response;
42: }
upload服务方法则会在
multipart/form-data mimi 内容类型执行,首先会检测http 请求的内容类型是否是多主体,如果是,则对比内容长度是否超过最大尺寸,如果没有超过,则开始上传内容,当操作完成之后,则提示相应的信息。
代码片段如下:
1: ///
2: /// upload file(s)
3: ///
4: ///an indicator to overwrite a file if it exist in the server.
5: /// message response
6: [route(upload)]
7: [httppost]
8: public httpresponsemessage uploadfile(bool overwrite)
9: {
10: httpresponsemessage response = request.createresponse();
11: list fileresponsemessages = new list();
12: fileresponsemessage fileresponsemessage = new fileresponsemessage { isexists = false };
13:
14: try
15: {
16: if (!request.content.ismimemultipartcontent())
17: {
18: fileresponsemessage.content = upload data request is not valid !;
19: fileresponsemessages.add(fileresponsemessage);
20: response = request.createresponse(httpstatuscode.unsupportedmediatype, fileresponsemessages, new mediatypeheadervalue(text/json));
21: }
22:
23: else
24: {
25: response = processuploadrequest(overwrite);
26: }
27: }
28: catch (exception exception)
29: {
30: // log exception and return gracefully
31: fileresponsemessage = new fileresponsemessage { isexists = false };
32: fileresponsemessage.content = processexception(exception);
33: fileresponsemessages.add(fileresponsemessage);
34: response = request.createresponse(httpstatuscode.internalservererror, fileresponsemessages, new mediatypeheadervalue(text/json));
35:
36: }
37: return response;
38: }
39:
40: ///
41: /// asynchronous upload file
42: ///
43: ///an indicator to overwrite a file if it exist in the server.
44: /// tasked message response
45: [route(uploadasync)]
46: [httppost]
47: public async task uploadfileasync(bool overwrite)
48: {
49: return await new taskfactory().startnew(
50: () =>
51: {
52: return uploadfile(overwrite);
53: });
54: }
55:
56: ///
57: /// process upload request in the server
58: ///
59: ///an indicator to overwrite a file if it exist in the server.
60: /// list of message object
61: private httpresponsemessage processuploadrequest(bool overwrite)
62: {
63: // .........................................
64: // full code available in the source control
65: // .........................................
66: }
调用download 及 upload 文件方法是控制台应用,app 假定文件流服务通过httpclient和相关类。基本下载文件代码,创建下载http 请求对象。
1: ///
2: /// download file
3: ///
4: /// awaitable task object
5: private static async task downloadfile()
6: {
7: console.foregroundcolor = consolecolor.green;
8: console.writeline(please specify file name with extension and press enter :- );
9: string filename = console.readline();
10: string localdownloadpath = string.concat(@c:, filename); // the path can be configurable
11: bool overwrite = true;
12: string actionurl = string.concat(downloadasync?filename=, filename);
13:
14: try
15: {
16: console.writeline(string.format(start downloading @ {0}, {1} time ,
17: datetime.now.tolongdatestring(),
18: datetime.now.tolongtimestring()));
19:
20:
21: using (httpclient httpclient = new httpclient())
22: {
23: httpclient.baseaddress = basestreamingurl;
24: httprequestmessage request = new httprequestmessage(httpmethod.get, actionurl);
25:
26: await httpclient.sendasync(request, httpcompletionoption.responseheadersread).
27: continuewith((response)
28: =>
29: {
30: console.writeline();
31: try
32: {
33: processdownloadresponse(localdownloadpath, overwrite, response);
34: }
35: catch (aggregateexception aggregateexception)
36: {
37: console.foregroundcolor = consolecolor.red;
38: console.writeline(string.format(exception : , aggregateexception));
39: }
40: });
41: }
42: }
43: catch (exception ex)
44: {
45: console.foregroundcolor = consolecolor.red;
46: console.writeline(ex.message);
47: }
48: }
49:
50:
51: ///
52: /// process download response object
53: ///
54: ///local download file path
55: ///an indicator to overwrite a file if it exist in the client.
56: ///awaitable httpresponsemessage task value
57: private static void processdownloadresponse(string localdownloadfilepath, bool overwrite,
58: task response)
59: {
60: if (response.result.issuccessstatuscode)
61: {
62: response.result.content.downloadfile(localdownloadfilepath, overwrite).
63: continuewith((downloadmessage)
64: =>
65: {
66: console.foregroundcolor = consolecolor.green;
67: console.writeline(downloadmessage.tryresult());
68: });
69: }
70: else
71: {
72: processfailresponse(response);
73: }
74: }
注意上述代码中httpclient 对象发送请求,并等待响应发送header内容(httpcompletionoption.responseheadersread )。而不是发送全部的响应内容文件。一旦response header 被读,则执行验证,一旦验证成功,则执行下载方法。
以下代码调用upload 文件流,与下载方法类似,创建多主体表单数据,并发送给服务器端。
1: ///
2: /// upload file
3: ///
4: /// awaitable task object
5: private static async task uploadfile()
6: {
7: try
8: {
9: string uploadrequesturi = uploadasync?overwrite=true;
10:
11: multipartformdatacontent formdatacontent = new multipartformdatacontent();
12:
13: // validate the file and add to multipartformdatacontent object
14: formdatacontent.adduploadfile(@c: ophoto.png);
15: formdatacontent.adduploadfile(@c:readme.txt);
16:
17: if (!formdatacontent.hascontent()) // no files found to be uploaded
18: {
19: console.foregroundcolor = consolecolor.red;
20: console.write(formdatacontent.getuploadfileerrormesage());
21: return;
22: }
23: else
24: {
25: string uploaderrormessage = formdatacontent.getuploadfileerrormesage();
26: if (!string.isnullorwhitespace(uploaderrormessage)) // some files couldn't be found
27: {
28: console.foregroundcolor = consolecolor.red;
29: console.write(uploaderrormessage);
30: }
31:
32: httprequestmessage request = new httprequestmessage(httpmethod.post, uploadrequesturi);
33: request.content = formdatacontent;
34:
35: using (httpclient httpclient = new httpclient())
36: {
37: console.foregroundcolor = consolecolor.green;
38: console.writeline(string.format(start uploading @ {0}, {1} time ,
39: datetime.now.tolongdatestring(),
40: datetime.now.tolongtimestring()));
41:
42: httpclient.baseaddress = basestreamingurl;
43: await httpclient.sendasync(request).
44: continuewith((response)
45: =>
46: {
47: try
48: {
49: processuploadresponse(response);
50: }
51: catch (aggregateexception aggregateexception)
52: {
53: console.foregroundcolor = consolecolor.red;
54: console.writeline(string.format(exception : , aggregateexception));
55: }
56: });
57: }
58: }
59: }
60: catch (exception ex)
61: {
62: console.foregroundcolor = consolecolor.red;
63: console.writeline(ex.message);
64: }
65: }
66:
67: ///
68: /// process download response object
69: ///
70: ///awaitable httpresponsemessage task value
71: private static void processuploadresponse(task response)
72: {
73: if (response.result.issuccessstatuscode)
74: {
75: string uploadmessage = string.format( upload completed @ {0}, {1} time ,
76: datetime.now.tolongdatestring(),
77: datetime.now.tolongtimestring());
78: console.foregroundcolor = consolecolor.green;
79: console.writeline(string.format({0} upload message : {1}, uploadmessage,
80: jsonconvert.serializeobject(response.result.content.readasasync>().tryresult(), formatting.indented)));
81: }
82: else
83: {
84: processfailresponse(response);
85: }
86: }
数据流项目由可扩展类和方法组成,本文就不再详述。下篇文章中将介绍“使用https 开发项目”
下载源代码
原文链接:https://www.codeproject.com/articles/838274/web-api-thoughts-of-data-streaming#hist
相信已经有很多文章来介绍asp.net web api 技术,本系列文章主要介绍如何使用数据流,https,以及可扩展的web api 方面的技术,系列文章主要有三篇内容。
主要内容如下:
i 数据流
ii 使用https
iii 可扩展的web api 文档
项目环境要求
- vs 2012(sp4)及以上,
- .net 框架4.5.1
- nuget包,可在packages.config 文件中查寻
本文涉及的知识点
- actionfilter
- authorizationfilter
- delegatehandler
- different web api routing 属性
- mediatypeformatter
- owin
- self hosting
- web api 文档及可扩展功能
.net 框架
- async/await
- .net reflection
- serialization
- asp.net web api/mvc error handling
- iis ,https 及certificate
- 设计准则及技术
前言
自从asp.net mvc 4之后.net 框架开始支持asp.net web api ,asp.net web api 基于http 协议建立的,是构建 restful 服务和处理数据的理想平台,旨在使用http 技术实现对多平台的支持。
asp.net web api 以request-response 的消息转换模式为主,客户端向服务器发送请求,服务器端响应客户端请求。响应可同步或异步。
个人认为使用web api创建应用需要注意的三个关键点:
- 采用服务及方法满足的目标
- 每个方法的输入,如请求
- 每个方法的输出,如响应
通常情况下,asp.net web api 定义method语法与http方法一一对应的,如自定义方法名
getpysicians(),则与http中get 方法匹配。下图是常用匹配表。
但是此方法在很多情况下,并不实用,假如你想在单个api controller 类中定义多个get 或post 方法,在这种情况下,需要定义包含action 的路径,将action 作为uri 的一部分。以下是配置代码:1: public static void register(httpconfiguration config)
2: {
3: // web api configuration and services
4: // web api routes
5: config.maphttpattributeroutes();
6:
7: config.routes.maphttproute(name: physicianapi,
8: routetemplate: {controller}/{action}/{id},
9: defaults: new { id = routeparameter.optional });
10: }
但是此方法不足以应对所有情况,如果想实现从*仓库删除文件,并且想调用同一个方法来获取文件,这种情况下,web api 框架需要伪装get 及delete对应的http 方法属性。如图所示:
removefile 方法可被delete(
httpdelete
) 或 get(httpget
)方法同时调用,从某种程度来说,http 方法使开发人员命名 api“方法”变得简单而标准。web api框架也提供了一些其他功能来处理路径方面的问题,与mvc 的路径处理方法相似。因此可定义不同类型的action方法。
数据流
网络app 最常见的执行操作就是获取数据流。asp.net web api 能够处理客户端与服务器端传输的重量级的数据流,数据流可来源于目录文件,也可是数据库中的二进制文件。本文主要介绍两种方法“download”和“upload”实现数据流相关的功能,download是从服务器下载数据操作,而upload则是上传数据到服务器。
相关项目
webapidatastreaming
webapiclient
-
pocolibrary
在对代码解释之前,首先来了解如何配置iis(7.5)和web api 服务web.config 文件。
1. 保证downloads/uploads 涉及的文件具有读写权限。
2. 保证有足够容量的内容或因*空间处理大文件。
3. 如果文件较大
a. 配置web.config 文件时,保证
maxrequestlength 时响应时间
executiontimeout 合理。具体的值主要依赖于数据大小,允许一次性上传的最大数据为2 gb
b. 保证
maxallowedcontentlength 在
requestfiltering部分配置下正确设置,默认值为30mb,最大值4gb
一旦完成预先配置,那么创建数据流服务就非常简单了,首先 需要定义文件流“
apicontroller
”,如下:1: ///
2: /// file streaming api
3: ///
4: [routeprefix(filestreaming)]
5: [requestmodelvalidator]
6: public class streamfilescontroller : apicontroller
7: {
8: ///
9: /// get file meta data
10: ///
11: ///filename value
12: /// filemeta data response.
13: [route(getfilemetadata)]
14: public httpresponsemessage getfilemetadata(string filename)
15: {
16: // .........................................
17: // full code available in the source control
18: // .........................................
19:
20: }
21:
22: ///
23: /// search file and return its meta data in all download directories
24: ///
25: ///filename value
26: /// list of file meta datas response
27: [httpget]
28: [route(searchfileindownloaddirectory)]
29: public httpresponsemessage searchfileindownloaddirectory(string filename)
30: {
31: // .........................................
32: // full code available in the source control
33: // .........................................
34: }
35:
36: ///
37: /// asynchronous download file
38: ///
39: ///filename value
40: /// tasked file stream response
41: [route(downloadasync)]
42: [httpget]
43: public async task downloadfileasync(string filename)
44: {
45: // .........................................
46: // full code available in the source control
47: // .........................................
48: }
49:
50: ///
51: /// download file
52: ///
53: ///filename value
54: /// file stream response
55: [route(download)]
56: [httpget]
57: public httpresponsemessage downloadfile(string filename)
58: {
59: // .........................................
60: // full code available in the source control
61: // .........................................
62: }
63:
64: ///
65: /// upload file(s)
66: ///
67: ///an indicator to overwrite a file if it exist in the server
68: /// message response
69: [route(upload)]
70: [httppost]
71: public httpresponsemessage uploadfile(bool overwrite)
72: {
73: // .........................................
74: // full code available in the source control
75: // .........................................
76: }
77:
78: ///
79: /// asynchronous upload file
80: ///
81: ///an indicator to overwrite a file if it exist in the server
82: /// tasked message response
83: [route(uploadasync)]
84: [httppost]
85: public async task uploadfileasync(bool overwrite)
86: {
87: // .........................................
88: // full code available in the source control
89: // .........................................
90: }
91: }
download 服务方法首先需要确认请求的文件是否存在,如果未找到,则返回错误提示“file is not found”,如果找到此文件,内容则转换为字节附加到响应对象,为“application/octet-stream” mimi 内容类型。
1: ///
2: /// download file
3: ///
4: ///filename value
5: /// file stream response
6: [route(download)]
7: [httpget]
8: public httpresponsemessage downloadfile(string filename)
9: {
10: httpresponsemessage response = request.createresponse();
11: filemetadata metadata = new filemetadata();
12: try
13: {
14: string filepath = path.combine(this.getdownloadpath(), @, filename);
15: fileinfo fileinfo = new fileinfo(filepath);
16:
17: if (!fileinfo.exists)
18: {
19: metadata.fileresponsemessage.isexists = false;
20: metadata.fileresponsemessage.content = string.format({0} file is not found !, filename);
21: response = request.createresponse(httpstatuscode.notfound, metadata, new mediatypeheadervalue(text/json));
22: }
23: else
24: {
25: response.headers.acceptranges.add(bytes);
26: response.statuscode = httpstatuscode.ok;
27: response.content = new streamcontent(fileinfo.readstream());
28: response.content.headers.contentdisposition = new contentdispositionheadervalue(attachment);
29: response.content.headers.contentdisposition.filename = filename;
30: response.content.headers.contenttype = new mediatypeheadervalue(application/octet-stream);
31: response.content.headers.contentlength = fileinfo.length;
32: }
33: }
34: catch (exception exception)
35: {
36: // log exception and return gracefully
37: metadata = new filemetadata();
38: metadata.fileresponsemessage.content = processexception(exception);
39: response = request.createresponse(httpstatuscode.internalservererror, metadata, new mediatypeheadervalue(text/json));
40: }
41: return response;
42: }
upload服务方法则会在
multipart/form-data mimi 内容类型执行,首先会检测http 请求的内容类型是否是多主体,如果是,则对比内容长度是否超过最大尺寸,如果没有超过,则开始上传内容,当操作完成之后,则提示相应的信息。
代码片段如下:
1: ///
2: /// upload file(s)
3: ///
4: ///an indicator to overwrite a file if it exist in the server.
5: /// message response
6: [route(upload)]
7: [httppost]
8: public httpresponsemessage uploadfile(bool overwrite)
9: {
10: httpresponsemessage response = request.createresponse();
11: list fileresponsemessages = new list();
12: fileresponsemessage fileresponsemessage = new fileresponsemessage { isexists = false };
13:
14: try
15: {
16: if (!request.content.ismimemultipartcontent())
17: {
18: fileresponsemessage.content = upload data request is not valid !;
19: fileresponsemessages.add(fileresponsemessage);
20: response = request.createresponse(httpstatuscode.unsupportedmediatype, fileresponsemessages, new mediatypeheadervalue(text/json));
21: }
22:
23: else
24: {
25: response = processuploadrequest(overwrite);
26: }
27: }
28: catch (exception exception)
29: {
30: // log exception and return gracefully
31: fileresponsemessage = new fileresponsemessage { isexists = false };
32: fileresponsemessage.content = processexception(exception);
33: fileresponsemessages.add(fileresponsemessage);
34: response = request.createresponse(httpstatuscode.internalservererror, fileresponsemessages, new mediatypeheadervalue(text/json));
35:
36: }
37: return response;
38: }
39:
40: ///
41: /// asynchronous upload file
42: ///
43: ///an indicator to overwrite a file if it exist in the server.
44: /// tasked message response
45: [route(uploadasync)]
46: [httppost]
47: public async task uploadfileasync(bool overwrite)
48: {
49: return await new taskfactory().startnew(
50: () =>
51: {
52: return uploadfile(overwrite);
53: });
54: }
55:
56: ///
57: /// process upload request in the server
58: ///
59: ///an indicator to overwrite a file if it exist in the server.
60: /// list of message object
61: private httpresponsemessage processuploadrequest(bool overwrite)
62: {
63: // .........................................
64: // full code available in the source control
65: // .........................................
66: }
调用download 及 upload 文件方法是控制台应用,app 假定文件流服务通过httpclient和相关类。基本下载文件代码,创建下载http 请求对象。
1: ///
2: /// download file
3: ///
4: /// awaitable task object
5: private static async task downloadfile()
6: {
7: console.foregroundcolor = consolecolor.green;
8: console.writeline(please specify file name with extension and press enter :- );
9: string filename = console.readline();
10: string localdownloadpath = string.concat(@c:, filename); // the path can be configurable
11: bool overwrite = true;
12: string actionurl = string.concat(downloadasync?filename=, filename);
13:
14: try
15: {
16: console.writeline(string.format(start downloading @ {0}, {1} time ,
17: datetime.now.tolongdatestring(),
18: datetime.now.tolongtimestring()));
19:
20:
21: using (httpclient httpclient = new httpclient())
22: {
23: httpclient.baseaddress = basestreamingurl;
24: httprequestmessage request = new httprequestmessage(httpmethod.get, actionurl);
25:
26: await httpclient.sendasync(request, httpcompletionoption.responseheadersread).
27: continuewith((response)
28: =>
29: {
30: console.writeline();
31: try
32: {
33: processdownloadresponse(localdownloadpath, overwrite, response);
34: }
35: catch (aggregateexception aggregateexception)
36: {
37: console.foregroundcolor = consolecolor.red;
38: console.writeline(string.format(exception : , aggregateexception));
39: }
40: });
41: }
42: }
43: catch (exception ex)
44: {
45: console.foregroundcolor = consolecolor.red;
46: console.writeline(ex.message);
47: }
48: }
49:
50:
51: ///
52: /// process download response object
53: ///
54: ///local download file path
55: ///an indicator to overwrite a file if it exist in the client.
56: ///awaitable httpresponsemessage task value
57: private static void processdownloadresponse(string localdownloadfilepath, bool overwrite,
58: task response)
59: {
60: if (response.result.issuccessstatuscode)
61: {
62: response.result.content.downloadfile(localdownloadfilepath, overwrite).
63: continuewith((downloadmessage)
64: =>
65: {
66: console.foregroundcolor = consolecolor.green;
67: console.writeline(downloadmessage.tryresult());
68: });
69: }
70: else
71: {
72: processfailresponse(response);
73: }
74: }
注意上述代码中httpclient 对象发送请求,并等待响应发送header内容(httpcompletionoption.responseheadersread )。而不是发送全部的响应内容文件。一旦response header 被读,则执行验证,一旦验证成功,则执行下载方法。
以下代码调用upload 文件流,与下载方法类似,创建多主体表单数据,并发送给服务器端。
1: ///
2: /// upload file
3: ///
4: /// awaitable task object
5: private static async task uploadfile()
6: {
7: try
8: {
9: string uploadrequesturi = uploadasync?overwrite=true;
10:
11: multipartformdatacontent formdatacontent = new multipartformdatacontent();
12:
13: // validate the file and add to multipartformdatacontent object
14: formdatacontent.adduploadfile(@c: ophoto.png);
15: formdatacontent.adduploadfile(@c:readme.txt);
16:
17: if (!formdatacontent.hascontent()) // no files found to be uploaded
18: {
19: console.foregroundcolor = consolecolor.red;
20: console.write(formdatacontent.getuploadfileerrormesage());
21: return;
22: }
23: else
24: {
25: string uploaderrormessage = formdatacontent.getuploadfileerrormesage();
26: if (!string.isnullorwhitespace(uploaderrormessage)) // some files couldn't be found
27: {
28: console.foregroundcolor = consolecolor.red;
29: console.write(uploaderrormessage);
30: }
31:
32: httprequestmessage request = new httprequestmessage(httpmethod.post, uploadrequesturi);
33: request.content = formdatacontent;
34:
35: using (httpclient httpclient = new httpclient())
36: {
37: console.foregroundcolor = consolecolor.green;
38: console.writeline(string.format(start uploading @ {0}, {1} time ,
39: datetime.now.tolongdatestring(),
40: datetime.now.tolongtimestring()));
41:
42: httpclient.baseaddress = basestreamingurl;
43: await httpclient.sendasync(request).
44: continuewith((response)
45: =>
46: {
47: try
48: {
49: processuploadresponse(response);
50: }
51: catch (aggregateexception aggregateexception)
52: {
53: console.foregroundcolor = consolecolor.red;
54: console.writeline(string.format(exception : , aggregateexception));
55: }
56: });
57: }
58: }
59: }
60: catch (exception ex)
61: {
62: console.foregroundcolor = consolecolor.red;
63: console.writeline(ex.message);
64: }
65: }
66:
67: ///
68: /// process download response object
69: ///
70: ///awaitable httpresponsemessage task value
71: private static void processuploadresponse(task response)
72: {
73: if (response.result.issuccessstatuscode)
74: {
75: string uploadmessage = string.format( upload completed @ {0}, {1} time ,
76: datetime.now.tolongdatestring(),
77: datetime.now.tolongtimestring());
78: console.foregroundcolor = consolecolor.green;
79: console.writeline(string.format({0} upload message : {1}, uploadmessage,
80: jsonconvert.serializeobject(response.result.content.readasasync>().tryresult(), formatting.indented)));
81: }
82: else
83: {
84: processfailresponse(response);
85: }
86: }
数据流项目由可扩展类和方法组成,本文就不再详述。下篇文章中将介绍“使用https 开发项目”
下一篇: 成人的世界,丰富多彩而搞笑有趣
推荐阅读
-
或许是你应该了解的一些 ASP.NET Core Web API 使用小技巧
-
ASP.NET Web API 应用教程(一) ——数据流使用
-
使用ASP.NET Web API和Web API Client Gen使Angular 2应用程序的开发更加高效
-
使用ASP.NET Web Api构建基于REST风格的服务实战系列教程——使用Repository模式构建数据库访问层
-
【Web API系列教程】1.3 — 实战:用ASP.NET Web API和Angular.js创建单页面应用程序(上)...
-
使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【七】——实现资源的分页
-
使用 ASP.NET Core MVC 创建 Web API(一)
-
如何使用ASP.NET Core、EF Core、ABP(ASP.NET Boilerplate)创建分层的Web应用程序(第一部分)
-
ASP.NET Core Web 应用程序系列(一)- 使用ASP.NET Core内置的IoC容器DI进行批量依赖注入(MVC当中应用)
-
ASP.NET Web API 应用教程(一) ——数据流使用