ASP.NET WebApi使用 (Framework框架)
WebApi:RESTful,http协议 无状态 标准化操作 更轻量级,尤其是json,适合移动端 网站启动时执行Application_Start---给Routes增加地址规则---请求进来时--会经过路由匹配找到合适的《控制器》 其实资源是这样定义的,不是一个学生,而可能是一个学校 版本兼容---约束路由---默认值/可空路由---多数据 IOC容器+配置文件初始化 |
属性路由
默认路由
routes.MapRoute( name: "Default", url: "{controller}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
如果我们要实现类似以下效果路由的话,使用常规公约路由比较麻烦。
order/Miles/三只松鼠干果/2袋 order/2017/1/13
如果使用属性路由的话就比较简单了。
新建WEB API项目的话,打开App_Start目录下的WebApiConfig.cs文件添加以下代码开启属性路由配置。
config.MapHttpAttributeRoutes();
属性路由也可以和公约路由混合使用,如下:
public static void Register(HttpConfiguration config) { // Web API 配置和服务 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional }, constraints: new { id=@"\d+"} ); }
在要使用属性路由的方法上打上特性标记,如下 :
[Route("order/{UserNickName}/{ProductName}/{count}")]
测试结果(URL经过了编码,不然会报400错误。)
通常情况下,在同一个控制器中的所有路由以相同的前缀开头
[Route("api/books")] [Route("api/books/{id:int}")] [Route("api/books")]
这样很明显是比较麻烦的。所以我们用[RoutePrefix]属性来设置一个公共的前缀
如果使用了[RoutePrefix]的话,某些比较特殊的api,我们可以使用波浪线来重写路由前缀,如下:
测试结果(同一个类下)
路由前缀中也可以包含参数,如下
测试结果
可以在路由中添加参数约束,如下
测试结果
如果参数不是Int类型,则不会匹配到该路由
以下都是一些会被支持到的约束
可以使用多个约束,但是要用冒号分开
[Route("users/{id:int:length(1,3)}")] public User GetUserById(int id) { ... }
结果
如果不在范围内的话则匹配不到
自定义路由约束,需要实现IHttpRouteConstraint接口,具体查看官方
作者:三只仓鼠
链接:https://www.jianshu.com/p/4430cbc57a26#
依赖注入&面向切面
安装unity包
依赖注入
使用配置文件来注入依赖关系
<configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/> </configSections> <unity> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/> <containers> <container name="WebApiContainer"> <extension type="Interception"/> <register type="Ruanmou.SOA.Interface.IUserService,Ruanmou.SOA.Interface" mapTo="Ruanmou.SOA.Service.UserService, Ruanmou.SOA.Service"> <!-- <interceptor type="InterfaceInterceptor"/> <interceptionBehavior type="Ruanmou.Framework.AOP.LogBeforeBehavior, Ruanmou.Framework"/> <interceptionBehavior type="Ruanmou.Framework.AOP.LogAfterBehavior, Ruanmou.Framework"/> <interceptionBehavior type="Ruanmou.Framework.AOP.ParameterCheckBehavior, Ruanmou.Framework"/> <lifetime type="transient" />--> </register> </container> </containers> </unity> </configuration>
建一个类,创建unity容器实例
/// <summary> /// 需要在nuget引用之后,单独引用Unity.Configuration /// 如果有AOP扩展,还需要引用Unity.Interception.Configuration /// 因为我们是用配置文件来做的配置 /// </summary> public class ContainerFactory { public static IUnityContainer BuildContainer() { //get //{ return _Container; //} } private static IUnityContainer _Container = null; static ContainerFactory() { ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config");//找配置文件的路径 Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName); _Container = new UnityContainer(); section.Configure(_Container, "WebApiContainer"); } }
建unity容器实例解析类
public class UnityDependencyResolver : IDependencyResolver { private IUnityContainer _UnityContainer = null; public UnityDependencyResolver(IUnityContainer container) { _UnityContainer = container; } public IDependencyScope BeginScope()//Scope { return new UnityDependencyResolver(this._UnityContainer.CreateChildContainer()); } public void Dispose() { this._UnityContainer.Dispose(); } public object GetService(Type serviceType) { try { return ContainerFactory.BuildContainer().Resolve(serviceType); } catch (Exception ex) { Console.WriteLine(ex.Message); return null; } } public IEnumerable<object> GetServices(Type serviceType) { try { return ContainerFactory.BuildContainer().ResolveAll(serviceType); } catch (Exception ex) { Console.WriteLine(ex.Message); return null; } } }
在WebApiConfig中配置unity的解析服务
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服务 config.DependencyResolver = new UnityDependencyResolver(ContainerFactory.BuildContainer()); // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi",//默认的api路由 routeTemplate: "api/{controller}/{id}",//正则规则,以api开头,第二个是控制器 第三个是参数 defaults: new { id = RouteParameter.Optional } ); // config.Routes.MapHttpRoute( // name: "CustomApi",//默认的api路由 // routeTemplate: "api/{controller}/{action}/{id}",//正则规则,以api开头,第二个是控制器 第三个是参数 // defaults: new { id = RouteParameter.Optional } //); } }
Controller中运行,看是否有值
public class IOCController : ApiController { private IUserService _UserService = null; public IOCController(IUserService userService) { this._UserService = userService; } public string Get(int id) { //IUserService service = new UserService(); //IUserService service = ContainerFactory.BuildContainer().Resolve<IUserService>(); return Newtonsoft.Json.JsonConvert.SerializeObject(this._UserService.Query(id)); } }
AOP配置
局部的ActionFilter
public class CustomActionFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { Console.WriteLine("1234567"); } public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { Console.WriteLine("2345678"); actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*"); } }
使用
//GET api/Users/?username=xx&id=1 [HttpGet] [CustomActionFilterAttribute] public IEnumerable<Users> GetUserByNameId(string userName, int id) { string idParam = HttpContext.Current.Request.QueryString["id"]; string userNameParam = HttpContext.Current.Request.QueryString["userName"]; return _userList.Where(p => string.Equals(p.UserName, userName, StringComparison.OrdinalIgnoreCase)); }
全局的ExceptionHandler
/// <summary> /// WEBApi的全局异常处理 /// </summary> public class CustomExceptionHandler : ExceptionHandler { /// <summary> /// 判断是否要进行异常处理,规则自己定 /// </summary> /// <param name="context"></param> /// <returns></returns> public override bool ShouldHandle(ExceptionHandlerContext context) { string url = context.Request.RequestUri.AbsoluteUri; return url.Contains("/api/"); //return base.ShouldHandle(context); } /// <summary> /// 完成异常处理 /// </summary> /// <param name="context"></param> public override void Handle(ExceptionHandlerContext context) { //Console.WriteLine(context);//log context.Result = new ResponseMessageResult(context.Request.CreateResponse( System.Net.HttpStatusCode.OK, new { Result = false, Msg = "出现异常,请联系管理员", Debug = context.Exception.Message })); //if(context.Exception is HttpException) } }
需要在WebApiConfig中替换默认的IExceptionHandler
config.Services.Replace(typeof(IExceptionHandler), new CustomExceptionHandler());//替换全局异常处理类
局部Authorize
public class CustomBasicAuthorizeAttribute : AuthorizeAttribute { /// <summary> /// action前会先来这里完成权限校验 /// </summary> /// <param name="actionContext"></param> public override void OnAuthorization(HttpActionContext actionContext) { //actionContext.Request.Headers["Authorization"] if (actionContext.ActionDescriptor.GetCustomAttributes<CustomAllowAnonymousAttribute>().FirstOrDefault() != null) { return;//继续 } else if (actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<CustomAllowAnonymousAttribute>().FirstOrDefault() != null) { return;//继续 } else { var authorization = actionContext.Request.Headers.Authorization; if (authorization == null) { this.HandlerUnAuthorization(); } else if (this.ValidateTicket(authorization.Parameter)) { return;//继续 } else { this.HandlerUnAuthorization(); } } } private void HandlerUnAuthorization() { throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized); } private bool ValidateTicket(string encryptTicket) { ////解密Ticket //if (string.IsNullOrWhiteSpace(encryptTicket)) // return false; try { var strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData; //FormsAuthentication.Decrypt(encryptTicket). return string.Equals(strTicket, string.Format("{0}&{1}", "Admin", "123456"));//应该分拆后去数据库验证 } catch (Exception ex) { return false; } } }
使用
[HttpGet] [CustomBasicAuthorizeAttribute] [CustomExceptionFilterAttribute] public IEnumerable<Users> GetUserByName(string userName) { //throw new Exception("1234567"); string userNameParam = HttpContext.Current.Request.QueryString["userName"]; return _userList.Where(p => string.Equals(p.UserName, userName, StringComparison.OrdinalIgnoreCase)); }
在WebApiConfig 中添加以下一句,就将局部变成了全局注册
config.Filters.Add(new CustomBasicAuthorizeAttribute());//全局注册
WebApi前台调用详析
代码
<form method="post" action="/api/users/register?id=1"> <div class="row"> <div class="col-md-5"> <h2>Test </h2> <p> 账号:<input type="text" id="txtAccount" name="账号" /> 密码:<input type="text" id="txtPassword" name="密码" /> <input type="button" id="btnLogin" value="登陆" /> </p> id参数:<p><input type="text" id="txtId" name="id" /> </p> <p> <input type="button" id="btnGet1" value="Get1" /> <input type="button" id="btnGet2" value="Get2" /> <input type="button" id="btnGet3" value="Get3" /> <input type="button" id="btnGet4" value="Get4" /> </p> <p> <input type="button" id="btnGet5" value="Get5" /> <input type="button" id="btnGet6" value="Get6" /> <input type="button" id="btnGet7" value="Get7" /> <input type="button" id="btnGet8" value="Get8" /> <input type="button" id="btnGet9" value="Get9" /> </p> <p> <input type="button" id="btnPost1" value="Post1" /> <input type="button" id="btnPost2" value="Post2" /> <input type="button" id="btnPost3" value="Post3" /> <input type="button" id="btnPost4" value="Post4" /> </p> <p> <input type="button" id="btnPost5" value="Post5" /> <input type="button" id="btnPost6" value="Post6" /> </p> @*<p><input type="submit" id="btnPost" /> </p>*@ <p> <input type="button" id="btnPut1" value="Put1" /> <input type="button" id="btnPut2" value="Put2" /> <input type="button" id="btnPut3" value="Put3" /> <input type="button" id="btnPut4" value="Put4" /> <input type="button" id="btnPut5" value="Put5" /> <input type="button" id="btnPut6" value="Put6" /> </p> <p> <input type="button" id="btnGetCors1" value="跨域Get1" /> </p> </div> </div> <script src="~/Scripts/jquery-3.3.1.js"></script> <script> $(function () { var user = { UserID: "11", UserName: "Eleven", UserEmail: "57265177@qq.com" }; var info = "this is muti model"; $("#btnGet1").on("click", function () { //$.ajax({ url: "/api/users", type: "get", data: { "userName": "Superman" }, success: function (data) { alert(data); }, datatype: "json" });//指向接口,参数匹配的,大小写不区分 $.ajax({ //url: "/api/users/GetUserByName?ticket=" + ticket url: "/api/users/GetUserByName", type: "get", data: { "username": "Superman" }, beforeSend: function (XHR) { //发送ajax请求之前向http的head里面加入验证信息 XHR.setRequestHeader('Authorization', 'BasicAuth ' + ticket); }, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnGet2").on("click", function () {//单个参数 $.ajax({ url: "/api/users/GetUserByID", type: "get", data: { "id": $("#txtId").val() }, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnGet3").on("click", function () {//两个参数 $.ajax({ url: "/api/users/GetUserByNameId", type: "get", data: { "userName": "Superman", "id": $("#txtId").val() }, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnGet4").on("click", function () {//无参数 $.ajax({ url: "/api/users/Get", type: "get", data: "", success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnGet5").on("click", function () {//传递实体 json对象 $.ajax({ url: "/api/users/GetUserByModel", type: "get", data: user, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnGet6").on("click", function () {//传递实体 必须FromUri才能找到 $.ajax({ url: "/api/users/GetUserByModelUri", type: "get", data: user, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnGet7").on("click", function () {//传递实体,序列化后传递 $.ajax({ url: "/api/users/GetUserByModelSerialize", type: "get", data: { userString: JSON.stringify(user) }, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnGet8").on("click", function () {//传递实体,序列化后传递 $.ajax({ url: "/api/users/GetUserByModelSerializeWithoutGet", type: "get", data: { userString: JSON.stringify(user) }, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnGet9").on("click", function () {//传递实体,序列化后传递 405 Method Not Allowed 不带httpget需要用get开头 $.ajax({ url: "/api/users/NoGetUserByModelSerializeWithoutGet", type: "get", data: { userString: JSON.stringify(user) }, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnPost1").on("click", function () {//单个值传递,json数据不要key,这样后台才能获取 $.ajax({ url: "/api/users/RegisterNoKey", type: "post", data: { "": $("#txtId").val() }, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnPost2").on("click", function () {//key-value形式后台拿不到这个参数,但是可以直接访问 $.ajax({ url: "/api/users/Register", type: "post", data: { "id": $("#txtId").val() }, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnPost3").on("click", function () {//传递json格式的,后台可以用实体接收 $.ajax({ url: "/api/users/RegisterUser", type: "post", data: user, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnPost4").on("click", function () {//传递json序列化后的格式,后台可以用实体接收,需要指定contentType $.ajax({ url: "/api/users/RegisterUser", type: "post", data: JSON.stringify(user), success: function (data) { alert(data); }, datatype: "json", contentType: 'application/json', }); }); $("#btnPost5").on("click", function () {//JObject接收 $.ajax({ url: "/api/users/RegisterObject", type: "post", data: { "User": user, "Info": info }, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnPost6").on("click", function () {//Dynamic 失败了 要序列化就可以了 $.ajax({ url: "/api/users/RegisterObjectDynamic", type: "post", data: { "User": user, "Info": info }, success: function (data) { alert(data); }, datatype: "json", contentType: 'application/json' }); }); //也可以还是包装成一个对象 $("#btnPut1").on("click", function () {//单个值传递,json数据不要key,这样后台才能获取 $.ajax({ url: "/api/users/RegisterNoKeyPut", type: "put", data: { "": $("#txtId").val() }, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnPut2").on("click", function () {//key-value形式后台拿不到 $.ajax({ url: "/api/users/RegisterPut", type: "put", data: { "id": $("#txtId").val() }, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnPut3").on("click", function () {//传递json格式的,后台可以用实体接收 $.ajax({ url: "/api/users/RegisterUserPut", type: "put", data: user, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnPut4").on("click", function () {//传递json序列化后的格式,后台可以用实体接收,需要指定contentType $.ajax({ url: "/api/users/RegisterUserPut", type: "put", data: JSON.stringify(user), success: function (data) { alert(data); }, datatype: "json", contentType: 'application/json', }); }); $("#btnPut5").on("click", function () {//JObject接收 $.ajax({ url: "/api/users/RegisterObjectPut", type: "put", data: { "User": user, "Info": info }, success: function (data) { alert(data); }, datatype: "json" }); }); $("#btnPut6").on("click", function () {//Dynamic 失败了 $.ajax({ url: "/api/users/RegisterObjectDynamicPut", type: "put", data: { "User": user, "Info": info }, success: function (data) { alert(data); }, datatype: "json", contentType: 'application/json' }); }); //delete一样 type换成delete //如果大家还有别的传递和获取 自动绑定好的方式,欢迎分享 $("#btnLogin").on("click", function () { $.ajax({ url: "/api/users/Login", type: "GET", data: { "Account": $("#txtAccount").val(), "Password": $("#txtPassword").val() }, success: function (data) { var result = JSON.parse(data); if (result.Result) { ticket = result.Ticket; alert(result.Ticket); } else { alert("failed"); } }, datatype: "json" }); }); var ticket = "";//登陆后放在某个html里面,ajax都得带上 //microsoft.aspnet.webapi.cors jQuery.support.cors = true; var location = "http://localhost:8088"; $("#btnGetCors1").on("click", function () { $.ajax({ url: location + "/api/users/GetUserByID", type: "get", data: { "id": 1 }, success: function (data) { alert(data); }, datatype: "json" }); }); }); </script> </form>
效果
Get方式传参
单个参数 :后台能找到
$("#btnGet2").on("click", function () {//单个参数
$.ajax({ url: "/api/users/GetUserByID", type: "get", data: { "id": $("#txtId").val() }, success: function (data) { alert(data); }, datatype: "json" });
});
二个参数 : 后台能找到
$("#btnGet3").on("click", function () {//两个参数
$.ajax({ url: "/api/users/GetUserByNameId", type: "get", data: { "userName": "Superman", "id": $("#txtId").val() }, success: function (data) { alert(data); }, datatype: "json" });
});
无参 :可以
$("#btnGet4").on("click", function () {//无参数
$.ajax({ url: "/api/users/Get", type: "get", data: "", success: function (data) { alert(data); }, datatype: "json" });
});
传递实体 json对象 : 后台user实体不能找到
var user = { UserID: "11", UserName: "Eleven", UserEmail: "57265177@qq.com" };
var info = "this is muti model";
$("#btnGet5").on("click", function () {//传递实体 json对象
$.ajax({ url: "/api/users/GetUserByModel", type: "get", data: user, success: function (data) { alert(data); }, datatype: "json" });
});
传递实体 json对象 ,必须FromUri才能找到
$("#btnGet6").on("click", function () {//传递实体 必须FromUri才能找到
$.ajax({ url: "/api/users/GetUserByModelUri", type: "get", data: user, success: function (data) { alert(data); }, datatype: "json" });
});
传递实体,序列化后传递
$("#btnGet7").on("click", function () {//传递实体,序列化后传递
$.ajax({ url: "/api/users/GetUserByModelSerialize", type: "get", data: { userString: JSON.stringify(user) }, success: function (data) { alert(data); }, datatype: "json" });
});
传递实体,序列化后传递,不带httpget需要用get开头
$("#btnGet8").on("click", function () {//传递实体,序列化后传递
$.ajax({ url: "/api/users/GetUserByModelSerializeWithoutGet", type: "get", data: { userString: JSON.stringify(user) }, success: function (data) { alert(data); }, datatype: "json" });
});
$("#btnGet9").on("click", function () {//传递实体,序列化后传递 405 Method Not Allowed
$.ajax({ url: "/api/users/NoGetUserByModelSerializeWithoutGet", type: "get", data: { userString: JSON.stringify(user) }, success: function (data) { alert(data); }, datatype: "json" });
});
/// 方法名以Get开头,WebApi会自动默认这个请求就是get请求,而如果你以其他名称开头而又不标注方法的请求方式,那么这个时候服务器虽然找到了这个方法,但是由于请求方式不确定,所以直接返回给你405——方法不被允许的错误。
/// 最后结论:所有的WebApi方法最好是加上请求的方式([HttpGet]/[HttpPost]/[HttpPut]/[HttpDelete]),不要偷懒,这样既能防止类似的错误,也有利于方法的维护,别人一看就知道这个方法是什么请求。
Post方式传参
单个值传递,json数据不要key,这样后台才能获取. key-value形式后台拿不到这个参数,但是可以直接访问
$("#btnPost1").on("click", function () {//单个值传递,json数据不要key,这样后台才能获取
$.ajax({ url: "/api/users/RegisterNoKey", type: "post", data: { "": $("#txtId").val() }, success: function (data) { alert(data); }, datatype: "json" });
});
$("#btnPost2").on("click", function () {//key-value形式后台拿不到这个参数,但是可以直接访问
$.ajax({ url: "/api/users/Register", type: "post", data: { "id": $("#txtId").val() }, success: function (data) { alert(data); }, datatype: "json" });
});
传递json格式的,后台可以用实体接收
$("#btnPost3").on("click", function () {//传递json格式的,后台可以用实体接收
$.ajax({ url: "/api/users/RegisterUser", type: "post", data: user, success: function (data) { alert(data); }, datatype: "json" });
});
传递json序列化后的格式,后台可以用实体接收,需要指定contentType
$("#btnPost4").on("click", function () {//传递json序列化后的格式,后台可以用实体接收,需要指定contentType
$.ajax({ url: "/api/users/RegisterUser", type: "post", data: JSON.stringify(user), success: function (data) { alert(data); }, datatype: "json", contentType: 'application/json', });
});
JObject接收
$("#btnPost5").on("click", function () {//JObject接收
$.ajax({ url: "/api/users/RegisterObject", type: "post", data: { "User": user, "Info": info }, success: function (data) { alert(data); }, datatype: "json" });
});
$("#btnPost6").on("click", function () {//Dynamic 失败了 要序列化就可以了
$.ajax({ url: "/api/users/RegisterObjectDynamic", type: "post", data: { "User": user, "Info": info }, success: function (data) { alert(data); }, datatype: "json", contentType: 'application/json' });
});
//也可以还是包装成一个对象
Put方式传参
单个值传递,json数据不要key,这样后台才能获取.key-value形式后台拿不到
$("#btnPut1").on("click", function () {//单个值传递,json数据不要key,这样后台才能获取
$.ajax({ url: "/api/users/RegisterNoKeyPut", type: "put", data: { "": $("#txtId").val() }, success: function (data) { alert(data); }, datatype: "json" });
});
$("#btnPut2").on("click", function () {//key-value形式后台拿不到
$.ajax({ url: "/api/users/RegisterPut", type: "put", data: { "id": $("#txtId").val() }, success: function (data) { alert(data); }, datatype: "json" });
});
传递json格式的,后台可以用实体接收
$("#btnPut3").on("click", function () {//传递json格式的,后台可以用实体接收
$.ajax({ url: "/api/users/RegisterUserPut", type: "put", data: user, success: function (data) { alert(data); }, datatype: "json" });
});
传递json序列化后的格式,后台可以用实体接收,需要指定contentType
$("#btnPut4").on("click", function () {//传递json序列化后的格式,后台可以用实体接收,需要指定contentType
$.ajax({ url: "/api/users/RegisterUserPut", type: "put", data: JSON.stringify(user), success: function (data) { alert(data); }, datatype: "json", contentType: 'application/json', });
});
JObject接收
$("#btnPut5").on("click", function () {//JObject接收
$.ajax({ url: "/api/users/RegisterObjectPut", type: "put", data: { "User": user, "Info": info }, success: function (data) { alert(data); }, datatype: "json" });
});
Dynamic 失败了
$("#btnPut6").on("click", function () {//Dynamic 失败了
$.ajax({ url: "/api/users/RegisterObjectDynamicPut", type: "put", data: { "User": user, "Info": info }, success: function (data) { alert(data); }, datatype: "json", contentType: 'application/json' });
});
Delete方式传参
与上述一样,略过
接口返回类型详解
Webapi的接口返回值主要有四种类型
- void无返回值
- IHttpActionResult
- HttpResponseMessage
-
自定义类型
void无返回值
大家都知道void声明的是一个无返回值的方法,声明一个api控制器方法,例如:
public class ValuesController : ApiController { [HttpGet] public void Get() { int a = 1; int b = 2; int c = a + b; //..................... } }
使用postman,测试接口:
可以看到,void声明的接口,在请求成功的时候得不到返回值,而且会返回http的状态码为204,表示没有返回值。
IHttpActionResult
IHttpActionResult是WebApi最常用的一种返回值类型,常用的方式有:Json(T content)、Ok()、 Ok(T content)、NotFound()、Content(HttpStatusCode statusCode, T value)、BadRequest()、Redirect(string location)等
-
Json(T content)
在WebApi的ApiController这个抽象类里面,为我们封装了Json(T content)这个方法,它的用法和MVC里面的JsonResult基本类似。
[HttpGet] public IHttpActionResult getJson() { var list = new List<userinfo>(); list.Add(new userinfo { Name="jeck",age=22 }); list.Add(new userinfo { Name = "poor", age = 23 }); return Json<List<userinfo>>(list); } private class userinfo{ public string Name { get; set; } public int age { get; set; } }
测试结果:
为什么可以返回 Json(T content)呢,转到Json(T content)的定义,发现它返回的是JsonResult对象
再转到JsonResult的定义,发现它实现了IHttpActionResult接口
当然也可以使用dynamic来返回一个对象
[HttpGet] public IHttpActionResult getJson() { return Json<dynamic>(new { AA = "a", BB = "b" }); }
-
Ok()、 Ok(T content)
如果返回Ok(),就表示不向客户端返回任何信息,只告诉客户端请求成功。
[HttpGet] public IHttpActionResult getJson() { return Ok(); }
Ok(T content)向客户端返回一个成功的对象
[HttpGet] public IHttpActionResult getJson1() { string result = "请求成功!"; return Ok(result); }
-
NotFound()
NotFound()方法会返回一个404的错误到客户端。
[HttpGet] public IHttpActionResult getJson() { return NotFound(); }
-
Content(HttpStatusCode statusCode, T value)
向客户端返回值和http状态码。
[HttpGet] public IHttpActionResult getJson() { return Content<string>(HttpStatusCode.OK, "OK"); }
-
BadRequest()
向客户端返回400的http错误。
[HttpGet] public IHttpActionResult getJson2() { return BadRequest(); }
-
Redirect(string location)
将请求重定向到其他地方。
[HttpGet] public IHttpActionResult getJson3() { return Redirect("http://localhost:7408/api/Values/getJson1"); } [HttpGet] public IHttpActionResult getJson1() { string result = "请求成功!"; return Ok(result); }
HttpResponseMessage
HttpResponseMessage这个对象,表示向客户端返回一个http响应的消息对象(包含http状态码和需要返回客户端的消息)。这个对象也有它独特的使用场景:需要向客户端返回HttpResponse时就要用到这个对象。以导出为例,由于需要将导出的Excel文件输出到客户端浏览器,Webapi的服务端需要向Web的客户端输出文件流,这个时候一般的IHttpActionResult对象不方便解决这个问题,于是HttpReponseMessage派上了用场。
public HttpResponseMessage Export() { //取数据 var lstRes = OrderBLL.Export(); //向Excel里面填充数据 HSSFWorkbook workbook = new HSSFWorkbook(); CreateAndFillSheet(workbook, lstRes); //保存到服务 var fileName = "Excel" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xls"; var strPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Data\" + fileName); using (FileStream fs = new FileStream(strPath, FileMode.Create)) { workbook.Write(fs); using (MemoryStream ms = new MemoryStream()) { workbook.Write(ms); } } //输出到浏览器 try { var stream = new FileStream(strPath, FileMode.Open); HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); response.Content = new StreamContent(stream); response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = fileName }; return response; } catch { return new HttpResponseMessage(HttpStatusCode.NoContent); } }
自定义类型
你也可以将webapi的接口和普通方法一样,返回任意的类型,WebApi会自动序列化你自定义任何返回类型,然后将序列化的值写到响应正文里,状态码统一返回200。
[HttpGet] public object getJson() { var list = new List<userinfo>(); list.Add(new userinfo { Name = "work", age = 11 }); list.Add(new userinfo { Name = "hard", age = 12 }); return list; }
转自:https://www.cnblogs.com/hnsongbiao/p/9375888.html
WebApi后台调用详析
单元测试
在同一解决方案下的单元测试
确认后,为了命名规范把第一个测试类命名成我们要测试的控制器的名称+Test,如图:
其次,需要填加对TestDemo也就是我么你要测试的那个项目的引用。选择引用,添加引用,然后勾选我们要测试的项目。
然后回到HomeControllerTest中,填加测试方法,该测试方法的代码如下:
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using TestDemo.Controllers; namespace WebApi_Test { [TestClass] public class ValueControllerTest { [TestMethod] public void TestMethod1() { var valueController = new ValueController(); var result = valueController.Get(1, 2); Assert.AreEqual(3,result); } } }
如果3和返回的结果相等,那么该测试就会通过,否侧测试不通过,运行单元测试的方法如图,
如果3和返回的结果相等,那么该测试就会通过,否侧测试不通过,运行单元测试的方法如图,
即可查看测试是否通过。
另建一个解决方案,专门进行单元测试(利用HttpClient/HttpWebRequset模拟浏览器请求)
HttpClient实现Get请求
#region HttpClient Get /// <summary> /// HttpClient实现Get请求 /// </summary> private string GetClient() { //string url = "http://localhost:8088/api/users/GetUserByName?username=superman"; //string url = "http://localhost:8088/api/users/GetUserByID?id=1"; //string url = "http://localhost:8088/api/users/GetUserByNameId?userName=Superman&id=1"; //string url = "http://localhost:8088/api/users/Get"; //string url = "http://localhost:8088/api/users/GetUserByModel?UserID=11&UserName=Eleven&UserEmail=57265177%40qq.com"; string url = "http://localhost:8088/api/users/GetUserByModelUri?UserID=11&UserName=Eleven&UserEmail=57265177%40qq.com"; //string url = "http://localhost:8088/api/users/GetUserByModelSerialize?userString=%7B%22UserID%22%3A%2211%22%2C%22UserName%22%3A%22Eleven%22%2C%22UserEmail%22%3A%2257265177%40qq.com%22%7D"; //string url = "http://localhost:8088/api/users/GetUserByModelSerializeWithoutGet?userString=%7B%22UserID%22%3A%2211%22%2C%22UserName%22%3A%22Eleven%22%2C%22UserEmail%22%3A%2257265177%40qq.com%22%7D"; //string url = "http://localhost:8088/api/users/NoGetUserByModelSerializeWithoutGet?userString=%7B%22UserID%22%3A%2211%22%2C%22UserName%22%3A%22Eleven%22%2C%22UserEmail%22%3A%2257265177%40qq.com%22%7D"; var handler = new HttpClientHandler();//{ AutomaticDecompression = DecompressionMethods.GZip }; using (var http = new HttpClient(handler)) { var response = http.GetAsync(url).Result;//拿到异步结果 Console.WriteLine(response.StatusCode); //确保HTTP成功状态值 //await异步读取最后的JSON(注意此时gzip已经被自动解压缩了,因为上面的AutomaticDecompression = DecompressionMethods.GZip) return response.Content.ReadAsStringAsync().Result; } } #endregion
HttpWebRequest实现Get请求
#region HttpWebRequest实现Get请求 /// <summary> /// HttpWebRequest实现Get请求 /// </summary> private string GetWebQuest() { //string url = "http://localhost:8088/api/users/GetUserByName?username=superman"; //string url = "http://localhost:8088/api/users/GetUserByID?id=1"; //string url = "http://localhost:8088/api/users/GetUserByNameId?userName=Superman&id=1"; //string url = "http://localhost:8088/api/users/Get"; //string url = "http://localhost:8088/api/users/GetUserByModel?UserID=11&UserName=Eleven&UserEmail=57265177%40qq.com"; //string url = "http://localhost:8088/api/users/GetUserByModelUri?UserID=11&UserName=Eleven&UserEmail=57265177%40qq.com"; string url = "http://localhost:8088/api/users/GetUserByModelSerialize?userString=%7B%22UserID%22%3A%2211%22%2C%22UserName%22%3A%22Eleven%22%2C%22UserEmail%22%3A%2257265177%40qq.com%22%7D"; //string url = "http://localhost:8088/api/users/GetUserByModelSerializeWithoutGet?userString=%7B%22UserID%22%3A%2211%22%2C%22UserName%22%3A%22Eleven%22%2C%22UserEmail%22%3A%2257265177%40qq.com%22%7D"; //string url = "http://localhost:8088/api/users/NoGetUserByModelSerializeWithoutGet?userString=%7B%22UserID%22%3A%2211%22%2C%22UserName%22%3A%22Eleven%22%2C%22UserEmail%22%3A%2257265177%40qq.com%22%7D"; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Timeout = 30 * 1000; //request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36"; //request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8"; string result = ""; using (var res = request.GetResponse() as HttpWebResponse) { if (res.StatusCode == HttpStatusCode.OK) { StreamReader reader = new StreamReader(res.GetResponseStream(), Encoding.UTF8); result = reader.ReadToEnd(); } } return result; } #endregion
HttpClient实现Post请求
#region HttpClient实现Post请求 /// <summary> /// HttpClient实现Post请求 /// </summary> private string PostClient() { //string url = "http://localhost:8088/api/users/register"; //Dictionary<string, string> dic = new Dictionary<string, string>() //{ // {"","1" } //}; //string url = "http://localhost:8088/api/users/RegisterNoKey"; //Dictionary<string, string> dic = new Dictionary<string, string>() //{ // {"","1" } //}; //string url = "http://localhost:8088/api/users/RegisterUser"; //Dictionary<string, string> dic = new Dictionary<string, string>() //{ // {"UserID","11" }, // {"UserName","Eleven" }, // {"UserEmail","57265177@qq.com" }, //}; string url = "http://localhost:8088/api/users/RegisterObject"; Dictionary<string, string> dic = new Dictionary<string, string>() { {"User[UserID]","11" }, {"User[UserName]","Eleven" }, {"User[UserEmail]","57265177@qq.com" }, {"Info","this is muti model" } }; HttpClientHandler handler = new HttpClientHandler(); using (var http = new HttpClient(handler)) { //使用FormUrlEncodedContent做HttpContent var content = new FormUrlEncodedContent(dic); var response = http.PostAsync(url, content).Result; Console.WriteLine(response.StatusCode); //确保HTTP成功状态值 return response.Content.ReadAsStringAsync().Result; } } #endregion
HttpWebRequest实现post请求
#region HttpWebRequest实现post请求 /// <summary> /// HttpWebRequest实现post请求 /// </summary> private string PostWebQuest() { //string url = "http://localhost:8088/api/users/register"; //var postData = "1"; //string url = "http://localhost:8088/api/users/RegisterNoKey"; //var postData = "1"; var user = new { UserID = "11", UserName = "Eleven", UserEmail = "57265177@qq.com" }; //string url = "http://localhost:8088/api/users/RegisterUser"; //var postData = JsonHelper.ObjectToString(user); var userOther = new { User = user, Info = "this is muti model" }; string url = "http://localhost:8088/api/users/RegisterObject"; var postData = Newtonsoft.Json.JsonConvert.SerializeObject(userOther); var request = HttpWebRequest.Create(url) as HttpWebRequest; request.Timeout = 30 * 1000;//设置30s的超时 request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36"; request.ContentType = "application/json"; request.Method = "POST"; byte[] data = Encoding.UTF8.GetBytes(postData); request.ContentLength = data.Length; Stream postStream = request.GetRequestStream(); postStream.Write(data, 0, data.Length); postStream.Close(); string result = ""; using (var res = request.GetResponse() as HttpWebResponse) { if (res.StatusCode == HttpStatusCode.OK) { StreamReader reader = new StreamReader(res.GetResponseStream(), Encoding.UTF8); result = reader.ReadToEnd(); } } return result; } #endregion
HttpClient实现Put请求
#region HttpClient实现Put请求 /// <summary> /// HttpClient实现Put请求 /// </summary> private string PutClient() { string url = "http://localhost:8088/api/users/RegisterPut"; Dictionary<string, string> dic = new Dictionary<string, string>() { {"","1" } }; //string url = "http://localhost:8088/api/users/RegisterNoKeyPut"; //Dictionary<string, string> dic = new Dictionary<string, string>() //{ // {"","1" } //}; //string url = "http://localhost:8088/api/users/RegisterUserPut"; //Dictionary<string, string> dic = new Dictionary<string, string>() //{ // {"UserID","11" }, // {"UserName","Eleven" }, // {"UserEmail","57265177@qq.com" }, //}; //string url = "http://localhost:8088/api/users/RegisterObjectPut"; //Dictionary<string, string> dic = new Dictionary<string, string>() //{ // {"User[UserID]","11" }, // {"User[UserName]","Eleven" }, // {"User[UserEmail]","57265177@qq.com" }, // {"Info","this is muti model" } //}; HttpClientHandler handler = new HttpClientHandler(); using (var http = new HttpClient(handler)) { //使用FormUrlEncodedContent做HttpContent var content = new FormUrlEncodedContent(dic); var response = http.PutAsync(url, content).Result; Console.WriteLine(response.StatusCode); //确保HTTP成功状态值 return response.Content.ReadAsStringAsync().Result; } } #endregion
HttpWebRequest实现put请求
#region HttpWebRequest实现put请求 /// <summary> /// HttpWebRequest实现put请求 /// </summary> private string PutWebQuest() { //string url = "http://localhost:8088/api/users/registerPut"; //var postData = "1"; //string url = "http://localhost:8088/api/users/RegisterNoKeyPut"; //var postData = "1"; var user = new { UserID = "11", UserName = "Eleven", UserEmail = "57265177@qq.com" }; //string url = "http://localhost:8088/api/users/RegisterUserPut"; //var postData = JsonHelper.ObjectToString(user); var userOther = new { User = user, Info = "this is muti model" }; string url = "http://localhost:8088/api/users/RegisterObjectPut"; var postData = Newtonsoft.Json.JsonConvert.SerializeObject(userOther); var request = HttpWebRequest.Create(url) as HttpWebRequest; request.Timeout = 30 * 1000;//设置30s的超时 request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36"; request.ContentType = "application/json"; request.Method = "PUT"; byte[] data = Encoding.UTF8.GetBytes(postData); request.ContentLength = data.Length; Stream postStream = request.GetRequestStream(); postStream.Write(data, 0, data.Length); postStream.Close(); string result = ""; using (var res = request.GetResponse() as HttpWebResponse) { if (res.StatusCode == HttpStatusCode.OK) { StreamReader reader = new StreamReader(res.GetResponseStream(), Encoding.UTF8); result = reader.ReadToEnd(); } } return result; } #endregion
HttpClient实现Delete请求
#region HttpClient实现Delete请求 /// <summary> /// HttpClient实现Put请求 /// 没放入数据 /// </summary> private string DeleteClient() { string url = "http://localhost:8088/api/users/RegisterDelete/1"; Dictionary<string, string> dic = new Dictionary<string, string>() { {"","1" } }; //string url = "http://localhost:8088/api/users/RegisterNoKeyDelete"; //Dictionary<string, string> dic = new Dictionary<string, string>() //{ // {"","1" } //}; //string url = "http://localhost:8088/api/users/RegisterUserDelete"; //Dictionary<string, string> dic = new Dictionary<string, string>() //{ // {"UserID","11" }, // {"UserName","Eleven" }, // {"UserEmail","57265177@qq.com" }, //}; //string url = "http://localhost:8088/api/users/RegisterObjectDelete"; //Dictionary<string, string> dic = new Dictionary<string, string>() //{ // {"User[UserID]","11" }, // {"User[UserName]","Eleven" }, // {"User[UserEmail]","57265177@qq.com" }, // {"Info","this is muti model" } //}; HttpClientHandler handler = new HttpClientHandler(); using (var http = new HttpClient(handler)) { //使用FormUrlEncodedContent做HttpContent var content = new FormUrlEncodedContent(dic); var response = http.DeleteAsync(url).Result; Console.WriteLine(response.StatusCode); //确保HTTP成功状态值 return response.Content.ReadAsStringAsync().Result; } } #endregion
HttpWebRequest实现Delete请求
#region HttpWebRequest实现Delete请求 /// <summary> /// HttpWebRequest实现put请求 /// </summary> private string DeleteWebQuest() { //string url = "http://localhost:8088/api/users/registerDelete"; //var postData = "1"; //string url = "http://localhost:8088/api/users/RegisterNoKeyDelete"; //var postData = "1"; var user = new { UserID = "11", UserName = "Eleven", UserEmail = "57265177@qq.com" }; //string url = "http://localhost:8088/api/users/RegisterUserDelete"; //var postData = JsonHelper.ObjectToString(user); var userOther = new { User = user, Info = "this is muti model" }; string url = "http://localhost:8088/api/users/RegisterObjectDelete"; var postData = Newtonsoft.Json.JsonConvert.SerializeObject(userOther); var request = HttpWebRequest.Create(url) as HttpWebRequest; request.Timeout = 30 * 1000;//设置30s的超时 request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36"; request.ContentType = "application/json"; request.Method = "Delete"; byte[] data = Encoding.UTF8.GetBytes(postData); request.ContentLength = data.Length; Stream postStream = request.GetRequestStream(); postStream.Write(data, 0, data.Length); postStream.Close(); string result = ""; using (var res = request.GetResponse() as HttpWebResponse) { if (res.StatusCode == HttpStatusCode.OK) { StreamReader reader = new StreamReader(res.GetResponseStream(), Encoding.UTF8); result = reader.ReadToEnd(); } } return result; } #endregion
单元测试调用
/// <summary> /// WebApi全部遵循的Http协议,HttpMethod /// 其实就等同于网页,可以去爬虫 /// 就时后端模拟Http请求 /// /// HttpWebRequest HttpClient /// /// HttpClient /// using (var http = new HttpClient(handler)) 不太好 tcp其实并不能立即释放掉 /// 如果高并发式的这样操作,会出现资源不够 积极拒绝 /// HttpClient内部有个连接池,各个请求是隔开的,可以复用链接的 实际应该单例一下 /// </summary> [TestClass] public class WebapiTest { [TestMethod] public void TestMethod() { //this.AuthorizationDemo(); var result1 = this.GetClient(); var result2 = this.GetWebQuest(); var result3 = this.PostClient(); var result4 = this.PostWebQuest(); var result5 = this.PutClient(); var result6 = this.PutWebQuest(); var result7 = this.DeleteClient();//传值只能是url var result8 = this.DeleteWebQuest(); //Console.WriteLine(); }
权限认证
权限认证:是需要的,http地址,是公开的,所以需要权限认证
session--webapi默认是不支持session--RESTful---可以自行扩展去支持
无状态:第2次请求和第1次请求不关联
1 登陆过程,拿到令牌--token--ticket--许可证
2 验证成功--账号+密码+其他信息+时间--加密一下得到ticket---返回给客户端
3 请求时,ajax里面带上这个ticket(header)
4 接口调用时,就去验证ticket,解密一下,看看信息,看看时间
5 每个方法都验证下ticket?就可以基于filter来实现
后端调用时,授权认证的演示
Basic基础认证
public class UserController : ApiController { /// <summary> /// 用户登录 /// </summary> /// <param name="strUser"></param> /// <param name="strPwd"></param> /// <returns></returns> [HttpGet] public object Login(string strUser, string strPwd) { if (!ValidateUser(strUser, strPwd)) { return new { bRes = false }; } FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(0, strUser, DateTime.Now, DateTime.Now.AddHours(1), true, string.Format("{0}&{1}", strUser, strPwd), FormsAuthentication.FormsCookiePath); //返回登录结果、用户信息、用户验证票据信息 var oUser = new UserInfo { bRes = true, UserName = strUser, Password = strPwd, Ticket = FormsAuthentication.Encrypt(ticket) }; //将身份信息保存在session中,验证当前请求是否是有效请求 HttpContext.Current.Session[strUser] = oUser; return oUser; } //校验用户名密码(正式环境中应该是数据库校验) private bool ValidateUser(string strUser, string strPwd) { if (strUser == "admin" && strPwd == "123456") { return true; } else { return false; } } } public class UserInfo { public bool bRes { get; set; } public string UserName { get; set; } public string Password { get; set; } public string Ticket { get; set; } }
这里有一点需要注意的是,因为WebApi默认是没有开启Session的,所以需要我们作一下配置,手动去启用session。如何开启WebApi里面的Session,请参考:http://www.cnblogs.com/tinya/p/4563641.html
正如上面的原理部分说的,登录如果失败,则直接返回;如果成功,则将生成的票据Ticket带到前端,传到主界面/Home/Index,下面,我们就来看看主界面Home/Index。
public class HomeController : Controller { // GET: Home public ActionResult Index(string UserName, string Ticket) { ViewBag.UserName = UserName; ViewBag.Ticket = Ticket; return View(); } }
<html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <script src="~/Content/jquery-1.9.1.js"></script> <link href="~/Content/bootstrap/css/bootstrap.css" rel="stylesheet" /> <script src="~/Content/bootstrap/js/bootstrap.js"></script> <script src="~/Scripts/Home/Index.js"></script> <script type="text/javascript"> //打开页面的时候保存票据信息 var UserName = '@ViewBag.UserName'; var Ticket = '@ViewBag.Ticket'; </script> </head> <body> <div>当前登录用户:'@ViewBag.UserName'</div> <div id="div_test"> </div> </body> </html>
$(function () { $.ajax({ type: "get", url: "http://localhost:27221/api/Charging/GetAllChargingData", data: {}, beforeSend: function (XHR) { //发送ajax请求之前向http的head里面加入验证信息 XHR.setRequestHeader('Authorization', 'BasicAuth ' + Ticket); }, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } }, error: function (e) { $("#div_test").html("Error"); }, complete: function () { } }); });
这里需要说明的是,我们在发送ajax请求之前,通过 XHR.setRequestHeader('Authorization', 'BasicAuth ' + Ticket); 这一句向请求的报文头里面增加票据信息。就是因为这里加了这一句,所以才有我们下图中的红线部分:
WebApiCORS验证部分(重点)
我们看到,上面的/Home/Index页面里面发送了ajax请求去访问服务的 http://localhost:27221/api/Charging/GetAllChargingData 这个接口,那么我们在WebApi里面怎么去验证这个请求和合法的请求呢?接下来我们重点看看验证的这个过程。
在WebApiCORS项目里面自定义一个类RequestAuthorizeAttribute,去继承我们的AuthorizeAttribute这个类。然后重写OnAuthorization方法,在这个方法里面取到请求头的Ticket信息,然后校验用户名密码是否合理。
/// <summary> /// 自定义此特性用于接口的身份验证 /// </summary> public class RequestAuthorizeAttribute : AuthorizeAttribute { //重写基类的验证方式,加入我们自定义的Ticket验证 public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext) { //从http请求的头里面获取身份验证信息,验证是否是请求发起方的ticket var authorization = actionContext.Request.Headers.Authorization; if ((authorization != null) && (authorization.Parameter != null)) { //解密用户ticket,并校验用户名密码是否匹配 var encryptTicket = authorization.Parameter; if (ValidateTicket(encryptTicket)) { 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 encryptTicket) { //解密Ticket var strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData; //从Ticket里面获取用户名和密码 var index = strTicket.IndexOf("&"); string strUser = strTicket.Substring(0, index); string strPwd = strTicket.Substring(index + 1); if (strUser == "admin" && strPwd == "123456") { return true; } else { return false; } } }
在具体的Api接口增加我们上面自定义类的特性
[RequestAuthorize] public class ChargingController : ApiController { /// <summary> /// 得到所有数据 /// </summary> /// <returns>返回数据</returns> [HttpGet] public string GetAllChargingData() { return "Success"; } /// <summary> /// 得到当前Id的所有数据 /// </summary> /// <param name="id">参数Id</param> /// <returns>返回数据</returns> [HttpGet] public string GetAllChargingData(string id) { return "ChargingData" + id; } }
转自:https://www.cnblogs.com/landeanfen/p/5287064.html
自主调用宿主HttpSelfHost的实现
宿主一词我们不会陌生,它可以看作是一个基础设施,它为一些服务和功能提供最底层的支持,如你的web应用程序可以运行在iis或者apache上,而这两个东西就是web应用程序的宿主,而今天说的自主宿主SelfHost就是说,它可以自己去监听自己的服务,如你可以把一个web应用程序宿主到一个console控制台程序上,或者把一个webApi宿主到一个console或者windowService上,这都是可以的。
一 需要添加一些程序集引用
二 代码实现
class Program { static void Main(string[] args) { try { var config = new HttpSelfHostConfiguration("http://localhost:7077"); config.Routes.MapHttpRoute(name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional }); using (var sever = new HttpSelfHostServer(config)) { sever.OpenAsync().Wait(); Console.WriteLine("服务已经启动了。。。。"); Console.WriteLine("输入任意字符关闭"); Console.Read(); sever.CloseAsync().Wait(); } } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.Read(); } }
三 web api代码
public class TestController : ApiController { public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } public string Get(int id) { return "value Get"; } }
四 测试
跨域问题:Cors
什么是跨域问题
出于安全考虑,浏览器会限制脚本中发起的跨站请求,浏览器要求JavaScript或Cookie只能访问同域下的内容。由于这个原因,我们不同站点之间的数据访问会被拒绝。
Cors解决跨域问题
跨域资源共享( CORS )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。它解决跨域问题的原理是通过向http的请求报文和响应报文里面加入相应的标识告诉浏览器它能访问哪些域名的请求。
解决跨域问题实例
下面就写一个简单是实例来说明如何使用CORS解决跨域
1、建立测试项目
1.1、新建两个ASP.NET Web 应用程序,作为Web站点和WebApi站点:
1.2、配置WebApi站点
在WebApiConfig.cs文件里面配置Web API 路由,指向具体的action
//Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi1", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } );
在控制器中新建一个测试方法,用于返回请求数据:
[Authorize] [RoutePrefix("api/Account")] public class AccountController : ApiController { /// <summary> /// 得到所有数据 /// </summary> /// <returns>返回数据</returns> [HttpGet] public string GetAllData() { return "Success"; } }
启动Web API项目,站点端口号为:8476
1.3、配置Web站点
新建一个index测试页面:
<html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <script src="~/Scripts/jquery-1.10.2.min.js"></script> </head> <body> 测试结果: <div id="div_test"> hello world </div> </body> </html>
public ActionResult Index() { return View(); }
用jquery 的 ajax处理请求:
<script> var ApiUrl = "http://localhost:8476/"; $(function () { $.ajax({ type: "get", dataType:"json", url: ApiUrl + "api/Account/GetAllData", data: {}, success: function (data, status) { if (data == "success") { $("#div_test").html(data); } }, error: function (e) { $("#div_test").html("Error"); }, complete: function () { } }); }); </script>
2、测试
在不做任何处理的情况下,运行Web项目,结果为:
可以看到浏览器拒绝了我们的跨域访问。
3、使用CORS跨域
首先安装CORS,在WebApiCors项目上面使用Nuget搜索“microsoft.aspnet.webapi.cors”,安装第一个
当我们安装这个包之后,现有的packages目录下会添加两个名称分别为“Microsoft.AspNet.Cors.5.2.3”和“Microsoft.AspNet.WebApi.Cors.5.2.3”,针对保存其中的两个程序集(System.Web.Cors.dll和System.Web.Http.Cors.dll)的引用被自动添加到WebApiCors项目中
然后在App_Start文件夹下面的WebApiConfig.cs文件夹配置跨域
public static class WebApiConfig { public static void Register(HttpConfiguration config) { //跨域配置 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi1", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
我们暂定三个“*”号,当然,在项目中使用的时候一般需要指定对哪个域名可以跨域、跨域的操作有哪些等等。这个下面介绍
重新运行:
谷歌
IE7、IE8、IE9
我都已经设置跨域了呀,怎么IE7、8、9还是不行呢?这个时候就有必要说说CORS的浏览器支持问题了。网上到处都能搜到这张图:
可以看到IE8、9只有部分浏览器支持,那么如何解决IE浏览器支持问题呢,其实在调用处指定 jQuery.support.cors = true; 这一句就能解决IE8、9的问题了:
<script> jQuery.support.cors = true; var ApiUrl = "http://localhost:8476/"; $(function () { $.ajax({ type: "get", url: ApiUrl + "api/Account/GetAllData", data: {}, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } }, error: function (e) { $("#div_test").html("Error"); }, complete: function () { } }); }); </script>
4、CORS的具体参数设置。
上文我们用的是:config.EnableCors(new EnableCorsAttribute(““, ““, “*”));,这里的*号表示只要别人知道你的url,任何请求都能返回资源,这是不安全的,所以需要进行访问控制。
配置方法一
在Web.Config配置:
<appSettings> <add key="cors:allowedMethods" value="*"/> <add key="cors:allowedOrigin" value="http://localhost:8610"/> <add key="cors:allowedHeaders" value="*"/> </appSettings>
然后在WebApiConfig.cs文件配置
public static void Register(HttpConfiguration config) { //跨域配置 var allowedMethods = ConfigurationManager.AppSettings["cors:allowedMethods"]; var allowedOrigin = ConfigurationManager.AppSettings["cors:allowedOrigin"]; var allowedHeaders = ConfigurationManager.AppSettings["cors:allowedHeaders"]; var geduCors = new EnableCorsAttribute(allowedOrigin, allowedHeaders, allowedMethods) { SupportsCredentials = true }; config.EnableCors(geduCors); //config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
配置方法二
如果你只想对某一些api做跨域,可以直接在API的类上面使用特性标注即可。
[EnableCors(origins: "http://localhost:8610/", headers: "*", methods: "GET,POST,PUT,DELETE")] public class AccountController : ApiController { /// <summary> /// 得到所有数据 /// </summary> /// <returns>返回数据</returns> [HttpGet] public string GetAllData() { return "Success"; } }
本内容转自:https://www.cnblogs.com/hnsongbiao/p/9375997.html
WEBAPI自动生成帮助文档,如何设置加载多个XML文件
咱们新建webapi项目时,默认会生成HelpPage,里面会有api的详细说明
刷新一下那个Help页面,看看是否有货了..
但默认类只能加载当前项目的xml文件,其他项目中的字段说明就没法显示了,如何解决?往下看
1. 咱们首先新建一个支持加载多xml的类 MultiXmlDocumentationProvider ,
/// <summary>A custom <see cref='IDocumentationProvider'/> that reads the API documentation from a collection of XML documentation files.</summary> public class MultiXmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider { /********* ** Properties *********/ /// <summary>The internal documentation providers for specific files.</summary> private readonly XmlDocumentationProvider[] Providers; /********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name='paths'>The physical paths to the XML documents.</param> public MultiXmlDocumentationProvider(params string[] paths) { this.Providers = paths.Select(p => new XmlDocumentationProvider(p)).ToArray(); } /// <summary>Gets the documentation for a subject.</summary> /// <param name='subject'>The subject to document.</param> public string GetDocumentation(MemberInfo subject) { return this.GetFirstMatch(p => p.GetDocumentation(subject)); } /// <summary>Gets the documentation for a subject.</summary> /// <param name='subject'>The subject to document.</param> public string GetDocumentation(Type subject) { return this.GetFirstMatch(p => p.GetDocumentation(subject)); } /// <summary>Gets the documentation for a subject.</summary> /// <param name='subject'>The subject to document.</param> public string GetDocumentation(HttpControllerDescriptor subject) { return this.GetFirstMatch(p => p.GetDocumentation(subject)); } /// <summary>Gets the documentation for a subject.</summary> /// <param name='subject'>The subject to document.</param> public string GetDocumentation(HttpActionDescriptor subject) { return this.GetFirstMatch(p => p.GetDocumentation(subject)); } /// <summary>Gets the documentation for a subject.</summary> /// <param name='subject'>The subject to document.</param> public string GetDocumentation(HttpParameterDescriptor subject) { return this.GetFirstMatch(p => p.GetDocumentation(subject)); } /// <summary>Gets the documentation for a subject.</summary> /// <param name='subject'>The subject to document.</param> public string GetResponseDocumentation(HttpActionDescriptor subject) { return this.GetFirstMatch(p => p.GetDocumentation(subject)); } /********* ** Private methods *********/ /// <summary>Get the first valid result from the collection of XML documentation providers.</summary> /// <param name='expr'>The method to invoke.</param> private string GetFirstMatch(Func<XmlDocumentationProvider, string> expr) { return this.Providers .Select(expr) .FirstOrDefault(p => !String.IsNullOrWhiteSpace(p)); } }
2.找到HelpPageConfig,vs可以搜索到
在Register方法中添加如下代码
config.SetDocumentationProvider(new MultiXmlDocumentationProvider( HttpContext.Current.Server.MapPath("~/App_Data/ZhongXin.ZXWX.WebApi.xml"), HttpContext.Current.Server.MapPath("~/App_Data/ZhongXin.ZXWX.Model.xml"), HttpContext.Current.Server.MapPath("~/App_Data/ZhongXin.ZXWX.Common.xml") ));
OK,运行起来吧
注意事项:xml文件要看看是否生成了
.网上有说要在HelpPageConfig中注释掉一下代码,试过没注释也没问题
#region *************************默认JSON显示接口*************************************** //config.SetSampleForMediaType( // new TextSample("Binary JSON content. See http://bsonspec.org for details."), // new MediaTypeHeaderValue("application/bson")); #endregion
付费内容,请联系本人QQ:1002453261
本文来自博客园,作者:明志德道,转载请注明原文链接:https://www.cnblogs.com/for-easy-fast/articles/12506325.html