ASP.NET Web API 之一 入門篇
一、基於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]stringvalue) { } // 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機制
這部分沒做成功,這裏只是記錄下
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的性能隱患
WebApi系列~通過HttpClient來調用Web Api接口
WebApi系列~通過HttpClient來調用Web Api接口~續~實體參數的傳遞
WebApi系列~在WebApi中實現Cors訪問
ASP.NET Web API 之一 入門篇