前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Rafy 框架:领域控制器

Rafy 框架:领域控制器

作者头像
用户1172223
发布2022-05-10 09:57:40
5500
发布2022-05-10 09:57:40
举报
文章被收录于专栏:哲学驱动设计

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

简介

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

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

示例

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

代码语言:javascript
复制
/// <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));
	}
}

调用方的代码如下:

代码语言:javascript
复制
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 事件发生时,入库模块会发生一些特定的逻辑。

代码语言:javascript
复制
//业务插件一:库存模块
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 用户手册》中。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
  • 示例
  • 特点
  • 远程调用
  • 领域控制器事件
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档