相信已经有很多文章来介绍asp.net web api 技术,本系列文章主要介绍如何使用数据流,https,以及可扩展的web api 方面的技术,系列文章主要有三篇内容。

主要内容如下:

i 数据流

ii 使用https

iii 可扩展的web api 文档

 

项目环境要求

  • vs 2012(sp4)及以上,
  • .net 框架4.5.1
  • nuget包,可在packages.config 文件中查寻

    本文涉及的知识点

    1. actionfilter
    2. authorizationfilter
    3. delegatehandler
    4. different web api routing 属性
    5. mediatypeformatter
    6. owin
    7. self hosting
    8. web api 文档及可扩展功能

      .net 框架

      1. async/await
      2. .net reflection
      3. serialization
      4. asp.net web api/mvc error handling
      5. iis ,https 及certificate
      6. 设计准则及技术

        前言

         

        自从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 文件中查寻

              本文涉及的知识点

              1. actionfilter
              2. authorizationfilter
              3. delegatehandler
              4. different web api routing 属性
              5. mediatypeformatter
              6. owin
              7. self hosting
              8. web api 文档及可扩展功能

                .net 框架

                1. async/await
                2. .net reflection
                3. serialization
                4. asp.net web api/mvc error handling
                5. iis ,https 及certificate
                6. 设计准则及技术

                  前言

                   

                  自从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 开发项目”