本文简要说明如何使用 Rafy 框架中的领域控制器。

简介

领域控制器是 Rafy 框架中用于封装领域逻辑的主要方式。

在控制器中,开发者可以封装大量的业务逻辑,并向外暴露业务接口。内部的逻辑在实现时,往往调用一个或多个实体仓库的 CDUQ 方法来实现。

示例

以下代码为 Rafy.Accounts 帐户插件 中 AccountController 类型的真实代码。

/// <summary>
/// 帐户插件的领域控制器。
/// </summary>
public class AccountController : DomainController
{
/// <summary>
/// 注册指定的用户。
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
[ControllerLogic]
public virtual Result Register(User user)
{
if (user == null) throw new ArgumentNullException("user");
var userNameAsId = _identityMode.HasFlag(UserIdentityMode.UserName);
if (userNameAsId && string.IsNullOrEmpty(user.UserName)) return new Result(ResultCodes.RegisterUserNameInvalid, "用户名不能为空。");
var emailAsId = _identityMode.HasFlag(UserIdentityMode.Email);
if (emailAsId && !TextFormatter.ReEmail.IsMatch(user.Email)) return new Result(ResultCodes.RegisterEmailInvalid, "邮箱格式不正确。");
if (!userNameAsId && !emailAsId) throw new InvalidProgramException("!userNameAsId && !useEmailAsId"); //验证其它属性。
var brokenRules = Validator.Validate(user);
if (brokenRules.Count > 0) return new Result(ResultCodes.RegisterPropertiesInvalid, brokenRules.ToString()); //检查用户名、邮箱的重复性。
var repo = RF.ResolveInstance<UserRepository>();
var criteria = new CommonQueryCriteria();
criteria.Concat = BinaryOperator.Or;
if (userNameAsId)
{
criteria.Add(new PropertyMatch(User.UserNameProperty, user.UserName));
}
if (emailAsId)
{
criteria.Add(new PropertyMatch(User.EmailProperty, user.Email));
}
var exists = repo.GetFirstBy(criteria);
if (exists != null)
{
if (emailAsId && exists.Email == user.Email)
{
return new Result(ResultCodes.RegisterEmailDuplicated, string.Format("注册失败,已经存在邮箱为:{0} 的用户。", user.Email));
}
else
{
return new Result(ResultCodes.RegisterUserNameDuplicated, string.Format("注册失败,已经存在用户名为:{0} 的用户。", user.UserName));
}
} //保存这个用户
user.PersistenceStatus = PersistenceStatus.New;
repo.Save(user); this.OnRegisterSuccessed(user); return true;
} /// <summary>
/// 注册成功的事件。
/// </summary>
public event EventHandler<AccountEventArgs> RegisterSuccessed; /// <summary>
/// 注册成功的事件。
/// </summary>
/// <param name="user"></param>
protected virtual void OnRegisterSuccessed(User user)
{
var handler = this.RegisterSuccessed;
if (handler != null) handler(this, new AccountEventArgs(user));
}
}

调用方的代码如下:

var controller = DomainControllerFactory.Create<AccountController>();

var res = controller.Register(new User
{
UserName = "hqf",
RealName = "hqf",
Password = controller.EncodePassword("hqf")
});

通过 DomainControllerFactory 来创建一个控制器(也可用简写 DCF),即可调用其中的方法。

特点

  • 支持本地调用,也支持分布式调用

    领域控制器是除了仓库查询以外,提供分布式数据传输的另一机制。控制器的调用,支持本地调用,也支持分布式调用。详见:部署

  • 无状态

    领域控制器本身应该是无状态的。每次使用工厂创建时,都会创建一个新实例。特殊情况下,如果需要传递状态,需要对属性添加 [ControllerClientSettings] 标记。

  • 支持领域控制器事件及依赖管理

    详见后文。

  • 支持使用接口来定义控制器契约。参见:IDomainControllerContract 接口。

远程调用

DomainController 中,所有可远程调用的方法,都需要满足:一、标记为虚方法;二、添加 [ControllerLogic] 标记。工厂会为在运行时创建控制器的子类,并这些方法实现远程调用。

所以,此类方法需要注意,参数及返回值应该都是要支持序列化的。否则会在远程调用时失败。

领域控制器事件

各业务模块可以分别定义大量的领域控制器,而模块之间的业务,往往需要进行交互。除直接的调用关系以外,领域控制器还提供了事件依赖及管理功能。

例如,我们往往希望在用户注册成功后,各业务模块(例如博客模块)再额外注册一些其它内容。这时,我们又不希望修改用户的注册代码。那么我们可以在博客模块的领域控制器中,指定该控制器依赖 AccountController,这时再监听 RegisterSuccessed 事件添加自己的业务逻辑。

下面示例代码中,基础库存模块与入库管理插件,后者依赖前者。代码展示了,库存业务插件的 StockChanged 事件发生时,入库模块会发生一些特定的逻辑。

//业务插件一:库存模块
public class StockController : DomainController
{
public event EventHandler StockChanged; protected virtual void OnStockChanged()
{
var handler = this.StockChanged;
if (handler != null) handler(this, EventArgs.Empty);
}
} //业务插件二:入库管理插件
public class RecieveController : DomainController
{
static RecieveController()
{
Depend<RecieveController>().On<StockController>();
} protected override void OnAlwaysDependon(DomainController controller)
{
var sc = controller as StockController;
if (sc != null)
{
sc.StockChanged += OnStockChanged;
}
} private void OnStockChanged(object sender, EventArgs e)
{
//根据库存变化信息,来实现特定功能
}
}

PS:该文已经纳入《 Rafy 用户手册》中。

Rafy 框架:领域控制器的更多相关文章

  1. 一位同事对 Rafy 框架的一些建议及我的回复

    下面是一位同事对当前的产品开发框架提出的一些建议,以及我的回复.我觉得一些问题提得有一定的代表性,在征得本人同意后,将本邮件发布在博客中. 同时,也非常希望对框架.产品有好的建议的小伙伴,都可以给我发 ...

  2. 使用 NuGet 下载最新的 Rafy 框架及文档

    为了让开发者更方便地使用 Rafy 领域实体框架,本月,我们已经把最新版本的 Rafy 框架程序集发布到了 nuget.org 上,同时,还把 RafySDK 的最新版本发布到了 VisualStud ...

  3. Rafy 框架 - 时间戳插件

    本文将解释 Rafy 框架中的时间戳插件的场景.使用方法.原理. 场景 在开发各类数据库应用系统时,业务领域实体往往需要包含"创建时间"."最后更新时间".&q ...

  4. Rafy框架

    l  什么是Rafy框架? -------- Rafy 是一个面向企业级开发的插件化快速开发框架. l  Rafy的优点是什么? ------快速开发.产品线工程.一套代码可同时生成并运行 C/S.单 ...

  5. Rafy 框架 - 实体支持只更新部分变更的字段

    Rafy 快一两年没有大的更新了.并不是这个框架没人维护了.相反,主要是因为自己的项目.以及公司在使用的项目,都已经比较稳定了,也没有新的功能添加.但是最近因为外面使用了 Rafy 的几个公司,找到我 ...

  6. Rafy 框架 - 通用查询条件(CommonQueryCriteria)

    在应用开发过程中,有 80% 的场景下,开发者所需要的实体查询,查询条件中其实都是一些简单的属性匹配,又或是一些属性匹配的简单组合.Rafy 为这样的场景提供了更为方便使用的 API:CommonQu ...

  7. Rafy 框架 - 使用 SqlTree 查询

    本文介绍如何使用 Rafy 框架中的 Sql Tree 查询: 除了开发者常用的 Linq 查询,Rafy 框架还提供了 Sql 语法树的方式来进行查询. 这种查询方式下,开发者不需要直接编写真正的 ...

  8. Rafy 框架 - 流水号插件

    Rafy 框架又添新成员:流水号插件.本文将解释 Rafy 框架中的流水插件的场景.使用方法. 场景 在开发各类数据库应用系统时,往往需要生成从一开始的流水号,有时还需要按月或者按日进行独立生成,如下 ...

  9. Rafy 框架 - 幽灵插件(假删除)

      Rafy 框架又添新成员:幽灵插件.本文将解释该插件的场景.使用方法.原理.   场景 在开发各类数据库应用系统时,往往需要在删除数据时不是真正地删除数据,而只是把数据标识为'已删除'状态.这些数 ...

随机推荐

  1. pm2 部署 vue

    链接:我整理了一个网站, 用来介绍一些有意思和实用工具的网站, 我没有打包, 直接甩上去了 因为vue是用 npm run dev 来运行的, 你用pm2 npm run dev 是错误的 需要加上- ...

  2. 3、网络并发编程--udp代码、操作系统发展史、多道技术、进程理论

    昨日内容回顾 socket基本使用 # 内置的模块 import socket s = socket.socket() # 默认是TCP协议 也可以切换为UDP协议 s.bind((ip,port)) ...

  3. 基于3U PXIe的ZU7EV图像编解码设计方案

    1.板卡简介 基于3U PXIe的ZU7EV图像编码卡用于加固设备的图像接入,编解码采集存储.用于机载.舰载.车载等工作场景,支持工业级温度工作.(此方案是由北京太速设计的,已应用到实际领域) 2.主 ...

  4. Argo workflow 案例练习和配置详细解析

    参数化 - parameters hello-world-parameters.yaml文件解析 apiVersion: argoproj.io/v1alpha1 kind: Workflow met ...

  5. 图解python | 简介

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/56 本文地址:http://www.showmeai.tech/article-det ...

  6. 详细介绍Windows下也能够使用osw性能升级历史

    1.Windows系统历史性能分析困难背景 在Linux/Unix上.要追朔历史性能,一般採用部署nmon进行性能监控採集与存储的方式实现.可是却没有在Windows上的版本号. Windows系统假 ...

  7. OpenLDAP测试搭建

    目录 ldap介绍 测试环境 安装LDAP服务端 设置LDAP的root密码 配置LDAP服务端 创建LDAP证书 设置LDAP数据库 创建LDAP用户 添加防火墙规则 开启LDAP日志 配置LDAP ...

  8. 【基础篇】js对本地文件增删改查--删

    前置条件: 1. 本地有安装node,点击传送门 项目目录: 1. msg.json内容 { "data": [ { "id": 1, "name&q ...

  9. linux服务器随机10字符病毒/libudev4.so病毒清理的过程

    故障表现:某天晚上突然收到某项目一台web服务器CPU报警,SSH连接困难卡顿,登陆后发现CPU使用率飙升到700%,第一感觉是被黑了,来事了. 故障处理: 1.登陆上后发现有好多莫名的命令(who/ ...

  10. parquet和orc选型以及压缩格式

    Hive表压缩功能 除了直接配置MapReduce压缩功能外,Hive的ORC表和Parquet表直接支持表的压缩属性. 但支持的压缩格式有限,ORC表支持None.Zlib.Snappy压缩,默认为 ...