发布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 判断一下,传进来的引用类型参数是否包含有效值