c# webapi2 实用详解
本文介绍webapi的使用知识
发布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);
最基础的demo
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);
})
控制器中方法的返回值
返回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
最后发布,将相关的资源包含到项目中来,然后生成,完事儿了发布即可
剩下的就是写注释了
路由
控制器中的方法可以使用 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] 即可
路由配置
路由模板,也就是路由配置中的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中获取,复杂的数据类型从请求体中获取
基于路由属性的控制器方法
上面我们讲的都是基于约定的路由,因为路由规则都是在配置文件中预先定义好的,可以使用路由属性更加灵活的配置请求
路由配置文件中
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参数不需要手动配置,写成通配符即可
请求和响应的数据格式化
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 判断一下,传进来的引用类型参数是否包含有效值
c# webapi2 实用详解的更多相关文章
- linux dd命令实用详解
linux dd命令刻录启动U盘详解 dd命令做usb启动盘十分方便,只须:sudo dd if=xxx.iso of=/dev/sdb bs=1M 用以上命令前必须卸载u盘,sdb是你的u盘,bs= ...
- tar命令的实用详解(C参数和排除文件 --exclude)
一.tar:从压缩包中解压出指定文件 [root@d176 test]# tar ztf nrpe-2.12.tar.gz |grep srcnrpe-2.12/src/nrpe-2.12/src/. ...
- 举例实用详解sc.textFile()和wholeTextFiles()
谈清楚区别,说明白道理,从案例开始: 1 数据准备 用hdfs存放数据,且结合的hue上传准备的数据,我的hue截图: 每个文件下的数据: 以上是3个文件的数据,每一行用英文下的空格隔开: 2 测试 ...
- centos6.5环境下svn服务器和客户端配置实用详解
一.服务器端配置 安装 # yum install -y subversion yum安装软件,不清除软件包的方法 # vim /etc/yum.conf keepcache=0 建立svn版本库数据 ...
- Instrument 实用详解
苹果:Instruments User Guide iPhone Memory Debugging with NSZombie and Instruments 苹果:Mac OS X Debuggin ...
- iOS模式详解—「runtime面试、工作」看我就 🐒 了 ^_^.
Write in the first[写在最前] 对于从事 iOS 开发人员来说,当提到 ** runtime时,我想都可以说出来 「runtime 运行时」和基本使用的方法.相信很多开发者跟我当初一 ...
- NoSQL之Redis高级实用命令详解--安全和主从复制
Android IOS JavaScript HTML5 CSS jQuery Python PHP NodeJS Java Spring MySQL MongoDB Redis NOSQL Vim ...
- [转]js中几种实用的跨域方法原理详解
转自:js中几种实用的跨域方法原理详解 - 无双 - 博客园 // // 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同 ...
- Objective-C 实用关键字详解1「面试、工作」看我就 🐒 了 ^_^.
在写项目 或 阅读别人的代码(一些优秀的源码)中,总能发现一些常见的关键字,随着编程经验的积累大部分还是知道是什么意思 的. 相信很多开发者跟我当初一样,只是基本的常用关键字定义属性会使用,但在关键字 ...
随机推荐
- HDFS相关概念
数据块 每个磁盘都有默认的数据块大小,这是磁盘进行数据读写的最小单位.构建与单个磁盘之上的文件系统通过磁盘块来管理该文件系统中的快.该文件系统块的大小可以使磁盘块的整数倍.文件系统块一般为几千字节,而 ...
- 整体二分learning
整体二分是一个离线的做法 目前可以解决求区间第k大问题 当然划分树主席树都可以的样子.. 为什么我老学一些解决同种问题的算法.. 主要思想大概是这样的: 如果要求[l,r]的区间第K大 而这个区间内 ...
- scrapy的操作
- java集合转换成json时问题和解决方法
json+hibernate死循环问题的一点见解,有需要的朋友可以参考下. [问题]如题所示,在我们使用hibernate框架而又需要将对象转化为json的时候,如果配置了双向的关联关系,就会出现这个 ...
- css3+jquery+js做的翻翻乐小游戏
主要是为了练习一下css3的3D翻转功能,就做了这么个小游戏,做的比较粗糙,但是效果看的见. 主要用到的css3代码如下: html结构: <div class="container& ...
- 分布式_理论_04_ 3PC
一.前言 五.参考资料 1.分布式理论(四)—— 一致性协议之 3PC 2.分布式理论(四) - 3PC协议 3.
- Solr单机版安装
感谢 shliuzw 的分享,原文地址http://blog.csdn.net/liuzhenwen/article/details/4060922 感谢 upxiaofeng 的分享,原文地址 ht ...
- ios 加密解密(包括base64,DES)非原创
.h文件 #import <Foundation/Foundation.h> /******字符串转base64(包括DES加密)******/ #define __BASE64( tex ...
- Android Studio 开始运行错误
/******************************************************************************** * Android Studio 开 ...
- MySql数据库中存放用户密码需要注意什么?
前几天被电话面试了,问了一些比较实际的问题,其中一个问题关于PHP开发中MySql里存放用户密码需要注意什么,由于没有过大项目经验,一时语塞,回来网上找了找记下来,希望能对其他人有帮助,我也继续学习. ...