简单创建.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

 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));
}
}

在WebApiConfig中加上:

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

UnityDependencyResolver:

 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 this._UnityContainer.Resolve(serviceType);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
} public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return this._UnityContainer.ResolveAll(serviceType);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
}
}

ContainerFactory:

/// <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");
}
}

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,其实就是

下面是示例代码:

 #region 用户登陆
[CustomAllowAnonymousAttribute]
[HttpGet]
public string Login(string account, string password)
{
if ("Admin".Equals(account) && "".Equals(password))//应该数据库校验
{
FormsAuthenticationTicket ticketObject = new FormsAuthenticationTicket(, account, DateTime.Now, DateTime.Now.AddHours(), true, string.Format("{0}&{1}", account, password), FormsAuthentication.FormsCookiePath);
var result = new
{
Result = true,
Ticket = FormsAuthentication.Encrypt(ticketObject)
};
return JsonConvert.SerializeObject(result);
}
else
{
var result = new { Result = false };
return JsonConvert.SerializeObject(result);
}
}
#endregion public class CustomAllowAnonymousAttribute : Attribute
{
} 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", ""));//应该分拆后去数据库验证
}
catch (Exception ex)
{
return false;
} }
}

异常处理Filter,ExceptionFilterAttribute

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

2、实现OnException方法

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

4、注册到全局

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

 public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
/// <summary>
/// 异常发生后(没有被catch),会进到这里
/// </summary>
/// <param name="actionExecutedContext"></param>
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
//actionExecutedContext.Response. 可以获取很多信息,日志一下
Console.WriteLine(actionExecutedContext.Exception.Message);//日志一下
actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(
System.Net.HttpStatusCode.OK, new
{
Result = false,
Msg = "出现异常,请联系管理员",
//Value=
});//创造一个返回
//base.OnException(actionExecutedContext);
//ExceptionHandler
}
}

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

WebApi全局异常处理

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

 /// <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)
}
} config.Services.Replace(typeof(IExceptionHandler), new CustomExceptionHandler());//替换全局异常处理类

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

 public class CustomActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
Console.WriteLine("");
} public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
Console.WriteLine("");
actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin",
"*");
}
}

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", "*");

public class CustomActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
Console.WriteLine("");
} public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
Console.WriteLine("");
actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
}
}

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

自动生成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. GIT和SVN教程

    各种版本控制工具的简单比较 特性 CVS SVN GIT 并发修改 支持 支持 支持 并发提交 不支持 支持 支持 历史轨迹 不支持更名 支持更名 支持更名 分布式 不支持 不支持 支持 SVN SV ...

  2. 再读faster rcnn,有了深层次的理解

    1. https://www.wengbi.com/thread_88754_1.html (图) 2. https://blog.csdn.net/WZZ18191171661/article/de ...

  3. 跟我学SpringCloud | 第十六篇:微服务利剑之APM平台(二)Pinpoint

    目录 SpringCloud系列教程 | 第十六篇:微服务利剑之APM平台(二)Pinpoint 1. Pinpoint概述 2. Pinpoint主要特性 3. Pinpoint优势 4. Pinp ...

  4. Linux CentOS7 下设置tomcat 开机自启动

    网上有很多教程说是可以设置Tomcat 自启动,但是一一验证了都不行.最后找到一个方法 验证可以: 1.改rc.local   位于/etc/rc.d/文件下的rc.local   vi /etc/r ...

  5. 分清<url-pattern>/</url-pattern>与<url-pattern>/*</url-pattern>的不同

    在写springMVC配置web.xml的时候会碰到下面有时候写/,有的时候又写/: 那么这两者有什么区别呢?我现在进行一些讲解: 1.当配置<url-pattern>/</url- ...

  6. Nacos高可用集群解决方案-Docker版本

    文章主旨 本文目的是配置高可用的Nacos集群 架构图 整体架构为:Nginx + 3 x Nacos +高可用MySQL 高可用MySQL使用主从复制结构的可以参考Docker搭建MySQL主从集群 ...

  7. 转载-Springboot整合ehcache缓存

    转载:https://www.cnblogs.com/xzmiyx/p/9897623.html EhCache是一个比较成熟的Java缓存框架,最早从hibernate发展而来, 是进程中的缓存系统 ...

  8. 【linux】【qt5】【信号槽示例】

    什么叫信号槽: 信号槽是 Qt 框架引以为豪的机制之一.所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal).这种发出是没有目的的, ...

  9. Fiddle用于移动端抓包

    一.什么情况下可以用到 1.调查参考其他移动端网站的抓包,他们传输方式.如微信上京东的智能机器人的包.移动端的请求接口格式.如何实现的效果等. 2.调试本地移动端页面的测试页面效果是否有问题.如:页面 ...

  10. [python]创建文本文件,并读取

    代码如下: # coding=gbk import os fname = raw_input("Please input the file name: ") print if os ...