前言:
正好在大概7月1日学习一份kendo ui的资料时发现一共5个章节,前3个章节都是用来讲Web API了,既然都已经看了索性就尝试一下,也不做深层次了解了,于是查阅了一些资料尝试写一个基于MVC 4 的WebAPI Demo。
正文:
下文简略介绍服务端的部分实现:
创建一个MVC4 基本项目,也就是不需要自己创建一些基本的注册绑定了。
直接新建一个Controller以及一个Model,如下所示:
UserModel.cs
1 public class UserModel 2 { 3 public string UserID { get; set; } 4 public string UserName { get; set; } 5 public string UserPwd { get; set; } 6 }
UserController
1 public class UserController : ApiController 2 { 3 public UserModel getUser() 4 { 5 return new UserModel { UserID="1000",UserName="Admin",UserPwd="Admin888"}; 6 } 7 }
查看一些App_Start 下WebAPI的路由设置如下:
1 public static void Register(HttpConfiguration config) 2 { 3 config.Routes.MapHttpRoute( 4 name: "DefaultApi", 5 routeTemplate: "api/{controller}/{id}", 6 defaults: new { id = RouteParameter.Optional } 7 ); 8 }
此时,直接访问api/User/getUser
即可得到以下结果:
可以看到结果是一个xml文档。
直接在本页面创建一个index.html页面,使用ajax以json数据形式调用这个api,实现如下:
$(function () { $.ajax({ type: ‘GET‘, url: ‘api/user/getadmin‘, dataType: ‘json‘, success: function (data, textStatus) { alert("用户ID:"+data.UserID + " , 用户名:" + data.UserName+" , 用户密码:"+data.UserPwd); }, error: function (xmlHttpRequest, textStatus, errorThrown) { } }); })
实现效果如下:
这属于在一个项目中调用数据,也就并提不上什么分布式了,另外新建一个webform项目,同样创建一个index.html页面,以同样的方式调用这一api,区别在于需要写上域名和主机头以及协议:
$(function () { $("#btnGet").click(function () { $.ajax({ type: ‘GET‘, url: ‘http://localhost:16564/api/user/getUser‘, dataType: ‘json‘, success: function (data, textStatus) { alert("用户ID:" + data.UserID + " , 用户名:" + data.UserName + " , 用户密码:" + data.UserPwd); }, error: function (xmlHttpRequest, textStatus, errorThrown) { } }); }); })
可以看到单击后并无任何效果。
打开chrome开发人员工具,查看网络请求可以看到,请求的api/user/getUser 状态是cancel,这应该是JS不允许跨域调用的结果,如下图所示:
通过分析以下错误信息:No ‘Access-Control-Allow-Origin‘ header is present on the requested resource. 查看后发现确实如此,OK,解决方案随之产生,直接将dataType 从json 改为JSONP即可。
$("#btnGet").click(function () { $.ajax({ type: ‘GET‘, url: ‘http://localhost:16564/api/user/getUser‘, dataType: ‘JSONP‘, success: function (data, textStatus) { alert("用户ID:" + data.UserID + " , 用户名:" + data.UserName + " , 用户密码:" + data.UserPwd); }, error: function (xmlHttpRequest, textStatus, errorThrown) { } }); });
此时刷新后再次访问仍然无响应,再次查看,结果如下:
得到的返回结果是:{"UserID":"1000","UserName":"Echo","UserPwd":"EchoIsnotLoser"}
如果想用JSONP来获得跨域的数据,需求的格式是
jQuery123456([{‘UserID‘:‘1000‘}])
而WebAPI本身是不支持JS的callback的,它返回的JSON是这样的:
{"UserID":"1000","UserName":"Echo","UserPwd":"EchoIsnotLoser"}
故而无法解析。
找到原因后只需要在WebAPI这个服务端写一个拓展类,并在全局注册即可:
1.创建一个JsonCallbackAttribute 判断接口的访问是属于跨域,还是非跨域,正常的返回。
public class JsonCallbackAttribute : ActionFilterAttribute { private const string CallbackQueryParameter = "callback"; public override void OnActionExecuted(HttpActionExecutedContext context) { var callback = string.Empty; if (IsJsonp(out callback)) { var jsonBuilder = new StringBuilder(callback); jsonBuilder.AppendFormat("({0})", context.Response.Content.ReadAsStringAsync().Result); context.Response.Content = new StringContent(jsonBuilder.ToString()); } base.OnActionExecuted(context); } private bool IsJsonp(out string callback) { callback = System.Web.HttpContext.Current.Request.QueryString[CallbackQueryParameter]; return !string.IsNullOrEmpty(callback); } }
2.在全局注册这个扩张类
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); GlobalConfiguration.Configuration.Filters.Add(new JsonCallbackAttribute()); }
此时 重新编译整个项目,再次运行即可查看到需要的效果,如下图所示:
至此在传统Webform中调用WebAPI的基本操作就实现了。