百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

熟练使用ASP.NET Web API之控制器

bigegpt 2024-09-11 01:05 6 浏览

1控制器操作的参数

控制器操作的参数可以是内置类型也可以是自定义类型,无参也是允许的。

还可以为控制器操作参数提供默认值。

例:

public IHttpActionResult User(int id=1)
 {
 return Json("id:"+id);
 }

2控制器操作返回值

2.1返回值为HttpResponseMessage

返回值为此类型时,有两种设置方式。

第一种调用HttpResponseMessage的构造函数,实例化一个HttpResponseMessage,并返回。Web API会将其直接转换为HTTP消息。

例:

 public HttpResponseMessage Get()
 {
 FileStream fs = new FileStream(@"D:\GreatFile.txt",FileMode.Open);//文件流
 HttpResponseMessage hrm = new HttpResponseMessage
 {
 StatusCode = HttpStatusCode.OK,
 Content = new StreamContent(fs, 4096)
 };
 
 return hrm;
 }

第二种方式是调用Request.CreateResponse方法,将自定义类型传递给它。Web API会调用序列化器将其序列化后写入HTTP响应。

 public HttpResponseMessage Get()
 {
 var publisher = new PublisherModel{Title ="ASP.NET Web API编程实战",Year=2018};
 return Request.CreateResponse<PublisherModel>(HttpStatusCode.OK, publisher);
 }
	}

HttpResponseMessage类的定义如下:

 public class HttpResponseMessage : IDisposable
 {
 public HttpResponseMessage();
 // 参数: statusCode:HTTP 响应的状态代码。
 public HttpResponseMessage(HttpStatusCode statusCode);
 // 获取或设置 HTTP 响应消息的内容。
 //返回 System.Net.Http.HttpContent。 HTTP 响应消息的内容。
 public HttpContent Content { get; set; }
 //获取 HTTP 响应标头的集合。
 public HttpResponseHeaders Headers { get; }
 //获取一个值,该值指示 HTTP 响应是否成功。
//System.Net.Http.HttpResponseMessage.StatusCode。在 200-299 //范围中,则为 true;否则为 false。
 public bool IsSuccessStatusCode { get; }
 //获取或设置服务器与状态代码通常一起发送的原因短语。
 //返回 System.String。 服务器发送的原因词组。
 public string ReasonPhrase { get; set; }
 //获取或设置导致此响应消息的请求消息。
 public HttpRequestMessage RequestMessage { get; set; }
 //获取或设置 HTTP 响应的状态代码。
 public HttpStatusCode StatusCode { get; set; }
 //获取或设置 HTTP 消息版本。默认值为 1.1。
 public Version Version { get; set; }
 //释放由 System.Net.Http.HttpResponseMessage 使用的非托管资源,并可根据需要释放托管资源。
 //参数: 如果为 true,则释放托管资源和非托管资源;如果为 false,则仅释放非托管资源。
 protected virtual void Dispose(bool disposing);
 //如果 HTTP 响应的 System.Net.Http.HttpResponseMessage.IsSuccessStatusCode 属性//为 false,将引发异常。
 public HttpResponseMessage EnsureSuccessStatusCode();
 //返回表示当前对象的字符串。
 public override string ToString();
	}

2.1.1设置响应状态:

可以通过构造函数设置响应状态码,也可以通过StatusCode 属性设置响应状态码。

2.1.2设置HTTP消息头

通过HttpResponseMessage.Headers属性设置HTTP消息头,其类型为HttpResponseHeaders,下面是这个类型的定义:

public sealed class HttpResponseHeaders : HttpHeaders
 {
 //获取 HTTP 请求的 Accept-Ranges 标头的值。
 public HttpHeaderValueCollection<string> AcceptRanges { get; }
 
 //获取或设置 HTTP 响应的 Age 标头值。
 public TimeSpan? Age { get; set; } 
 //获取或设置 HTTP 响应的 Cache-Control 标头值。
 public CacheControlHeaderValue CacheControl { get; set; }
 //获取 HTTP 请求的 Connection 标头的值。
 public HttpHeaderValueCollection<string> Connection { get; }
 //获取或设置指示 HTTP 响应的 Connection 标头是否应包含 Close 的值。
 public bool? ConnectionClose { get; set; }
 //获取或设置 HTTP 响应的 Date 标头值。
 public DateTimeOffset? Date { get; set; }
 //获取或设置 HTTP 响应的 ETag 标头值。
 public EntityTagHeaderValue ETag { get; set; }
 //获取或设置 HTTP 响应的 Location 标头值。
 public Uri Location { get; set; }
 //获取 HTTP 请求的 Pragma 标头的值。
 public HttpHeaderValueCollection<NameValueHeaderValue> Pragma { get; }
 //获取 HTTP 请求的 Proxy-Authenticate 标头的值。
 public HttpHeaderValueCollection<AuthenticationHeaderValue> ProxyAuthenticate { get; }
 //获取或设置 HTTP 响应的 Retry-After 标头值。
 public RetryConditionHeaderValue RetryAfter { get; set; }
 //获取 HTTP 请求的 Server 标头的值。
 public HttpHeaderValueCollection<ProductInfoHeaderValue> Server { get; }
 //获取 HTTP 请求的 Trailer 标头的值。
 public HttpHeaderValueCollection<string> Trailer { get; }
 //获取 HTTP 请求的 Transfer-Encoding 标头的值。
 public HttpHeaderValueCollection<TransferCodingHeaderValue> TransferEncoding { get; }
 //获取或设置指示 HTTP 响应的 Transfer-Encoding 标头是否应包含 chunked 的值。
 public bool? TransferEncodingChunked { get; set; }
 //获取 HTTP 请求的 Upgrade 标头的值。
 public HttpHeaderValueCollection<ProductHeaderValue> Upgrade { get; }
 //获取 HTTP 请求的 Vary 标头的值。
 public HttpHeaderValueCollection<string> Vary { get; }
 //获取 HTTP 请求的 Via 标头的值。
 public HttpHeaderValueCollection<ViaHeaderValue> Via { get; }
 //获取 HTTP 请求的 Warning 标头的值。
 public HttpHeaderValueCollection<WarningHeaderValue> Warning { get; }
 //获取 HTTP 请求的 WWW-Authenticate 标头的值。
 public HttpHeaderValueCollection<AuthenticationHeaderValue> WwwAuthenticate { get; }
 }

对部分属性的解析

1)可通过属性AcceptRanges来设置HTTP 请求的 Accept-Ranges 标头,当浏览器发现Accept-Range头时,可以尝试继续中断了的下载,而不是重新开始。设置为none表示不支持范围请求。设置为bytes表示支持范围请求。通过设置此表头,以支持断点续传机制。

例:

HttpResponseMessage hrm = new HttpResponseMessage
 {
 //其他设置
 };
 hrm.Headers.AcceptRanges.Add("bytes");

2)使用属性Location获取或设置重定向地址。

浏览器收到此类响应时会跳转到指定的地址。

例:

 public class ValuesController : ApiController
	{
 public HttpResponseMessage Get(int id)
 {
 HttpResponseMessage hrm = new HttpResponseMessage
 {
 //其他设置
 };
 var controller = this.Request.GetRouteData().Values["controller"];
 var uri = new Uri(this.Url.Link("DefaultApi", new { controller = controller, id = id }));
 hrm.Headers.Location = uri;
 return hrm;
	 }
	}
	}

2.1.3设置消息内容

使用HttpResponseMessage.Content属性设置消息内容。

HttpResponseMessage.Content属性的类型为HttpContent,其定义如下:

public abstract class HttpContent : IDisposable
 {
 //其他代码略
 //根据 RFC 2616 中的定义,获取内容标头。 
	public HttpContentHeaders Headers { get; }
	//其他代码略
	}

HttpContent.Headers 属性

其的定义如下:

public sealed class HttpContentHeaders : HttpHeaders
 {
 //获取 HTTP 响应上的 Content-Disposition 内容标头值。
 public ContentDispositionHeaderValue ContentDisposition { get; set; }
 //获取 HTTP 响应的 Content-Encoding 内容标题的值。
 public ICollection<string> ContentEncoding { get; }
 //获取或设置 HTTP 响应上的 Content-Length 内容标头值。
 public long? ContentLength { get; set; }
 //获取或设置 HTTP 响应上的 Content-Range 内容标头值。
 public ContentRangeHeaderValue ContentRange { get; set; }
 //获取或设置 HTTP 响应上的 Content-Type 内容标头值。
 public MediaTypeHeaderValue ContentType { get; set; }
 	//其他代码略
	}

解析:

1)Content-Disposition 内容标头值

在HTTP场景中,第一个参数或者是inline(默认值,表示回复中的消息体会以页面的一部分或者整个页面的形式展示),或者是attachment(意味着消息体应该被下载到本地;大多数浏览器会呈现一个“保存为”的对话框,将filename的值预填为下载后的文件名,假如它存在的话)。

例:

HttpResponseMessage response = new HttpResponseMessage() ;
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
//设置文件名
response.Content.Headers.ContentDisposition.FileName =”TextFile.txt”;

2)Content-Length,指明发送给接收方的消息主体的大小

例:

HttpResponseMessage response = new HttpResponseMessage();
response.Content.Headers.ContentLength = 32767;

3)Content-Range,一个数据片段在整个文件中的位置

例:

HttpResponseMessage response = new HttpResponseMessage();
new ContentRangeHeaderValue(0, 1024, 32767);

4)Content-Type,用于指示资源的MIME类型

例:

HttpResponseMessage response = new HttpResponseMessage();
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

根据实际的需要可以使用以下几种类型:StreamContent、PushStreamContent、ByteArrayContent、StringContent。

使用StreamContent“拉”模式将数据放入响应

例如:

FileStream fileStream = new FileStream(@"D:\testfile.txt", FileMode.Open);
HttpResponseMessage hrm = new HttpResponseMessage
{
	//其他设置
};
hrm.Content = new StreamContent(fileStream, 1024);

使用PushStreamContent“推”模式将数据放入响应。

推模式的有点是,可以将数据一块一块地写入响应中,而不是一下子将数据先放入缓存中,然后全部发送出去。虽然StreamContent也可以,但只能将FileStream流赋给HttpResponseMessage.Content才能实现流传输,以达控制内存的目的,对于byte[]类型的数据就无能为力了。

例如:

 public class DiskFileStream
 {
 private readonly string filename;
 
 public DiskFileStream(string filename)
 {
 this.filename = filename;
 }
 
 public async Task WriteToStream(Stream outputStream, HttpContent httpContent, TransportContext transportContext)
 {
 try
 {
 var buffer = new byte[65536];
 
 using (var file = File.Open(filename, FileMode.Open, FileAccess.Read))
 {
 var length = (int)file.Length;
 var bytesRead = 1;
 
 while (length > 0 && bytesRead > 0)
 {
 bytesRead = file.Read(buffer, 0, Math.Min(length, buffer.Length));
 await outputStream.WriteAsync(buffer, 0, bytesRead);
 length -= bytesRead;
 }
 }
 }
 catch (HttpException ex)
 {
 return;
 }
 finally
 {
 outputStream.Close();
 }
 }
	}
 public class DownLoadController:ApiController
 {
 public HttpResponseMessage Get(string filename)
 {
 var file = new DiskFileStream(filename);
 
 var response = Request.CreateResponse();
 Func<Stream, HttpContent, TransportContext,Task> onStreamAvailable = file.WriteToStream;
 response.Content = new PushStreamContent(onStreamAvailable, new MediaTypeHeaderValue("application/octet-stream"));
 
 return response;
 }
 }

使用StringContent

在基类控制器使用StringContent,以便返回Json类型的数据。如下定义了一个泛型方法,指定类型T为class。

例如:

public class BaseController : ApiController
 {
 public HttpResponseMessage ToJson<T>(T model) where T : class
 {
 string str = JsonConvert.SerializeObject(model);
 return new HttpResponseMessage { Content = new StringContent(str, Encoding.GetEncoding("UTF-8"), "application/json") };
 }
	}

也可以不使用泛型方法,而对传入类型检测,但是需要做类型检查,不过可以序列化匿名类型。

 public HttpResponseMessage ToJson(Object obj)
 {
 String str = string.Empty;
 if (obj is String || obj is Char)
 {
 str = obj.ToString();
 }
 else
 {
 str = JsonConvert.SerializeObject(obj);
 }
 return new HttpResponseMessage { Content = new StringContent(str, Encoding.GetEncoding("UTF-8"), "application/json") };
 }

2.1.4设置原因短语ReasonPhrase

使用ReasonPhrase属性可以设置消息短语,用于解释状态码代表的含义。消息短语应尽可能地简洁扼要,尽量使用英文。

例:

HttpResponseMessage hrm = new HttpResponseMessage
{
	StatusCode = (HttpStatusCode)701,
	ReasonPhrase = "Unable to find the user"
 
	//其他设置
};

2.2返回值为IHttpActionResult

IHttpActionResult是一个接口,只有一个返回值为Task<System.Net.Http.HttpResponseMessage> 的异步方法ExecuteAsync。

当控制器操作返回此类型时,Web API会调用ExecuteAsync方法创建类型为HttpResponseMessage的实例,然后将这个实例转换为HTTP消息。

例:

实现IHttpActionResult

 public class CustomActionResult : IHttpActionResult
 {
 private object param;
 private HttpRequestMessage request;
 public CustomActionResult(object param,HttpRequestMessage request)
 {
 this.param = param;
 this.request = request;
 }
 public System.Threading.Tasks.Task<HttpResponseMessage> ExecuteAsync(System.Threading.CancellationToken cancellationToken)
 {
 var response = new HttpResponseMessage
 {
 Content = ......,
 RequestMessage = ......
 };
 }
	}

使用CustomActionResult

 public IHttpActionResult GetOther()
 {
 object param = ......
 return CustomActionResult(param,Request);
 }

注意;CustomActionResult 构造函数的参数为object类型,实际项目并不一定如此,这里只是举个例子而已。

System.Web.Http.ApiController提供了几个方法返回值类型都继承自IHttpActionResult

仅举几个常用的方法:

protected internal JsonResult<T> Json<T>(T content);返回值JsonResult继承自IHttpActionResult,可将泛型参数T的实例序列化后写入HTTP响应中。

protected internal virtual NotFoundResult NotFound();返回NotFoundResult,创建一个状态码为404的空响应。

protected internal virtual OkResult Ok();返回值为OkResult ,创建一个状态码为200的空响应。

protected internal virtual OkNegotiatedContentResult<T> Ok<T>(T content);返回值为OkNegotiatedContentResult,创建一个状态码为200的响应,并将参数content实例序列化写入响应消息体中。

2.3返回值为内置类型或自定义类型

返回值为内置类型或自定义类型时,Web API使用格式化器序列化返回值,并将其写入HTTP消息中,响应的状态码为200。

例:

 public IEnumerable<string> Get()
 {
 return new string[] { "value1", "value2" };
 }

3修饰控制器及操作

使用特性修饰控制器及其操作。

HTTP动词特性

包括:HttpGet、HttpPost、HttpPut、HttpDelete,HttpHead,HttpPatch,HttpOptions只能用来修饰操作。

HttpGet:使操作只能处理HTTP GET请求,用于获取资源且不对数据进行修改的操作。

HttpPost:使操作只处理HTTP POST请求,用于传输数据实体或者对数据进行修改的操作。

HttpPut:使操作只处理HTTP PUT请求,用于新增资源或者使用请求中的有效负载替换目标资源的表现形式。

HttpDelete:使操作只处理HTTP DELETE请求,一般使用DELETE请求删除请求URL所指定的资源。

HttpHead:使操作只处理HTTP HEADER请求,使用HEADER请求要求服务器的响应只返回首部,而不返回实体的主体部分。

HttpPatch:使操作只处理HTTP PATCH请求,对资源执行部分修改。

HttpOptions:使操作只处理HTTP OPTIONS请求,用于向服务器询问其支持的方法。

PUT与POST方法的区别在于,PUT方法是幂等的:调用一次与连续调用多次是等价的(即没有副作用),而连续调用多次POST方法可能会有副作用,比如将一个订单重复提交多次。

例:

限定操作只支持post请求。

 [HttpPost]
 public IHttpActionResult ListALL()
 {
 //具体实现
 return Ok();
 }

AcceptVerbs特性

使用AcceptVerbs特性可设置允许多种HTTP方法调用,且支持非标准的HTTP方法。

例:

支持多种方法

[AcceptVerbs("DELETE", "POST")]
 public void Delete(int id)
 {
 }

支持自定义方法,这种方式比较少用,大多数情况下,HTTP标准方法足够用

[AcceptVerbs("LALL")]
 public IHttpActionResult ListALL()
 {
 //具体实现
 return Ok();
 }

为Action重命名

使用ActionName特性为Action重命名。

阻止方法被调用

使用NonAction特性标记Action,阻止其被调用。

使用路由特性

使用RouteAttribute和RoutePrefix可以设置路由值。具体见路由一节。

参考:

1. https://docs.microsoft.com/en-us/aspnet/web-api/

2. https://developer.mozilla.org/zh-CN/docs/Web

相关推荐

最全的MySQL总结,助你向阿里“开炮”(面试题+笔记+思维图)

前言作为一名编程人员,对MySQL一定不会陌生,尤其是互联网行业,对MySQL的使用是比较多的。对于求职者来说,MySQL又是面试中一定会问到的重点,很多人拥有大厂梦,却因为MySQL败下阵来。实际上...

Redis数据库从入门到精通(redis数据库设计)

目录一、常见的非关系型数据库NOSQL分类二、了解Redis三、Redis的单节点安装教程四、Redis的常用命令1、Help帮助命令2、SET命令3、过期命令4、查找键命令5、操作键命令6、GET命...

netcore 急速接入第三方登录,不看后悔

新年新气象,趁着新年的喜庆,肝了十来天,终于发了第一版,希望大家喜欢。如果有不喜欢看文字的童鞋,可以直接看下面的地址体验一下:https://oauthlogin.net/前言此次带来得这个小项目是...

精选 30 个 C++ 面试题(含解析)(c++面试题和答案汇总)

大家好,我是柠檬哥,专注编程知识分享。欢迎关注@程序员柠檬橙,编程路上不迷路,私信发送以下关键字获取编程资源:发送1024打包下载10个G编程资源学习资料发送001获取阿里大神LeetCode...

Oracle 12c系列(一)|多租户容器数据库

作者杨禹航出品沃趣技术Oracle12.1发布至今已有多年,但国内Oracle12C的用户并不多,随着12.2在去年的发布,选择安装Oracle12c的客户量明显增加,在接下来的几年中,Or...

flutter系列之:UI layout简介(flutter-ui-nice)

简介对于一个前端框架来说,除了各个组件之外,最重要的就是将这些组件进行连接的布局了。布局的英文名叫做layout,就是用来描述如何将组件进行摆放的一个约束。在flutter中,基本上所有的对象都是wi...

Flutter 分页功能表格控件(flutter 列表)

老孟导读:前2天有读者问到是否有带分页功能的表格控件,今天分页功能的表格控件详细解析来来。PaginatedDataTablePaginatedDataTable是一个带分页功能的DataTable,...

Flutter | 使用BottomNavigationBar快速构建底部导航

平时我们在使用app时经常会看到底部导航栏,而在flutter中它的实现也较为简单.需要用到的组件:BottomNavigationBar导航栏的主体BottomNavigationBarI...

Android中的数据库和本地存储在Flutter中是怎样实现的

如何使用SharedPreferences?在Android中,你可以使用SharedPreferencesAPI来存储少量的键值对。在Flutter中,使用Shared_Pref...

Flet,一个Flutter应用的实用Python库!

▼Flet:用Python轻松构建跨平台应用!在纷繁复杂的Python框架中,Flet宛如一缕清风,为开发者带来极致的跨平台应用开发体验。它用最简单的Python代码,帮你实现移动端、桌面端...

flutter系列之:做一个图像滤镜(flutter photo)

简介很多时候,我们需要一些特效功能,比如给图片做个滤镜什么的,如果是h5页面,那么我们可以很容易的通过css滤镜来实现这个功能。那么如果在flutter中,如果要实现这样的滤镜功能应该怎么处理呢?一起...

flutter软件开发笔记20-flutter web开发

flutterweb开发优势比较多,采用统一的语言,就能开发不同类型的软件,在web开发中,特别是后台式软件中,相比传统的html5开发,更高效,有点像c++编程的方式,把web设计出来了。一...

Flutter实战-请求封装(五)之设置抓包Proxy

用了两年的flutter,有了一些心得,不虚头巴脑,只求实战有用,以供学习或使用flutter的小伙伴参考,学习尚浅,如有不正确的地方还望各路大神指正,以免误人子弟,在此拜谢~(原创不易,转发请标注来...

为什么不在 Flutter 中使用全局变量来管理状态

我相信没有人用全局变量来管理Flutter应用程序的状态。毫无疑问,我们的Flutter应用程序需要状态管理包或Flutter的基本小部件(例如InheritedWidget或St...

Flutter 攻略(Dart基本数据类型,变量 整理 2)

代码运行从main方法开始voidmain(){print("hellodart");}变量与常量var声明变量未初始化变量为nullvarc;//未初始化print(c)...