简单创建.NET Core WebApi:https://www.cnblogs.com/yanbigfeg/p/9197375.html

登陆验证四种方式:https://www.cnblogs.com/zuowj/p/5123943.html

解决跨域的8种方法:https://blog.csdn.net/weixin_39939012/article/details/83822126

WebApi深入学习--特性路由:https://www.cnblogs.com/TiestoRay/p/5755454.html
本文的示例代码是基于.NET Framework下的,.NET WebApi与.NET Core WebApi的区别,个人认为主要是来自框架的不一样。可以参照官网https://docs.microsoft.com/en-us/aspnet/core/migration/webapi?view=aspnetcore-2.2#migrate-models-and-controllers后续介绍到.NET Core的时候再详细做下这两个框架的不同。

在WebApi中,方法名以Get开头,WebApi会自动默认之歌请求是Get请求,而如果你以其他名称开头而又不标注这个方法的请求方式,那么这个时候服务器虽然找到了这个方法,但是由于请求方式不确定,所以直接返回给你405---方法不被允许的错误
最后结论:所有的WebApi方法最好是加上请求的方式[HttpGet]/[HttpPost]/[HttpPut]/[HttpDelete],不要偷懒,这样既能防止类似的错误,也有利于方法的维护,被人一看就知道这个方法是什么请求

网站在启动时执行Application_Start(),给Route增加地址规则,请求进来时,会经过路由匹配找到合适的控制器。

那怎么找Action?

  1、根据HttpMethod找方法---用的方法名字开头,Get就是对应的Get请求

  2、如果名字不是Get开头,可以加上[HttpGet]

  3、按照参数找最吻合

其实资源是这样定义的,不是一个学生,而可能是一个学校。可能是一个订单----多件商品,一次查询,订单-商品,数据之间嵌套关系很复杂。还有个特性路由,可以单独定制(config.MapHttpAttributeRoutes()、标机特性)

 IOC容器+配置文件初始化

控制器也要注入--完成容器和WebApi框架融合--实现IDependencyResolver,将容器放进去--初始化

config.DependencyResolver 换成自定义的Resolver

  1. public class IOCController : ApiController
  2. {
  3. private IUserService _UserService = null;
  4. public IOCController(IUserService userService)
  5. {
  6. this._UserService = userService;
  7. }
  8.  
  9. public string Get(int id)
  10. {
  11. //IUserService service = new UserService();
  12. //IUserService service = ContainerFactory.BuildContainer().Resolve<IUserService>();
  13. return Newtonsoft.Json.JsonConvert.SerializeObject(this._UserService.Query(id));
  14. }
  15. }

在WebApiConfig中加上:

  1. // Web API 配置和服务
  2. config.DependencyResolver = new UnityDependencyResolver(ContainerFactory.BuildContainer());

UnityDependencyResolver:

  1. public class UnityDependencyResolver : IDependencyResolver
  2. {
  3. private IUnityContainer _UnityContainer = null;
  4. public UnityDependencyResolver(IUnityContainer container)
  5. {
  6. _UnityContainer = container;
  7. }
  8.  
  9. public IDependencyScope BeginScope()//Scope
  10. {
  11. return new UnityDependencyResolver(this._UnityContainer.CreateChildContainer());
  12. }
  13.  
  14. public void Dispose()
  15. {
  16. this._UnityContainer.Dispose();
  17. }
  18.  
  19. public object GetService(Type serviceType)
  20. {
  21. try
  22. {
  23. return this._UnityContainer.Resolve(serviceType);
  24. }
  25. catch (Exception ex)
  26. {
  27. Console.WriteLine(ex.Message);
  28. return null;
  29. }
  30. }
  31.  
  32. public IEnumerable<object> GetServices(Type serviceType)
  33. {
  34. try
  35. {
  36. return this._UnityContainer.ResolveAll(serviceType);
  37. }
  38. catch (Exception ex)
  39. {
  40. Console.WriteLine(ex.Message);
  41. return null;
  42. }
  43. }
  44. }

ContainerFactory:

  1. /// <summary>
  2. /// 需要在nuget引用之后,单独引用Unity.Configuration
  3. /// 如果有AOP扩展,还需要引用Unity.Interception.Configuration
  4. /// 因为我们是用配置文件来做的配置
  5. /// </summary>
  6. public class ContainerFactory
  7. {
  8. public static IUnityContainer BuildContainer()
  9. {
  10. //get
  11. //{
  12. return _Container;
  13. //}
  14. }
  15.  
  16. private static IUnityContainer _Container = null;
  17. static ContainerFactory()
  18. {
  19. ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
  20. fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config");//找配置文件的路径
  21. Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
  22. UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
  23. _Container = new UnityContainer();
  24. section.Configure(_Container, "WebApiContainer");
  25. }
  26. }

Basic授权认证&权限Filter

  在Basic授权认证,(.NET Core下面用OAuth2,后续的随笔会记载到OAuth2),两者的区别可以参考博客https://blog.csdn.net/qq_15028299/article/details/89028774

权限认证,是需要的,因为是Http地址,如果不加权限认证,别人不就可以直接拿到这边的请求去进行操作了,然后再去猜测别的WebApi。

Session不可以吗?WebApi默认是不支持的Session的,因为RESTFul风格,因为是状态的。

无状态:第二次请求和第一次请求不联系,没关系。

步骤:

  1、登录过程,是为了拿到令牌,tooken/ticket/许可证

  2、验证成功,把账号+密码+其他信息+时间,加密一下,得到ticket,返回给客户端

  3、请求时,Ajax里面就带上这个tooken/ticket(在header里面验证)

  4、接口调用时,就去验证下ticket,解密一下,看看信息,看看时间

  5、每个方法都验证下ticket?不是这样的,可以基于filter来实现,FormAuthenticationTicket

用户登录返回的结果中会是这个样子的。

这边用到了AuthorizeAttribute,现在我们自定义个类CustomBasicAuthorizeAttribute继承自AuthorizeAttribute。

1、方法注册,标机在action上

2、控制器生效,方法全部生效,标机在Controller上

3、全局注册:

在WebApiConfig里面加上

问题来了,现在不能每一个action都标机吧,就要用到控制器或者全局的。那么登录的时候也要验证token,每次都登录,就是登录不上去,然后循环下去。。。

有一个特性AllowAnonymous,我们可以自己写一个CustomAllowAnonymousAttribute,其实就是

下面是示例代码:

  1. #region 用户登陆
  2. [CustomAllowAnonymousAttribute]
  3. [HttpGet]
  4. public string Login(string account, string password)
  5. {
  6. if ("Admin".Equals(account) && "".Equals(password))//应该数据库校验
  7. {
  8. FormsAuthenticationTicket ticketObject = new FormsAuthenticationTicket(, account, DateTime.Now, DateTime.Now.AddHours(), true, string.Format("{0}&{1}", account, password), FormsAuthentication.FormsCookiePath);
  9. var result = new
  10. {
  11. Result = true,
  12. Ticket = FormsAuthentication.Encrypt(ticketObject)
  13. };
  14. return JsonConvert.SerializeObject(result);
  15. }
  16. else
  17. {
  18. var result = new { Result = false };
  19. return JsonConvert.SerializeObject(result);
  20. }
  21. }
  22. #endregion
  23.  
  24. public class CustomAllowAnonymousAttribute : Attribute
  25. {
  26. }
  27.  
  28. public class CustomBasicAuthorizeAttribute : AuthorizeAttribute
  29. {
  30. /// <summary>
  31. /// action前会先来这里完成权限校验
  32. /// </summary>
  33. /// <param name="actionContext"></param>
  34. public override void OnAuthorization(HttpActionContext actionContext)
  35. {
  36. //actionContext.Request.Headers["Authorization"]
  37. if (actionContext.ActionDescriptor.GetCustomAttributes<CustomAllowAnonymousAttribute>().FirstOrDefault() != null)
  38. {
  39. return;//继续
  40. }
  41. else if (actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<CustomAllowAnonymousAttribute>().FirstOrDefault() != null)
  42. {
  43. return;//继续
  44. }
  45. else
  46. {
  47. var authorization = actionContext.Request.Headers.Authorization;
  48. if (authorization == null)
  49. {
  50. this.HandlerUnAuthorization();
  51. }
  52. else if (this.ValidateTicket(authorization.Parameter))
  53. {
  54. return;//继续
  55. }
  56. else
  57. {
  58. this.HandlerUnAuthorization();
  59. }
  60. }
  61. }
  62.  
  63. private void HandlerUnAuthorization()
  64. {
  65. throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized);
  66. }
  67. private bool ValidateTicket(string encryptTicket)
  68. {
  69. ////解密Ticket
  70. //if (string.IsNullOrWhiteSpace(encryptTicket))
  71. // return false;
  72. try
  73. {
  74. var strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData;
  75. //FormsAuthentication.Decrypt(encryptTicket).
  76. return string.Equals(strTicket, string.Format("{0}&{1}", "Admin", ""));//应该分拆后去数据库验证
  77. }
  78. catch (Exception ex)
  79. {
  80. return false;
  81. }
  82.  
  83. }
  84. }

异常处理Filter,ExceptionFilterAttribute

1、自己定义一个类,继承自ExceptionFilterAttribute

2、实现OnException方法

3、标机到需要的控制钱Action

4、注册到全局

5、Filter的范围仅仅局限在Action里面

  1. public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
  2. {
  3. /// <summary>
  4. /// 异常发生后(没有被catch),会进到这里
  5. /// </summary>
  6. /// <param name="actionExecutedContext"></param>
  7. public override void OnException(HttpActionExecutedContext actionExecutedContext)
  8. {
  9. //actionExecutedContext.Response. 可以获取很多信息,日志一下
  10. Console.WriteLine(actionExecutedContext.Exception.Message);//日志一下
  11. actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(
  12. System.Net.HttpStatusCode.OK, new
  13. {
  14. Result = false,
  15. Msg = "出现异常,请联系管理员",
  16. //Value=
  17. });//创造一个返回
  18. //base.OnException(actionExecutedContext);
  19. //ExceptionHandler
  20. }
  21. }

自定义的异常类,要在全局中进行注册:config.Filters.Add(new CustomExceptionFilterAttribute());

WebApi全局异常处理

自定义一个类,继承自ExceptionHandler,重写Handle,初始化项目时,服务替换上。

  1. /// <summary>
  2. /// WEBApi的全局异常处理
  3. /// </summary>
  4. public class CustomExceptionHandler : ExceptionHandler
  5. {
  6. /// <summary>
  7. /// 判断是否要进行异常处理,规则自己定
  8. /// </summary>
  9. /// <param name="context"></param>
  10. /// <returns></returns>
  11. public override bool ShouldHandle(ExceptionHandlerContext context)
  12. {
  13. string url = context.Request.RequestUri.AbsoluteUri;
  14. return url.Contains("/api/");
  15.  
  16. //return base.ShouldHandle(context);
  17. }
  18. /// <summary>
  19. /// 完成异常处理
  20. /// </summary>
  21. /// <param name="context"></param>
  22. public override void Handle(ExceptionHandlerContext context)
  23. {
  24. //Console.WriteLine(context);//log
  25. context.Result = new ResponseMessageResult(context.Request.CreateResponse(
  26. System.Net.HttpStatusCode.OK, new
  27. {
  28. Result = false,
  29. Msg = "出现异常,请联系管理员",
  30. Debug = context.Exception.Message
  31. }));
  32.  
  33. //if(context.Exception is HttpException)
  34. }
  35. }
  36.  
  37. config.Services.Replace(typeof(IExceptionHandler), new CustomExceptionHandler());//替换全局异常处理类

ActionFilter,可以在Action前/后增加逻辑

  1. public class CustomActionFilterAttribute : ActionFilterAttribute
  2. {
  3. public override void OnActionExecuting(HttpActionContext actionContext)
  4. {
  5. Console.WriteLine("");
  6. }
  7.  
  8. public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
  9. {
  10. Console.WriteLine("");
  11. actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin",
  12. "*");
  13. }
  14. }

WebApi跨域请求

  这里对WebApi跨域请求做下简单介绍。什么是跨域请求呢?就是浏览器请求时,如果A网站(域名+端口)页面里面,通过XMLHTTPRequest去请求B域名,这个就是跨域。这个请求时是跨域正常到达B服务器后端的,正常的响应(200)。但是浏览器是不允许这样操作的,除非在相应里面有声明(Access-Control-Allow-Origin)。

  这个是因为浏览器同源策略。出于安全考虑,浏览器限制脚本去发起蛞蝓请求。比如你想攻击别人的网站,得自己服务器发起请求,如果你搞个js,等于在客户端的电脑上去攻击别人。但是页面是script-src、img-href、jss/css/图片,这些是浏览器自己发起的,是可以跨域的。还有a标签,iframe标签也是可以的。浏览器自己的可以,但是用XHR去请求就是不行。

解决跨域的方法

  1、Jsonp:脚本标签自动请求,请求回来的内容执行回调方法,解析数据

  2、CORS,跨域资源共享。允许服务器在响应时,指定Access-Control-Allow-Origin,浏览器按照响应来操作

  nuget下面添加cors

全局的都允许:

Action级别的:

自定义一个一个标签,继承ActionFilter Attribute,执行完城后,加上actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");

  1. public class CustomActionFilterAttribute : ActionFilterAttribute
  2. {
  3. public override void OnActionExecuting(HttpActionContext actionContext)
  4. {
  5. Console.WriteLine("");
  6. }
  7.  
  8. public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
  9. {
  10. Console.WriteLine("");
  11. actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
  12. }
  13. }

因为跨域是浏览器控制的,在后端并没有跨域。

自动生成WebApi文档(.NET Core下面基于Swagger生成文档)

可以在浏览器中直接访问。

 WebApi深坑系列

1、RESTFul  Action共存

  在get情况下,相同路由的Action无法共存,运行报错会匹配到多个Action

  在post情况下,相同路由的Action可以共存,会存在优先级,但是只会执行一个正则匹配到的Action

2、RESTFul相同路由的Action如何并存,并访问指定的Action

  [Route("list"),HttpPost]

  路由如下 api/{controller}/list

3、RESTFul如何设置多参数

  [Route("list"),HttpPost("{a}/{b}/{c}")]

  路由如下 api/{controller}/list/1/2/3

4、Post提交多参数,[FromBody]跨域问题

  去注册中间件,让WebApi支持跨域

5、Post提交多参数,[FromBody]ajax提交类型错误

  必须设置:contentType:'application/json;charset=utf-8'

  参数必须格式化成json字符串:data:Json.stringify(data)

6、关于[FormBody]表示的参数不能设置基础类型,如string.....

  错误书法,跨域设置成string类型

7、为什么Post提交参数必须要标识[FromBody]

  [FromBody]标识该参数值应该从请求的Body中获取,而不是从URL中获取,URL有长度限制,在不超多长度限制的情况下,可以随意。

WebApi简介的更多相关文章

  1. webapi简介及参数绑定

    介绍:WebAPI用来开发系统间接口的技术,基于HTTP协议,返回默认是json格式.比wcf简单 更通用,更轻量级,更省流量(json格式):WebAPI尽可能复用MVC路由.ModelBinder ...

  2. Asp.Net WebAPI的简介及创建

    一.WebAPI简介 ASP.NET Web API 是一种框架,用于轻松构建可以由多种客户端(包括浏览器和移动设备)访问的 HTTP 服务.ASP.NET Web API 是一种用于在 .NET F ...

  3. Asp.Net WebApi学习教程之增删改查

    webapi简介 在asp.net中,创建一个HTTP服务,有很多方案,以前用ashx,一般处理程序(HttpHandler),现在可以用webapi 微软的web api是在vs2012上的mvc4 ...

  4. 初探webapi

    在网上看了小牛之路的webapi那篇文章,所以自己也想偿试一下 一,webapi简介 目前使用Web服务的三种主流的方式是:远程过程调用(RPC),面向服务架构(SOA)以及表征性状态转移(REST) ...

  5. 第九节:JWT简介和以JS+WebApi为例基于JWT的安全校验

    一. 简介 1. 背景 传统的基于Session的校验存在诸多问题,比如:Session过期.服务器开销过大.不能分布式部署.不适合前后端分离的项目. 传统的基于Token的校验需要存储Key-Val ...

  6. C#设计模式总结 C#设计模式(22)——访问者模式(Vistor Pattern) C#设计模式总结 .NET Core launch.json 简介 利用Bootstrap Paginator插件和knockout.js完成分页功能 图片在线裁剪和图片上传总结 循序渐进学.Net Core Web Api开发系列【2】:利用Swagger调试WebApi

    C#设计模式总结 一. 设计原则 使用设计模式的根本原因是适应变化,提高代码复用率,使软件更具有可维护性和可扩展性.并且,在进行设计的时候,也需要遵循以下几个原则:单一职责原则.开放封闭原则.里氏代替 ...

  7. Webservice WCF WebApi 前端数据可视化 前端数据可视化 C# asp.net PhoneGap html5 C# Where 网站分布式开发简介 EntityFramework Core依赖注入上下文方式不同造成内存泄漏了解一下? SQL Server之深入理解STUFF 你必须知道的EntityFramework 6.x和EntityFramework Cor

    Webservice WCF WebApi   注明:改编加组合 在.net平台下,有大量的技术让你创建一个HTTP服务,像Web Service,WCF,现在又出了Web API.在.net平台下, ...

  8. ASP.NET Core 3.0 WebApi中使用Swagger生成API文档简介

    参考地址,官网:https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/getting-started-with-swashbuckle?view ...

  9. 解读ASP.NET 5 & MVC6系列(1):ASP.NET 5简介

    ASP.NET 5简介 ASP.NET 5是一个跨时代的改写,所有的功能和模块都进行了独立拆分,做到了彻底解耦.为了这些改写,微软也是蛮 拼的,几乎把.NET Framwrok全部改写了一遍,形成了一 ...

随机推荐

  1. 《Java 8 in Action》Chapter 7:并行数据处理与性能

    在Java 7之前,并行处理数据集合非常麻烦.第一,你得明确地把包含数据的数据结构分成若干子部分.第二,你要给每个子部分分配一个独立的线程.第三,你需要在恰当的时候对它们进行同步来避免不希望出现的竞争 ...

  2. gradle引jar包,引工程

    gradle引jar包有直接引mvn仓库的,也有引本地的,引本地jar包需要: compile files("xxxxxx.jar")

  3. unicode的编码与解码

  4. Codeforces Round #480 (Div. 2) B. Marlin

    题目地址:http://codeforces.com/contest/980/problem/B 官方题解: 题意: 有一个城市有4行n列,n是奇数,有一个村庄在(1,1),村民在(4,n)钓鱼:还有 ...

  5. hdu 5902 GCD is Funny

    Problem Description Alex has invented a new game for fun. There are n integers at a board and he per ...

  6. Symmetric Matrix 牛客网暑期ACM多校训练营(第一场) B dp 组合数学

    Count the number of n x n matrices A satisfying the following condition modulo m. * Ai, j ∈ {0, 1, 2 ...

  7. 利用PIL库创建空白图像

    背景 最近,想自己生成带位置坐标的文字数据集来训练文本位置探测网络. 理想情况是,给文字加盐噪声,背景不需要加噪声,所以需要创建一个空白的背景.将文字放在空白背景上,然后利用opencv加噪声. 解决 ...

  8. 【Offer】[6] 【从尾到头打印链表】

    题目描述 思路分析 Java代码 代码链接 题目描述 从尾到头打印链表,将其添加到ArrayList当中输出 思路分析 递归的思路 利用栈 Java代码 public class Offer006 { ...

  9. 题解 洛谷P1071【潜伏者】

    题目链接:https://www.luogu.org/problem/P1071 题意概括:给你一段原来截获的英文密码和与之对应的明文,如果密码表非F♂A法,输出"Failed"  ...

  10. 如何设置FreePBX的数据库用户可以通过远程来连接Mysql数据库?

    要满足mysql允许通过除了本机外的主机进行使用客户端连接的方法: 要设置root用户允许通过外网用户进行连接访问的操作方法: 1.首先先改mysql的配置文件 将绑定的#bind-address = ...