asp.net web api 控制器
1控制器操作的參數
控制器操作的參數可以是內置類型也可以是自定義類型,無參也是允許的。
2控制器操作返回值
類型 |
說明 |
void |
操作返回值為void時,Web API返回空HTTP響應,其狀態碼為204(無內容) |
HttpResponseMessage |
Web api會將此返回值直接轉換為HTTP消息 |
IHttpActionResult |
接口形式 |
內置類型或自定義類型 |
無 |
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
---------------------------------------------------------------------
轉載與引用請註明出處。
時間倉促,水平有限,如有不當之處,歡迎指正。
asp.net web api 控制器