1. 程式人生 > >asp.net web api 控制器

asp.net web api 控制器

method 集合 ati microsoft options accept arr 場景 okr

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");

根據實際的需要可以使用以下幾種類型:StreamContentPushStreamContentByteArrayContentStringContent。

使用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 控制器