一、基于RESTful标准的Web Api
原文讲解:https://www.cnblogs.com/lori/p/3555737.html
微软的web api是在vs2012上的mvc4项目绑定发行的,它提出的web api是完全基于RESTful标准的,完全不同于之前的(同是SOAP协议的)wcf和webService,它是简单,代码可读性强的,上手快的,如果要拿它和web服务相比,我会说,它的接口更标准,更清晰,没有混乱的方法名称,有的只有几种标准的请求,如get,post,put,delete等,它们分别对应的几个操作,下面讲一下:
GET:生到数据列表(默认),或者得到一条实体数据
POST:添加服务端添加一条记录,记录实体为Form对象
PUT:添加或修改服务端的一条记录,记录实体的Form对象,记录主键以GET方式进行传输
DELETE:删除 服务端的一条记录
自带的示例
public class ValuesController : ApiController { // GET api/values public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // GET api/values/5 public string Get(int id) { return "value"; } // POST api/values public void Post([FromBody]string value) { } // PUT api/values/5 public void Put(int id, [FromBody]string value) { } // DELETE api/values/5 public void Delete(int id) { } }
二、自定义的Web Api
自定义这里并没有多高明,说白了就是习惯了mvc的写法,不想用奇葩的restfull api
修改WebApiConfig即可实现
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服务 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); config.Filters.Add(new ValidataModelAttribute()); config.Filters.Add(new WebApiExceptionFilterAttribute()); // config.Filters.Add(new AuthFilterAttribute());//由于用java httpclient请求无法识别session,故而没使用了 config.Formatters.Remove(config.Formatters.XmlFormatter); } }
WebApi没有session的,可在Global.asax开启session
public class WebApiApplication : System.Web.HttpApplication { //省略.... protected void Application_PostAuthorizeRequest() { if (isWebAPiRequest()) { HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required); } } private bool isWebAPiRequest() { return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith("~/api"); } }
三、使用模型验证
直接将步骤了,呵呵
1. 定义特性过滤:ValidataModelAttribute
响应结果:返回状态200,和错误结果提示,而不是400等其他状态,那样返回格式不一致,状态也不对
public class ValidataModelAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { if (!actionContext.ModelState.IsValid) { string error = string.Empty; foreach (var key in actionContext.ModelState.Keys) { var state = actionContext.ModelState[key]; if (state.Errors.Any()) { error = state.Errors.First().ErrorMessage; break; } } var result = new ErrorResult(error); actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, result); //actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState); } } }
2.定义模型类
可参看:https://www.cnblogs.com/kexxxfeng/p/5602656.html
public class PageModel : BaseModel { [Required(ErrorMessage = "当前页不能为空")] [Range(1, 9999,ErrorMessage = "当前页必须大于0")] public int Page { get; set; } }
3.使用特性
这样就能自动验证了
[ValidataModel] [HttpGet] public IHttpActionResult GetPage([FromUri]PageModel model) { var dataGrid = xxx; return JsonDataResult(dataGrid); }
这里顺便讲下使用dynamic的问题,遇到 dynamic类型报错:“object”不包含“xxx”的定义
按网上的说法没法解决:https://www.cnblogs.com/similar/p/6716320.html
四、异常拦截
直接上代码
日志组件自己去搞定哈,WebApiConfig里面的配置注意配对
Application_Start下增加过滤: GlobalConfiguration.Configuration.Filters.Add(new WebApiExceptionFilterAttribute()); 这个不确定是否真的需要
public class WebApiExceptionFilterAttribute : ExceptionFilterAttribute { //重写基类的异常处理方法 public override void OnException(HttpActionExecutedContext actionExecutedContext) { //1.异常日志记录(正式项目里面一般是用log4net记录异常日志) var msg = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "——" + actionExecutedContext.Exception.GetType().ToString() + ":" + actionExecutedContext.Exception.Message + "——堆栈信息:" + actionExecutedContext.Exception.StackTrace; LogHelper.Fatal(msg); //2.返回调用方具体的异常信息 if (actionExecutedContext.Exception is NotImplementedException) { actionExecutedContext.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented); } else if (actionExecutedContext.Exception is TimeoutException) { actionExecutedContext.Response = new HttpResponseMessage(HttpStatusCode.RequestTimeout); } //.....这里可以根据项目需要返回到客户端特定的状态码。如果找不到相应的异常,统一返回服务端错误500 else { actionExecutedContext.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError); } base.OnException(actionExecutedContext); } }
五、TOKEN机制
这部分没做成功,这里只是记录下
其实,使用postman可以,客户端是别人做的,使用的是java httpclient,请求后,后台得不到当前用户session
public class AuthFilterAttribute : AuthorizeAttribute { public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext) { //取出区域的控制器controller,Action string controller = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName; string action = actionContext.ActionDescriptor.ActionName; if (controller.ToLower() == "account" && action.ToLower() == "login") { base.OnAuthorization(actionContext); } else { var content = actionContext.Request.Properties["MS_HttpContext"] as HttpContextBase; var token = content.Request.QueryString["Token"]; if (!string.IsNullOrEmpty(token)) { //URL路径 string filePath = HttpContext.Current.Request.FilePath; //校验用户名密码是否匹配 if (ValidateTicket(token) && ValiddatePermission(token, controller, action, filePath)) { base.IsAuthorized(actionContext); } else { HandleUnauthorizedRequest(actionContext); } } //如果取不到身份验证信息,并且不允许匿名访问,则返回未验证401 else { var attributes = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>(); bool isAnonymous = attributes.Any(a => a is AllowAnonymousAttribute); if (isAnonymous) { base.OnAuthorization(actionContext); } else { HandleUnauthorizedRequest(actionContext); } } } } private bool ValidateTicket(string encryptToken) { if (UserProvider.CurrentUser != null && UserProvider.CurrentUser.LoginToken == encryptToken) { return true; } return false; } public bool ValiddatePermission(string token, string controller, string action, string filePath) { //bool isPass = false; //TODO 权限验证 return true; } }
另外,推荐几篇相关的文章
WebApi系列~StringContent参数需要添加MetaType对象
WebApi系列~通过HttpClient来调用Web Api接口
WebApi系列~通过HttpClient来调用Web Api接口~续~实体参数的传递
六、使用request form
示例:https://www.cnblogs.com/FlowerThree/articles/10275476.html
var token = HttpContext.Current.Request.Headers["token"]; var uid = HttpContext.Current.Request.Form["uid"]; var aa = HttpContext.Current.Request.Form["list[aa]"];