發佈webapi的問題前端
配置問題 webapi的項目要前端訪問,須要在web.config配置文件中添加以下配置 在system.webServer節點下面添加 <modules runAllManagedModulesForAllRequests="true" /> <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Headers" value="*" /> <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE" /> </customHeaders> </httpProtocol> 在Global.asax.cs文件中添加 GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
最基礎的demoios
public class ProductsController : ApiController { MyTest[] tests = new MyTest[] { new MyTest {Id = 1, Name = "蘋果", Category = "水果", Price = 10}, new MyTest {Id = 2, Name = "番茄", Category = "蔬菜", Price = 5}, new MyTest {Id = 3, Name = "豬肉", Category = "肉類", Price = 20} }; public IEnumerable<MyTest> GetAllProducts() { return tests; } public IHttpActionResult GetProduct(int id) { var product = tests.FirstOrDefault(p => p.Id == id); if(product == null) { return NotFound(); } return Ok(product); } } 將程序編譯好,而後發佈出去就能夠經過以下方式請求數據 var axiosInstance = window.axios.create({ baseURL: "http://192.168.31.198:8888/api", timeout: 5000 }) // 或者是products/2 獲取具體某一條數據 axiosInstance.get("products").then(function (res) { debugger }).catch(function (err) { console.log(err); })
控制器中方法的返回值web
返回void 若是一個get方法寫成 public void GetAllProducts(){} 那麼HTTP響應狀態碼是204,表示沒有返回內容 返回HttpResponseMessage 若是返回的是HttpResponseMessage對象,那麼請求的HTTP響應信息就是HttpResponseMessage對象 public HttpResponseMessage GetAllProducts() { // 建立HttpResponseMessage對象,而且將返回值設置爲 葉家偉 HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "葉家偉"); // 設置響應的返回內容,StringContent用來返回字符串的Json對象 response.Content = new StringContent(@"{""a"": ""1""}", Encoding.UTF8); // 設置響應頭的緩存控制 response.Headers.CacheControl = new CacheControlHeaderValue { NoCache = false }; return response; } 能夠直接設置 HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, tests); 將tests可枚舉對象做爲返回結果 返回IHttpActionResult IHttpActionResult是HttpResponseMessage的生產工廠 若是一個控制器的方法返回一個IHttpActionResult,那麼會自動調用ExecuteAsync方法建立HttpResponseMessage ApiController提供了不少的內置生產IHttpActionResult類型的函數,方便調用,好比OK,NotFound等 其餘類型的返回值 用戶能夠返回值類型和引用類型,web api使用媒體序列化器解析返回值類型,默認支持的數據格式有 xml,json,bson,form-urlencoded,若是有其餘類型須要本身手動的建立 public MyTest[] GetAllProducts() { return tests; }
建立webapi文檔頁正則表達式
首先,安裝 Install-Package Microsoft.AspNet.WebApi.HelpPage 而後,在Global.asax文件中的Application_Start方法下添加 AreaRegistration.RegisterAllAreas(); 而後,在Areas/HelpPage/App_Start/HelpPageConfig.cs,開啓 config.SetDocumentationProvider(new XmlDocumentationProvider( HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml"))); 在項目屬性的生成中開啓XML documentation file 添加 App_Data/XMLDocument.xml 最後發佈,將相關的資源包含到項目中來,而後生成,完事兒了發佈便可 剩下的就是寫註釋了
路由json
控制器中的方法能夠使用 GET,POST,PUT和DELETE 開頭的命名規則,來指定具體請求對應的方法 固然,你也能夠選擇修飾符的方式來指定方法,支持的修飾符 HttpGet, HttpPut, HttpPost, or HttpDelete [HttpPost] public MyTest[] AllProducts() { return tests; } 使用 [AcceptVerbs("GET", "HEAD")] 這種寫法,能夠支持多種http請求,而且還能夠使用GET,POST,PUT和DELETE以外的方式 另外若是你想把具體的方法的名稱也加到請求的url中,那麼能夠配合上面的修飾符形式,結合下面的方法實現 首先,將WebApiConfig.cs文件中的配置改爲 config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); 還能夠這樣配置 config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{action}/{id}", defaults: new { controller = "Department", id = RouteParameter.Optional } ); // 表示若是api知足routeTemplate那麼使用Department控制器匹配,若是不知足則執行其餘的路由匹配規則 控制器中的方法的寫法 [HttpPost] public MyTest[] AllProducts() { return tests; } url的請求方式 post("products/AllProducts") 若是,想無視某個方法,添加 [NonAction] 便可
路由配置axios
路由模板,也就是路由配置中的routeTemplate選項 "api/{controller}/yejiawei/{action}/{id}" 其中使用花括號包裹的是佔位符,能夠有多個佔位符 路由參數默認值,是路由配置中的defaults參數,用來給方法的參數指定默認值 new { id = RouteParameter.Optional } 表示id這個字段在匹配的時候能夠有,也能夠沒有 new { id = 2 } 表示id這個字段能夠有也能夠沒有,可是若是沒有會自動設置爲2 new { id = @"\d+" } 能夠使用正則限定id能夠的值 建立路由匹配規則的方式 除了使用config.Routes.MapHttpRoute方法建立路由規則外,還能夠使用以下的方式 IHttpRoute myRoute = config.Routes.CreateRoute( "api/{controller}/yejiawei/{id}", new { id = RouteParameter.Optional }, null ); config.Routes.Add("MyRoute", myRoute); MapHttpRoute方法的參數除了上面將到的name,routeTemplate,defaults還有以下的參數 constraints 使用正則表達式,限定傳參的要求 constraints: new { id = @"/d+"} handler 每一個請求的分發函數 路由字典 var routeData = Request.GetRouteData(); IDictionary<string, object> routes = routeData.Values; foreach(KeyValuePair<string, object> item in routes) { Console.WriteLine("Key: {0}, Value{1}", item.Key, item.Value); } 路由匹配到的全部佔位符都保存在上面的routes裏面, 若是一個佔位符被設置成 RouteParameter.Optional 那麼若是這個佔位符沒有提供的話,就不會添加到路由佔位符對象裏面 defaults選項中也能夠包含routeTemplate中不存在的佔位符,這樣能夠保存一些額外的信息 路由參數的獲取方式 默認狀況下簡單的數據類型從URL中獲取,複雜的數據類型從請求體中獲取
基於路由屬性的控制器方法api
上面咱們講的都是基於約定的路由,由於路由規則都是在配置文件中預先定義好的,能夠使用路由屬性更加靈活的配置請求 路由配置文件中 config.MapHttpAttributeRoutes(); 這段代碼就是屬性路由的配置,當方法沒有配置屬性路由,默認使用基於約定的路由 使用例子 [Route("yejiawei/{id}/haha")] [HttpPost] public int AllProducts(int id) { return id; } 匹配的路由 yejiawei/3/haha 注意api已經不須要了 能夠給控制器添加路由前綴 [RoutePrefix("yejiawei")] 那麼控制器的方法只須要簡寫成 [Route("{id}/haha")] 便可 若是有的控制器方法的前綴不一致能夠使用~重寫 [Route("~/api/{id}/haha")] 還能夠添加路由約束 [Route("{id:int}/haha")] 支持的路由約束還有不少,自行查閱 添加可選的路由參數 [Route("{id:int?}/haha")] 控制器的方法要設置默認值 添加路由參數默認值 [Route("{id:int=2}/haha")]
路由參數跨域
參數名稱必須相同,不區分大小寫 get請求 值類型參數從url中獲取 public string GetDepartments(string str) { return str; } 符合的api Departments?str=bbb post請求 值類型參數默認從url中獲取 public string PostDepartments(string str) { return str; } 符合的api Departments?str=ccc 引用類型的參數默認從請求體中獲取 public class Demo { public string Name { get; set; } public string Sex { get; set; } } [Route("yejiawei/Departments")] public Demo PostDepartments(Demo obj) { return obj; } 符合的api axios.post("yejiawei/Departments", { Name: "yejiawei", Sex: "女" }).then( (res) => { debugger }).catch( (err) => {console.log(err);}) 注意:應用類型的參數,只能存在一個,put方法的處理方式和post一致 若是想修改默認的參數獲取規則,能夠使用 [FromUri] 可讓引用類型的屬性從uri中的參數獲取 public class Demo { public string Name { get; set; } public string Sex { get; set; } } public Demo GetDepartments([FromUri] Demo obj) { return obj; } 匹配的api以下 axiosInstance.get("api/Departments", { params: { Name: "yejiawei", Sex: "女" } }) [FromBody] 可讓值類型從請求體中獲取 [Route("yejiawei/BodyTest")] public string Post ([FromBody] string name) { return name; } 匹配的api以下 axiosInstance.post("yejiawei/BodyTest", "=yejiawei") 若是你不想上面這種奇怪的寫法,能夠參考以下 首先定義一個類 public class Test { public string Name { get; set; } } 控制器方法改爲以下 [Route("yejiawei/BodyTest")] public string Post ([FromBody] Test name) { return name.Name; } 符合的api寫法 axiosInstance.post("yejiawei/BodyTest", { name: "yejiawei" }) 注意: [FromBody] 只能使用於一個參數
webapi跨域解決緩存
使用開局介紹的配置只能簡單的解決get,post不帶請求體這類的跨域請求,若是想完全的跨域,請看下面 第一步,安裝 Install-Package Microsoft.AspNet.WebApi.Cors 第二步,在WebApiConfig.cs中添加 config.EnableCors(); 第三步,在會被跨域的控制器上添加 [EnableCors(origins: "http://mywebclient.azurewebsites.net", headers: "*", methods: "*")] origins對應前端發請求的地址 第四步,註釋掉本文開頭所說配置中的 <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Headers" value="*" /> <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE" /> 幹掉上面這三句句話,此時你的跨域配置已經ok了 注: [EnableCors] 能夠單獨給一個控制器方法使用 [DisableCors] 能夠給一個單獨的控制器方法禁用跨域 開啓全局跨域 讓任何一個控制器都支持跨域,只須要將上面的第二步改爲 var cors = new EnableCorsAttribute("http://localhost:3000", "*", "*"); config.EnableCors(cors); 設置規則的順序 Action > Controller > Global origins參數詳解 origins支持一逗號分隔,寫多個跨域地址,也能夠支持通配符 * methods參數 methods參數用來指定具體的http方法,能夠以逗號分隔寫多個,也支持通配符 headers參數不須要手動配置,寫成通配符便可
請求和響應的數據格式化app
MIME類型指定了數據的基本格式 在HTTP請求中 Accept頭指定了客戶端指望獲得的數據格式 Content-Type指定了請求發送的數據格式 Web Api根據Content-Type頭指定的格式類型,將請求的數據轉化成對應的CLR對象,同時根據Accept頭將響應的結果序列化成對應的數據格式,Web Api 內置支持JSON, XML, BSON, form-urlencoded 序列化器,這就是說這幾種格式的數據Web Api會自動處理 因此僅僅改變Content-Type和Accept就能夠方便的序列化請求或者響應的數據 媒體類型格式序列化器 webapi可以自動識別而且處理JSON和XML數據格式,是由於Web API包含如下的內置媒體格式化器 媒體格式化器類 JsonMediaTypeFormatter 處理的MIME類型 application/json, text/json 用來處理JSON格式化 XmlMediaTypeFormatter 處理的MIME類型 application/xml, text/json 用來處理XML格式化 FormUrlEncodedMediaTypeFormatter 處理的MIME類型 application/x-www-form-urlencoded 處理HTML表達URL編碼的數據 JQueryMvcFormUrlEncodedFormatter 處理的MIME類型 application/x-www-form-urlencoded 處理模型綁定的HTML表單URL編碼的數據 訪問全部的媒體格式化器 [Route("yejiawei/MIMEType")] public IEnumerable<string> Get() { IList<string> formatters = new List<string>(); foreach(var item in GlobalConfiguration.Configuration.Formatters) { formatters.Add(item.ToString()); } return formatters.AsEnumerable<string>(); } 單獨訪問指定的媒體格式化器 GlobalConfiguration.Configuration.Formatters.JsonFormatter.GetType().FullName GlobalConfiguration.Configuration.Formatters.FormUrlEncodedFormatter.GetType().FullName webapi 處理Json格式的數據默認使用 PascalCase, 能夠設置成支持camelCase的 在WebApiConfig.cs中添加以下代碼 config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
WebApi過濾器
過濾器能夠在控制器方法調用以前和以後執行 簡單的一個用法 先建立一個實現ActionFilterAttribute的類 public class LogAttribute : ActionFilterAttribute { public LogAttribute() { } public override void OnActionExecuting(HttpActionContext actionContext) { Trace.WriteLine(string.Format("Action Method {0} executing at {1}", actionContext.ActionDescriptor.ActionName, DateTime.Now.ToShortDateString()), "Web API Logs"); } public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { Trace.WriteLine(string.Format("Action Method {0} executed at {1}", actionExecutedContext.ActionContext.ActionDescriptor.ActionName, DateTime.Now.ToShortDateString()), "Web API Logs"); } } 而後在控制器類的頭部添加屬性 [Log] 便可,當控制器調用方法時,OnActionExecuting會執行,當方法調用完畢之後OnActionExecuted會執行
WebApi使用注意點
在寫post,put請求以前,要先使用 ModelState.IsValid 判斷一下,傳進來的引用類型參數是否包含有效值