重温ASP.NET WebAPI(二)进阶

介绍

本文为个人对WebApi的回顾无参考价值。

本文内容:

  1. Rest和UnitOfWork
  2. 创建WebAPi的流程
  3. IOC-Unity的使用
  4. MEF
  5. 自定义URL
  6. Base认证和Token自定义权限
  7. 日志NLog
  8. OData的使用
  9. Owin自宿主的使用

代码地址:https://github.com/OtherRuan/Review-Serials

WebApi的几点特性

WebApi 提供了几点特性:

1. 自动匹配HTTP方法

GetMethod(), 惯例上会直接匹配Get的http方法。

Web Api允许方法同时拥有多种type,比如:

[AcceptVerbs(“Delete”,”Get”)]

Public HttpResponseMessage MultiMethod();

MultiMethod可以同时为Delete、Get两种类型的http请求使用

2. Web Api还提供自定义Route的功能,比如定义自己的参数,如下

[Route(“data/{param1}/{param2}”)]

Public object GetData(string param1, string param2){}

请求地址:http://localhost/data/1/2

Route属性有以下5种,用于帮你重定义你的API路由

a)      ActionName: 定义你自己的路由的Action名称

b)      Http Method(httpGet,HttpPost,AcceptVerbs…):  定义你的HTTP方法类型和版本等相关信息

c)       NonAction: 预防当前的Action没有被调用

d)      Route: 自定义路由,可设置参数

e)      RoutePrefix:在controller上定义前缀,Controller下的所有Action路由都会自动带上此前缀

3. HttpClient, HttpRequestMessage, HttpResponseMessage

Https下的Web Api

Https/SSL  是管理计算机互联网消息资源传输安全的协议。先介绍一下两者

Certificate :也就是电子证书,是一种电子签名,它通过绑定公钥来确认用户、设备、服务,以及对应的私钥

Certificate Authority(CA):主要用途是指定哪些URL是可信任的URL

Repository和Unit of Work

Repository模式好处:

  1. 集中了数据和web服务访问逻辑
  2. 支持单元测试
  3. 提供了灵活架构以适应整个应用设计的扩展

Unit of Work的职责:

  1. 管理事务
  2. 有序化数据的插入、删除、更新操作
  3. 预防重复的更新。

使用Unit of Work模式的好处是能够让你更关注于业务逻辑。

创建WebAPI项目流程

  1. 创建DAL
  2. 创建Repository和Unit of Work
  3. 创建Entities
  4. 创建Services
  5. 创建WebAPI
  6. 创建IOC
  7. 使用MEF解耦依赖注册关系
  8. 自定义路由
  9. 创建Exception处理和日志功能
  10. 创建单元测试

Questions:

  1. Context.Entry(entity).State = EntityState.Modified;
  2. IQueryable
  3. UnitOfWork继承IDisposable

Cause:他需要释放链接

  1. DbEntityValidationException e.EntityValidationErrors
  2. GC.SuppressFinalize

IOC – Unity

Unity 是轻量级、可扩展的依赖注入容器,支持构造函数注入、属性注入和方法调用注入。

Unity的优势:

  1. 提供简单的对象创建,特别是分层对象结构和依赖。
  2. 提供抽象需求。允许开发人员在运行时或者配置中指定依赖。
  3. 增加灵活性,推迟组件配置到容器中
  4. 它有一个本地服务能力。允许用户保存或缓存容器。这个特别适用于Asp.Net web应用程式中,持久化Session和application容器

创建流程:

  1. 安装Unity for MVC
  2. 创建Bootstrapper.cs文件
    1. Initialise()

注册对应反转依赖

  1. Application_Start()

Bootstrapper.Initialise();

  2. 构造函数注入

private IEmployeeService _employeeService;

        public UserController(IEmployeeService employeeService)

        {

            _employeeService = employeeService;

        }

MEF(Managed Extensibility Framework)

虽然之前IOC以前减少了部分依赖,但是Domain Model依然依赖在API中。

轻耦合架构需要做到以下几点:

  1. Domain Model:只跟Service层关联
  2. Services:只跟REST终端和Domain Model关联
  3. REST API,也就是Controller,通过IOC,跟Services暴露的接口关联

为了解决API依赖Domain Model,我们采用MEF进行解耦。

MEF(Managed Extensibility Framework)是一个用于创建可扩展的轻型应用程序的库。 应用程序开发人员可利用该库发现并使用扩展,而无需进行配置。 扩展开发人员还可以利用该库轻松地封装代码,避免生成脆弱的硬依赖项。 通过 MEF,不仅可以在应用程序内重用扩展,还可以在应用程序之间重用扩展。(摘自MSDN)

流程:

  1. 删除原有容器的注册配置

    container.RegisterType<IEmployeeService, EmployeeBusinessLayer>()
                        .RegisterType<UnitOfWork>(new HierarchicalLifetimeManager());

  2. 创建Resolver类库

    a. 添加Unity.MVC

    b. 添加引用:System.ComponentModel.Composition

      这个DLL是MEF的一部分,提供MEF的核心类

    c. 添加接口IComponent

      包含方法initialization方法Setup, 组合IRegisterComponent

    d. 添加接口IRegisterComponent

      定义RegisterType等容器的方法

    e. 添加ComponentLoder加载类。

      包含LoadContainer,加载指定path路径的dll里的所有带有Export属性并继承IComponent的modules,执行他们的setup方法也就是注册依赖关系。

var dirCat = new DirectoryCatalog(path, pattern);
            var importDef = BuildImportDefinition();
            try
            {
                using (var aggregateCatalog = new AggregateCatalog())
                {
                    aggregateCatalog.Catalogs.Add(dirCat);
                    using (var componsitionContainer = new CompositionContainer(aggregateCatalog))
                    {
                        var exports = componsitionContainer.GetExports(importDef);
                        var modules = exports.Select(export => export.Value as IComponent).Where(m => m != null);
                        var registerComponent = new RegisterComponent(container);
                        foreach (var module in modules)
                        {
                            module.SetUp(registerComponent);
                        }
                    }
                }

    f. 每个需要做IOC的类库下,添加类DependencyResolver,继承IComponent,实现SetUp方法,方法内部实现RegisterType功能,达到依赖注册的作用。添加属性Export

[Export(typeof(IComponent))]
    public class DependencyResolver : IComponent
    {
        public void SetUp(IRegisterComponent registerComponent)
        {
            registerComponent.RegisterType<IUnitOfWork, UnitOfWork>();
        }
    }

  3. 修改原来配置为如下:

ComponentLoader.LoadContainer(container, ".\\bin", "Services.dll");

使用MEF的好处:

  1. 使应用程序更解耦和可扩展。扩展的时候,只需要以同样的方法添加新的DependencyResolver类,没有依赖。
  2. 依赖注册通过反射自动生成。只需要指定对应的dll的位置,如在bin下。
  3. 数据库事务或者一些模块不想暴露到服务终端时,MEF就变得更安全且不破坏当前设计结构。

使用AttributeRouting重写自定义URL

流程:

  1. 在WebConfig的Register方法中,替换为MapHttpAttributeRoute();如下:
public static class WebApiConfig

    {

        public static void Register(HttpConfiguration config)

        {

            //config.Routes.MapHttpRoute(

            //    name: "DefaultApi",

            //    routeTemplate: "api/{controller}/{id}",

            //    defaults: new { id = RouteParameter.Optional }

            //);

            config.MapHttpAttributeRoutes();

        }

    }

  2. Global.ascx中,替换原来的注册

protected void Application_Start()

        {

            //WebApiConfig.Register(GlobalConfiguration.Configuration);

            GlobalConfiguration.Configure(WebApiConfig.Register);

}

  3. 几种Route自定义方式

    a. Controller上设置前缀

[RoutePrefix("users/user")]

[RoutePrefix("v1/users/user")]

    b. Action上自定义路由

[Route("u/{id?}")]

[Route("u/{id:range(1,3)}")]

[Route("u/id/{e:regex(^[0-9]$)}")]

[Route("~/myroute/users")]

使用ActionFilter创建基于WebApi认证安全和基于Token的自定义权限

企业级应用的安全尤为重要,特别是通过服务暴露我们的业务数据。先介绍一下内容:

  1. Authentication认证

Authentication认证用于确认终端用户,验证用户是否有权限访问系统。等会通过Basic Authentication技术来理解如何在webapi中实现authentication功能。

  1. Authorization授权

Authorization授权可以理解为做完Authentication认证后的第二部实现安全机制。并不是所有可以访问系统的用户都能访问所有模块比如action。Authorization通过设置角色和许可给终端用户,或者通过提供安全的token,来指定用户是否能够访问具体系统资源。

  1. 持久化Session

RESTful服务工作在无状态的协议,比如HTTP。我们可以通过基于token授权技术来实现持久化Session的功能。一个授权过的用户,允许你在一定时间内访问资源,且能通过延长session的有效时间来重新实例化请求访问资源。使用WebAPI的站点可以通过Basic Authentication和Token Base authorization来持久化session.

Basic Authentication

Basic认证是一种机制。当用户请求服务时,会将用户名密码等嵌套在请求头。服务接收请求后验证证书是否有效,然后返回响应结果。无效证书对应的响应结果是401,代表无权限访问。

优点:容易实现,支持所有浏览器,并且成为RESTful的标准认证。

缺点:用户证书包含在请求头,很容易受到攻击。没有持久化Session,一旦用户登录且多次发送过证书给服务的时候,就不能退出。而且非常容易受到攻击,如CSRF

基于Token授权

Token一般为加密后的key,只有服务器或者服务知道它的含义。当用户发送请求并传递token的时候,服务器通过token判断用户是否有权限访问系统。生成后的Token可以被存到数据库或者配置文件中。Token有自己的生命周期,有失效时间。

WebAPI使用Basic认证和Token授权的流程:

  1. 创建用户表
  2. 创建Service和Repository
  3. IOC
  4. 创建AuthorizationFilterAttribute
    1. 实现OnAuthrozation

i.      获取用户相关信息GenericIdentity

filterContext.Request.Headers.Authorization.

Scheme==”Basic”

Parameter.split(“:”) [0] username, [1]password

ii.      调用Service获取数据库用户信息,进行验证

  5. 通过添加属性过滤,或者在global添加全局过滤

[ApiAuthenticationFilter]

GlobalConfiguration.Configuration.Filters.Add(new ApiAuthenticationFilter());

设计缺陷

每一次请求都发送用户密码。假设我创建一个应用,这个应用的认证只在我登录的时候发生一次。这时我也有权限访问其他服务。我们的应用应该更安全,他要能约束及时认证过的用户,不能访问没有授权给他的服务。

通过Token来实现授权。只暴露比如登录的服务给用户。当用户登录成功后,发送一个token(可以是GUID或者加密的key)给用户,每一次请求时都要带上这个token。在持久化session方面,token有失效时间,一般为15分钟,可以在web.config做个入口配置。在session过期后,用户登出,重新登录获取新的token。

使用Action Filter, Exception Filter实现WebAPI的日志容错功能

NLog的使用

  1. Nuget下载NLog
  2. 配置NLog
    1. ConfigSection的配置

      2. NLog节点的配置

  3. Web项目中添加APILog文件夹

  4. 添加Helpers文件夹,添加以下几个文件

    1. NLogger类

      继承ITraceWriter的Trace方法,主要用于记录所有类型的错误和信息的日志。

  5. 添加LoggingFilterAttribute继承Action Filter

    将NLogger类引入

  6. 注册LoggingFilterAttribute到Global

错误日志

  1. 添加GlobalExceptionAttribute类,继承ExceptionFilterAttribute,实现OnException方法

将NLogger注入

  2. 其余操作如日志一样

自定义错误日志

可以将错误分为三大类:API级别的错误、业务错误、数据错误

  1. 添加接口IApiException

    包含属性Error的基本信息属性

  2. 各添加三个类ApiException、ApiBusinessException、ApiDataException,继承IApiException和Exception

  3. 引用JSon序列化

    Log需要能够序列化成json以便我们能够将日志对象传输到各个模块中去。

  4. 修改之前的NLogger类

  5. 修改GlobalExceptionAttribute

  6. 在Controller中,抛出我们自定义的错误类

WebAPI中的OData

OData是一种协议,它提供灵活创建可查询的REST服务,准确的说,它提供各种查询选项,如参数,来决定你具体要查询的数据。如下面链接

http://localhost/Products?$orderby=Name

OData允许你创建可查询的服务,当终端服务支持OData时,你可以过滤请求结果,比如提取前n条数据,排序,选取某条数据等等。

查询选项

ASP.NET WebAPI支持以下几种:

  1. $orderby:排序
  2. $select:选择某列或者某个属性
  3. $skip:与Linq类似,跳过前N条数据,提取N+1后数据
  4. $top:前N条
  5. $expand:扩展实体
  6. $filter:过滤
  7. $inlinecount:类似分页

使用流程

  1. nuget安装OData
  2. 在Api里的结果集中引用方法AsQueryable(),设置成可查询
_employeeService.GetAll().AsQueryable()

  3. 各种查询选项的使用

    a. $top

    /Employee/All?$top=2

    b. $filter

    /Employee/All?$ filter =name eq ‘Ryan ’  获取name等于Ryan的数据

    /Employee/All?$ filter =id lt 3  获取id小于3的数据

    c. $orderby

    /Employee/All?$ orderby =name desc

    d. $orderby和 $top一起用

    /Employee/All?$top=2&orderby = name desc

    e. $skip

    /Employee/All?$top=5$skip=2 取第3条开始的前5条数据,3-7

Filter的操作符


eq


等于


$filter=revenue eq 100


ne


不等于


$filter=revenue ne 100


gt


大于


$filter=revenue gt 100


ge


大于等于


$filter=revenue ge 100


lt


小于


$filter=revenue lt 100


le


小于等于


$filter=revenue le 100


and



$filter=revenue lt 100 and revenue gt 2000


Or



$filter=contains(name,‘(sample)‘) or contains(name,‘test‘)


Not


不包含


$filter=not contains(name,‘sample‘)


( )


括号域


(contains(name,‘sample‘) or contains(name,‘test‘)) and revenue gt 5000

查询函数


Contains


$filter=contains(name,‘(sample)‘)


endswith


$filter=endswith(name,‘Inc.‘)


startswith


$filter=startswith(name,‘a‘)

    f. 分页

    添加属性[Queryable(PageSize = 10)]

    g. 设置可允许的选项

 [Queryable(AllowedQueryOptions =AllowedQueryOptions.Filter | AllowedQueryOptions.OrderBy)]

    h. 允许具体的排序范围

[Queryable(AllowedOrderByProperties = "ProductId")]

    i. 允许操作符范围

[Queryable(AllowedLogicalOperators = AllowedLogicalOperators.GreaterThan)]

    j. 允许计算操作符的范围

[Queryable(AllowedArithmeticOperators = AllowedArithmeticOperators.Add)]

创建自宿主的WebAPI-OWIN

  1. 添加console应用
  2. Nuget安装webapi owin self-host
  3. 添加api
  4. 添加Startup类

    使用httpConfiguration创建路由,通过appBuilder.UseWebApi方法添加到请求管道中

  

  5.Main函数中使用Api项目里的Startup类

  6. 运行console

参考文献

http://www.codeproject.com/Articles/659131/Understanding-and-Implementing-ASPNET-WebAPI

http://www.codeproject.com/Articles/838274/Web-API-Thoughts-of-Data-Streaming

http://www.codeproject.com/Articles/990492/RESTful-Day-sharp-Enterprise-Level-Application#_Toc418969124

http://www.codeproject.com/Articles/889242/WebAPI-Self-Hosting-Using-OWIN

http://www.codeproject.com/Articles/631668/Learning-MVC-Part-Repository-Pattern-in-MVC-App

http://www.codeproject.com/Articles/640294/Learning-MVC-Part-Generic-Repository-Pattern-in

时间: 2024-10-09 21:49:05

重温ASP.NET WebAPI(二)进阶的相关文章

重温ASP.NET WebAPI(一)初阶

前言 本文为个人对WebApi的回顾无参考价值.主要简单介绍WEB api和webapi项目的基本结构,并创建简单地webaapi项目实现CRUD操作. 在商业应用领域中,应用之间的关联是相当重要的,应用之间如移动应用或者单页应用的创建,都需要强大的后端服务提供相应的数据以便进行CRUD操作. WCF and WebApi 的不同 WCF是基于SOAP协议,支持多种传输协议,多种编码,寄宿于.net framework下,需要生产WSDL代理类文件,更安全可靠. WebApi是基于HTTP协议,

使用ASP.Net WebAPI构建REST服务(二)——路由

REST并没有像传统的RPC服务那样显式指定了服务器函数的访问路径,而是将URL根据一定的规则映射为服务函数入口,这个规则就称之为路由.Asp.Net WebAPI的路由方式和Asp.Net MVC是相同的,它支持两种路由方式,传统的路由映射和特性路由. 路由规则WebApiConfig.cs中定义,它的默认内容如下: publicstaticclassWebApiConfig    {        publicstaticvoid Register(HttpConfiguration con

Asp.Net WebApi 项目及依赖整理

一.目前版本 Microsoft ASP.NET Web API 2.2 对应程序集版本5.2.3 二.默认生成的配置文件中的内容 <packages> <package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net452" /> <package id="Microsoft.AspNet.WebApi.Client&qu

Asp.Net WebAPI配置接口返回数据类型为Json格式

一.默认情况下WebApi 对于没有指定请求数据类型类型的请求,返回数据类型为Xml格式 例如:从浏览器直接输入地址,或者默认的XMLRequest,或者AngularJs的get请求等. 对于有循环引用的也会抛出异常""ObjectContent`1"类型未能序列化内容类型"application/xml; charset=utf-8"的响应正文." 二.设置返回格式为Json数据 1.修改配置,这对所有的接口都生效 找到Global.asax

分享一个前后端分离方案源码-前端angularjs+requirejs+dhtmlx 后端asp.net webapi

一.前言 半年前左右折腾了一个前后端分离的架子,这几天才想起来翻出来分享给大家.关于前后端分离这个话题大家也谈了很久了,希望我这个实践能对大家有点点帮助,演示和源码都贴在后面. 二.技术架构 这两年angularjs和reactjs算是比较火的项目了,而我选择angularjs并不是因为它火,而是因它的模块化.双向数据绑定.注入.指令等都是非常适合架构较复杂的前端应用,而且文档是相当的全,碰到问题基本上可以在网上都找到答案.所以前端基本思路就以angularjs为主.代码模块化,通过requir

Asp.Net WebApi Post请求整理(一)

Asp.Net WebApi+JQuery Ajax的Get请求整理 一.总结 1.WebApi 默认支持Post提交处理,返回的结果为json对象,前台不需要手动反序列化处理.2.WebApi 接收Post提交参数需要指定([FromBody] string name)3.WebApi 中如果只接收一个基础类型参数,不能指定key的名称4.WebApi Post请求Action只能接收一个参数,也就是说一个Action中[FromBody]仅可指定一次5.WebApi Post请求处理多个参数

ASP.NET WebAPI 02-Action的选择(一)

在WebAPI对于Action的选择主要经过:Action方法名匹配,Http方法匹配,参数匹配三步. Http方法匹配 WebAPI提供了三种Http方法的选择方式,分别是:方法前缀,AcceptVerbs特性,HttpXXX特性 方法前缀: 在上一篇中都是采用的这种方式,即将Http方法作为Action的前缀.比如GetAll, PostByUrl. 另外这种方式只能指定一种Http方法,比如GetPutPostAll()只支持GET请求 AcceptVerbs特性 AcceptVerbs特

mongodb+asp.net webapi开放平台系列

一步一步,从未知到懵懂到…… 脚印从来没有停止过…… mongodb+asp.net webapi开放平台系列渐行渐近…… 梳理此项目中的知识点包括mongodb,asp.net webapi  oauth2 elasticsearch mvc mongodb基础知识学习 Mongodb学习笔记一(Mongodb环境配置) Mongodb学习笔记二(Mongodb基本命令) Mongodb学习笔记三(Mongodb索引操作及性能测试) Mongodb学习笔记四(Mongodb聚合函数) asp.

Asp.Net WebAPI添加OData功能后,支持查询,排序,过滤。

给Asp.Net WebAPI添加OData功能后,就能支持在url中直接输入排序,过滤条件了. 一.修改WebAPIConfig.cs: using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; using System.Net.Http.Formatting; using System.Net.Configuration; namespace ProjectManagem