6.8 ASP.NET Core

6.8.1 简介

这篇文档是对ABP中集成的ASP.NET Core的描述。ASP.NET 集成是被实现在 Abp.AspNetCore 中。

迁移到ASP.NET Core?

如果你有一个旧项目想要迁移到ASP.NET Core,你可以从该博客获取一些迁移经验

6.8.2 Startup Template

你可以从Startup Template来创建你的项目,该模板是一个空置且简单的web项目,它预先集成且配置好一切可以与ABP框架一起运行。

6.8.3 Configuration

Startup Class

为了集成ABP到ASP.NET Core,我们应该在 Startup Class 中做一些配置,如下所示:

public class Startup
{
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        //...

        
        //配置Abp和依赖注入,在最后调用
        return services.AddAbp<MyProjectWebModule>(options =>
        {            
            //配置Log4Net(可选的)
            options.IocManager.IocContainer.AddFacility<LoggingFacility>(
                f => f.UseLog4Net().WithConfig("log4net.config")
            );
        });
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        //初始化ABP框架和所有其他模块,这个应该首先被调用
        app.UseAbp(); 
        
        //...
    }
}

Module Configuration

你可以使用启动配置来配置AspNet Core模块(在你模块的PreInitialize方法中使用 Configuration.Modules.AbpAspNetCore())

6.8.4 Controllers

在ASP.NET Core中控制器可以是任何类类型。它没有限制控制器类必须派生自Controller类,以Controller结尾的类默认为是MVC Controller,例如:ProductController。你也可以使用[Controller]特性添加到任何类上,使该类作为一个控制器。这就是ASP.NET Core MVC的工作方式。详细了解请查看ASP.NET Core文档 当然已经有贡献者开始翻译该文档https://github.com/dotnetcore/aspnetcore-doc-cn ,详细可以在cnblog中搜索。

如果你要使用web层类如:HttpContext或者返回一个视图,最好的方式是继承 AbpController (该类也是派生自MVC的Controller),如果你在创建一个和对象一起工作的API Controller,你可以考虑创建一个POCO Controller类或者可以使用应用层服务作为控制器,如下所述:

Application Services as Controllers

ABP提供了基础设施来创建应用服务。如果你想你的应用服务作为控制器暴露给远程客户端(正如前面文档描述的使用[动态WebAPI](5.1ABP分布式服务-ASP.NET WebApi.md)),你可以很容易的实现,只需要在你模块的 PreInitialize 方法中做一个简单的配置,如:

Configuration.Modules.AbpAspNetCore().CreateControllersForAppServices(typeof(MyApplicationModule).Assembly, moduleName: 'app', useConventionalHttpVerbs: true);

CreateControllersForAppServices 方法会取得指定程序集并转换该程序集下的所有的应用服务作为MVC Controller。你可以使用 RemoteService 特性来enable/disable 方法,类或者接口。

当应用服务被转换为MVC Controller时,默认路由模板是:/api/services/<module-name>/<service-name>/<method-name> 。例如:如果ProductAppService中定义了一个方法,那么它的URL会是:/api/services/app/product/create (假设模块名称是app)。

如果 useConventionalHttpVerbs 被设置为 true (默认就是这个)。那么通过命名约定对于应用服务的方法所使用的HTTP谓词会被断定为:

  • Get:如果方法的名字是以 Get 开头

  • Put:如果方法的名字是以 Put 或者 Update 开头

  • Delete:如果方法的名字是以 Delete 或者 Remove 开头

  • Post:如果方法的名字是以 Post,Create 或者 Insert 开头

  • Path:如果方法的名字是以 Path 开头

  • 否则 Post 被作为Http谓词的默认设置

你可以使用任何的 ASP.NET Core 特性来改变HTTP方法或者Action的路由(当然,添加ASP.NET Core package的引用是必须的)。

注意:首先,动态WebAPI需要应用服务层的服务类必须实现服务层的接口。但是对于ASP.NET Core 的集成不是必须的。所以MVC attributes应该被添加到服务类上,即使你实现了该接口。

6.8.4 Filters

ABP为AspNet Core预先构建了一些过滤器,这些过滤器被默认添加到所有控制器的所有的Action上。

Authorization Filter

身份授权认证功能管理 集成了 AbpAuthorizationFilter 过滤器.

  • 你可以在Action或者Controller上使用 AbpMvcAuthorize 特性,在Action执行之前来检查给定的权限是否开启

  • 你可以在Action或者Controller上使用 RequiresFeature 特性,在Action执行之前来检查给定的功能是否开启

  • 你可以在Action或者Controller上使用 AllowAnonymous(或者在应用层使用AbpAllowAnonymous) 特性来进行匿名访问,避免身份以及授权认证检测

Audit Action Filter

审计日志 集成了 AbpAuditActionFilter 过滤器,默认记录所有对Action的请求。你可以在Action或者Controller上使用特性: Audited和DisableAuditing 来控制是否记录日志。

Validation Action Filter

数据传输对象验证 集成了 AbpValidationActionFilter 过滤器,并且自动为所有Action进行输入验证。除此之外ABP还内置了validation & normalization。它也会检查MVC的 Model.IsValid 属性,如果Action的输入有无效的输入值那么它会抛出validation exception。

你可以使在Action和Controller上用特性:EnableValidation和DisableValidation 控制validation。

Unit of Work Action Filter

工作单元 集成了 AbpUowActionFilter 过滤器,它会在Action执行之前自动开启一个工作单元并且在Action执行完成后完成工作单元(如果没有异常抛出)。

你可以使用特性 UnitOfWork 来控制Action的UOW行为。你也可以使用启动配置来改变所有Action上的默认的工作单元特性设置。

Exception Filter

AbpExceptionFilter 被用来处理来自Controller的Action的异常。它处理并且记录异常信息且返回包裹的响应到客户端。

  • 它仅处理object result,不包括 view result。所以,action返回的任何对象,JsonResult 或者 ObjectResult 将会被处理。Action返回的任何实现自IActionResult视图或者其他结果类型不会被处理。最好是使用定义在Microsoft.AspNetCore.Diagonistics package中内置的 UseExceptionHandler 扩展方法来处理视图异常。

  • 可以在方法或者类上面使用 WrapResult和DontWrapResult 特性来改变异常处理和日志行为。

Result Filter

AbpResultFilter 被用来包装Action的返回结果,如果该Action执行成功的话。

  • 它仅对JsonResult,ObjectResult和其它不是实现IActionResult接口对象进行返回结果包装,如果你的Action正在返回一个视图或者其它结果的类型,它不会进行包装。

  • 在方法或者类上面使用 WrapResult和DontWrapResult 特性可以enable/disable包装。

  • 你可以在启动配置里面对包装结果的默认行为进行更改

缓存Ajax请求结果

对于Ajax请求,AbpResultFilter 会添加 Cache-Control 头 (no-cache, no-store...) 到响应结果。 因此,对于AJAX请求,它会阻止浏览器缓存响应结果,甚至对于Get请求也一样。通过配置或者特性,你可以禁用该行为。你可以使用 NoClientCache 特性来阻止缓存(这是默认行为)或者使用 AllowClientCache 特性来允许浏览器缓存结果。或者,为了更好的自定义控制,你可以扩展 IClientCacheAttribute 接口来实现指定特性。

6.8.5 Model Binders

AbpDateTimeModelBinder 被用来标准化输入时间(可空类型的时间),实际是调用 Clock.Normalize 方法来实现该功能。

6.8.6 Views

MVC视图继承自 AbpRazorPage,它自动实现了大多数基础设置的注入(例如:LocalizationManager, PermissionChecker, SettingManager等等)。它也有一些便捷的方法如 L() 资源本地化。

你可以从 AbpViewComponent 继承web组件,而不是使用 ViewComponent 来利用基本属性和方法。

6.8.7 Client Proxies

ABP能自动的为所有的MVC Controllers创建脚本代理(不仅仅是服务层应用)。它默认为控制器的应用层服务创建脚本代理。你可以在任何的MVC Controller上使用 [RemoteService] 特性来创建客户端代理。脚本代理在运行时被动态的创建。你只需要在页面(Layout.cshtml)上添加如下代码:

<script src="~/AbpServiceProxies/GetAll?type=jquery" type="text/javascript"></script>

当前仅生成了JQuery代理。我们可以使用脚本来调用MVC Action,如下所示:

abp.services.app.product.create({
    name: 'My test product',
    price: 99
}).done(function(result){
    //...
});

6.8.7 集成测试

对于ASP.NET Core的集成测试是相当容易的详细请查阅文档。ABP遵循这个指导并且在Abp.AspNetCore.TestBase package 提供了 AbpAspNetCoreIntegratedTestBase 类。这使集成测试变得更容易。

最好是在启动模板中通过检查集成测试来查看实际应用情况。