您的位置:首页 > Web前端 > AngularJS

使用Angular2及WebApi开发SPA类型的企业应用 - Part 7- 应用运行周期管理

2017-02-28 10:19 666 查看
使用Angular2及RESTful WebApi开发SPA类型的企业应用 - Part 7 应用生命周期管理

作者:techcoaching,翻译:飘落寒冰

原文 有道

注:第一次翻译文章,有错译之处还请多多包涵,欢迎指出以便改进。

在本文中,我们将学习如何管理应用的各个阶段

从Github上下载源码

该系列的全部文章

概览

添加新角色

项目结构

多语言

依赖注入和控制反转-为什么和为什么不?

RESTful & WebApi

应用运行周期管理

应用构建与部署

我们将学习哪些内容

本文将介绍

- 什么是应用的运行周期

- 为什么需要管理应用的运行周期

- 如何引发和处理应用的事件,例如:处理应用的错误,处理应用的启动等…

什么是应用的运行周期

应用的运行周期是指应用从启动到关闭的所有阶段的集合

例如一些应用有以下阶段

- 启动完成时

- 错误发生时

- 应用关闭时

为什么我们需要管理应用的运行周期

这将帮助我们在事件发生时执行特定的操作。例如:在一些应用中,我们可以:

- 当无法处理的异常发生时给系统管理员发送邮件

- 在应用开始运行之前准备数据

- 在应用关闭之前存储应用的状态

一个应用应该有几个阶段?

实际上,一个应用并没有固定的必须有的阶段列表。只是根据应用需要处理的事件来定义阶段列表。

本示例中,我们有以下的阶段:

事件说明
OnApplicationStarted当app启动完成时触发,部分应用在这时配置IoC&DI。
OnApplicationReady当app准备完毕后立即触发,部分应用在这时创建默认数据。
OnApplicationRequestStartedWeb应用中,每一次请求发送完毕后触发。
OnApplicationRequestEndedWeb应用中,每一次请求处理完毕时触发。
OnUnHandledError应用运行过程中,每一个未被处理的应用都会触发。
OnApplicationEnded应用结束时触发。通常我们会将应用的状态保存(到db,文件…)。

哪些类型的应用需要运行周期

本示例中我们用到了以下类型

类型说明
Console我们使用运行周期去管理console应用的状态
WebApi我们使用运行周期去管理WebAPI应用的状态,通常用于公开的API
MVC我们使用运行周期去管理MVC应用的状态
UnitTest我们使用运行周期去管理UnitTest应用的状态
IntegrationTest我们使用运行周期去管理IntegrationTest应用的状态
原文, 可能翻译有误

Which type of application we can have?

At this time, we have the flowing type of application:

Console We use this to manage the state of console application

WebApi We use this to manage the state of WebAPI application. This usually provide the public API

MVC We use this to manage the state of MVC application.

UnitTest We use this to manage the state of Unittest application.

IntegrationTest We use this to manage the state of integration-test application.

这有一些难以理解,你能给我举个具体的WebAPI应用例子吗?

我们按照以下的步骤为我们的应用处理事件

Global.asax

namespace App.Api
{
public class WebApiApplication : System.Web.HttpApplication
{
private App.Common.IApplication application;
public WebApiApplication()
{
this.application = App.Common.ApplicationFactory.Create<System.Web.HttpApplication>(App.Common.ApplicationType.WebApi, this);
}

protected void Application_Start()
{
this.application.OnApplicationStarted();
}

protected void Application_End()
{
this.application.OnApplicationEnded();
}
}
}


需要注意:

- 我们通过ApplicationFactory,使用ApplicationType.WebApi作为参数创建了一个IApplication实例。

- “Application_Start” (WebAPI app运行周期事件)调用了”OnApplicationStarted” (我们的 app运行周期事件) 。

- “Application_End” (WebAPI app运行周期事件)调用了”OnApplicationEnded” (我们的 app运行周期事件) 。

ApplicationFactory.cs

namespace App.Common
{
using App.Common.Validation;

public class ApplicationFactory
{
public static IApplication Create<TContext>(ApplicationType type, TContext application)
{
switch (type)
{
case ApplicationType.Console:
return new ConsoleApplication<TContext>(application);
case ApplicationType.MVC:
return new MVCApplication<TContext>(application);
case ApplicationType.WebApi:
return new WebApiApplication(application as System.Web.HttpApplication);
case ApplicationType.UnitTest:
return new UnitTestApplication<TContext>(application);
default:
throw new ValidationException("Common.ApplicationDoesNotSupported", type);
}
}
}
}


在这个类中,我们创建了WebApiApplication(接口IApplication的实现)的实例(接口IApplication的实现)。

WebApiApplication.cs

namespace App.Common
{
using App.Common.Helpers;
using App.Common.Tasks;
using System.Web.Routing;

public class WebApiApplication : BaseApplication<System.Web.HttpApplication>
{
public WebApiApplication(System.Web.HttpApplication context)
: base(context, ApplicationType.WebApi)
{
this.Context.BeginRequest += this.OnBeginRequest;
this.Context.EndRequest += this.OnEndRequest;
this.Context.Error += this.OnError;
}

public override void OnApplicationStarted()
{
base.OnApplicationStarted();
this.OnRouteConfigured();
}

private void OnRouteConfigured() {
TaskArgument<RouteCollection> taskArg = new TaskArgument<RouteCollection>(RouteTable.Routes, this.Type);
AssemblyHelper.ExecuteTasks<IRouteConfiguredTask, TaskArgument<RouteCollection>>(taskArg);
}

private void OnBeginRequest(object sender, System.EventArgs e)
{
this.OnApplicationRequestStarted();
}

private void OnEndRequest(object sender, System.EventArgs e)
{
this.OnApplicationRequestEnded();
}

private void OnError(object sender, System.EventArgs e)
{
this.OnUnHandledError();
}
}
}


在此类中,我们主要WebAPI的event映射到应用的event。

API事件应用事件
BeginRequestOnApplicationRequestStarted
EndRequestOnApplicationRequestEnded
ErrorOnUnHandledError
Application_Start (in Global.asax)OnApplicationStarted
Application_End (in Global.asax)OnApplicationEnded
此类继承于BaseApplication类

namespace App.Common
{
using App.Common.Helpers;
using App.Common.Tasks;

public class BaseApplication<TContext> : IApplication
{
public TContext Context { get; private set; }
public ApplicationType Type { get; private set; }
public BaseApplication(TContext context, ApplicationType type)
{
this.Context = context;
this.Type = type;
}

public virtual void OnApplicationStarted()
{
TaskArgument<TContext> taskArg = new TaskArgument<TContext>(this.Context, this.Type);
AssemblyHelper.ExecuteTasks<IApplicationStartedTask<TaskArgument<TContext>>, TaskArgument<TContext>>(taskArg);
AssemblyHelper.ExecuteTasks<IApplicationReadyTask<TaskArgument<TContext>>, TaskArgument<TContext>>(taskArg, true);
}

public virtual void OnApplicationEnded()
{
TaskArgument<TContext> taskArg = new TaskArgument<TContext>(this.Context, this.Type);
AssemblyHelper.ExecuteTasks<IApplicationEndedTask<TaskArgument<TContext>>, TaskArgument<TContext>>(taskArg);
}

public virtual void OnApplicationRequestStarted()
{
TaskArgument<TContext> taskArg = new TaskArgument<TContext>(this.Context, this.Type);
AssemblyHelper.ExecuteTasks<IApplicationRequestStartedTask<TaskArgument<TContext>>, TaskArgument<TContext>>(taskArg);
}

public virtual void OnApplicationRequestEnded()
{
TaskArgument<TContext> taskArg = new TaskArgument<TContext>(this.Context, this.Type);
AssemblyHelper.ExecuteTasks<IApplicationRequestEndedTask<TaskArgument<TContext>>, TaskArgument<TContext>>(taskArg);
}

public virtual void OnUnHandledError()
{
TaskArgument<TContext> taskArg = new TaskArgument<TContext>(this.Context, this.Type);
AssemblyHelper.ExecuteTasks<IUnHandledErrorTask<TaskArgument<TContext>>, TaskArgument<TContext>>(taskArg);
}
}
}


每个阶段都有对应的接口。

为了处理应用的某个阶段(例如,OnApplicationStarted),我们需要创建一个新的类来实现相应的接口(本例程中为IApplicationStartedTask )。

在事件触发是,这些类会被自动执行。

我想在应用启动时记录日志,能给个例子吗?

为了写日志,我哦们需要创建一个新的类继承IApplicationStartedTask, 命名为WriteLogOnApplicationStartedTask

namespace App.Api.Features.Share.Tasks.Common
{
using System.Web;
using App.Common.Tasks;
using System;

public class WriteLogOnApplicationStartedTask : BaseTask<TaskArgument<System.Web.HttpApplication>>, IApplicationStartedTask<TaskArgument<System.Web.HttpApplication>>
{
public WriteLogOnApplicationStartedTask() : base(App.Common.ApplicationType.WebApi){}

public override void Execute(TaskArgument<HttpApplication> context)
{
if (!this.IsValid(arg.Type)) { return; }
Console.WriteLine("This for test only: Application was started");
}
}
}


当用户第一次请求访问你的API时,此任务将会被调用:



为什么我们需要在我们的类的构造器中指定“ApplicationType.WebApi”?

此参数标明任务我们希望仅仅在WebApi application中执行。

在“Execute”方法中,我们会检查此任务,验证它是在何种类型的应用中执行。

if (!this.IsValid(arg.Type)) { return; }


我们假定当前运行的是“Console”应用,Isvalid方法将返回false,该任务将不会执行。

我们能指定任务的执行顺序吗?

是的,可以。在许多场景中,我们需要一个任务在其他任务完成后执行。

“WriteLogOnApplicationStartedTask”继承与“BaseTasks”,其拥有“Order”属性。

默认,所有的Task的Order都是0,我们可以将其设置成1,2,3或者更高。当执行的时候,这些任务会按Order的顺序执行。

因此,我们的类将变成:

public WriteLogOnApplicationStartedTask() : base(App.Common.ApplicationType.WebApi){
this.Order = 10;
}


Webapi已经有了这些事件,为什么我们还需要自己的应用运行周期的管理?

我打个比方,应用是游荡在水(.Net framework)里的鱼。 技巧 : 如何用一年时间获得十年的经验



将来我们可以换掉鱼缸,例如:将windows应用移植成web应用。

本app只需要做一点小修改就可以正常工作。



我们只需要将我们的代码映射到新环境相应的时间中,就可以管理我们app的运行周期。

举例来说: WriteLogOnApplicationStartedTask

Web环境下,我们注册了当App开始的任务

public class WebApiApplication : System.Web.HttpApplication
{
private App.Common.IApplication application;
public WebApiApplication()
{
this.application = App.Common.ApplicationFactory.Create<System.Web.HttpApplication>(App.Common.ApplicationType.WebApi, this);
}
protected void Application_Start()
{
this.application.OnApplicationStarted();
}
}


备注:在Application_Start, 我们触发了OnApplicationStarted。

但在单元测试应用中,我们这样注册

public abstract class BaseUnitTest
{
public App.Common.IApplication Application { get; protected set; }
public BaseUnitTest()
{
this.Application = App.Common.ApplicationFactory.Create<System.Web.HttpApplication>(App.Common.ApplicationType.UnitTest, null);
}

[TestInitialize()]
public void Init()
{
this.Application.OnApplicationStarted();
}

}


备注:在单元测试的初始化中,我们触发了 OnApplicationStarted。

同样的,我们也可以在Console应用中做类似的工作。通过这种方法,我们的代码可以在多种类型的应用中复用,而不是将他们复制到各处。

结论

本文是根据我的经验携程,如果您觉得某处写的有问题,请给我来信以便进一步的讨论。

我更期待您的回应而不是仅仅依据“此处有误”,交流是为了相互共享和提高我们自己。

授权

本文,以及所包含的源码,文件遵循CPOL协议
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  企业应用 angular
相关文章推荐