CoreCRM 开发实录 —— Profile
再简单的功能,也需要一坨代码的支持。Profile 的编辑功能主要就是修改个人的信息。比如用户名、头像、性别、电话……虽然只是一个编辑界面,但添加下来,涉及了6个文件的修改和7个新创建的文件。各种生成的和手写的代码,共有934行之多。
1. Account 和 Profile 分离
什么是 Account?通常这个词被翻译成“帐户”。我的理解是,这个 Model 里的内容,是为了登录而设计的。而 Profile 呢,应该保存那些和登录无关的附加信息,比如昵称、头像之类的。不过,有一点坑的是,ASP.NET Core 默认的那个 Identify 服务把电话号码也做为 Account 的一部分,但没有提供通过电话来查找一个 User 的方法。虽然可以通过写一个 Extension 来实现这个功能,暂时先放在一边,有需求再说。
在原来的“悟空CRM”中,所有的信息都是放在 user 这个表里的。对于 CRM 这个应用,也不是一个大的问题。但我认为还是应该把 Profile 和 Account 分开。这样,在登录及验证用户权限的时候,就不需要去访问不相关的 Profile 里的内容。也许有朋友会说:我通过 SELECT 那些我需要的列,不也一样可以实现这个结果吗?但实际上,一个 Row 的内容,都是保存在一起的。只是数据库帮你过滤出来那些需要的信息。但在读取的时候,还是要去访问一整个 Row 的内容。如果分开当然就完全不需要访问了(虽然还有个 ID 在那里,但一个 ID 最多才4个字节)。
2. Repository
Repository 模式其实算是对一些使用 Plain Object 做 ORM 的系统的补充。按照 MVC 的实践准则,业务逻辑应该是写在 Model 这一层的。但为了保持 Model 是一个 Plain Object,只能再引入一层抽象,用来嫁接 Controller 和底层的 Model。当然,使用 Repository 还有另外一个好处,就是把数据库隔离开了。这样,对于 Controller 的单元测试就方便多了。否则,对 Controller 里一些逻辑的测试,还需要配置数据库。不过,有得就一定会有失。这里虽然测试 Controller 方便了,确还得对 Repository 本身时行测试。比较幸运的是,Entity Framework Core 提供了一个 InMemory 的数据库,专门用来测试对数据库的访问。
通常 Repository 会包含以下这些方法:
IEnumerable<Model> GetInstances();
Model GetModelByID(int ID);
void InsertModel(Model model);
void DeleteModel(int ID);
void UpdateModel(Model model);
void Save();
当然,对于具体的某个哪个 Model,这个列表也可以做一些修改。比如对于 Profile 这个 Model,我只使用了:
Task<Profile> GetCurrentUserProfileAsync(ClaimsPrincipal userClaimsPrincipal);
Task<ProfileViewModel> GetCurrentUserProfileViewModelAsync(ClaimsPrincipal userClaimsPrincipal);
Task UpdateProfileAsync(ClaimsPrincipal userClaimsPrincipal, ProfileViewModel model);
感觉上,这三个函数应该做一些修改。因为这个页面不只可以编辑自己的资料,也可以让管理员改任何人的资料。如果是这样,GetCurrentUserProfileAsync 这个函数就应该改成 GetUserProfileAsync,可以加一个参数:userId。如果 userId 是 null 的话,就需要获取当前的用户的 Profile,如果有 userId, 那就去获取对应用户的 Profile。
MSDN 上有一篇关于 Repository 模式的说明。写的比较细。园子里的这篇也写的不错。
3. Interface
C# 里通常都是面向 interface 来写程序的。一开始我不是很适应这种模式,因为同一个类,还需要再写一个 interface,等于要把所有的函数签名再抄一遍。如果要修改,也是需要两处都改。保如果把测试考虑进去的话,就不一样了。如果是对一个类产生依赖,那么注入的时候,就需要对这个类进行 mock。如果这个类还有依赖,那整个就悲剧了。如果是使用 interface,这个问题就不存在了。
其实 interface 和 C 语言的 header file 很像。都是定义了函数的签名,然后在另一个地方来实现这个函数的功能。到了 C# 里,为什么这种分享确成了一种负担呢?只是这里有一个问题:interface 是这种侵入式的语言特性。也就是说:一个类必需要继承了对应的 interface 才可以做为这个 interface 的实例来使用。如果想对一个没有修改方法(比如一个 NuGet 包)想添加 interface 的话,就需要一个中间的 Adaptor 来转换。
4. MaxLength & StringLength
EF Core 的 Model 可以通过 Attribute 来指定一个字段的长度。同时,在 ViewModel 里,还可以指定 UI 层的验证。这时候就有两个东东出来了:StringLength 和 MaxLength。其中 MaxLength 是用来指定 EF 里面一个 string 字段的最多可以写多少个字符,也就是:varchar(n) 里的 n。而 StringLength 则是用来指定 ViewModel 里的验证长度的。
下一步
下一步,我要给 ProfileController 增加单元测试,把一些逻辑从 Repository 里弄出来,让 Repository 里尽量少的包含逻辑代码。这样,因为是直通底层,只需要最后做集成测试就可以了,就不需要做单元测试了。
CoreCRM 开发实录 —— Profile的更多相关文章
- CoreCRM 开发实录 —— 单元测试、测试驱动开发和在线服务
测试不是问题,问题是怎么测试. ## 单元测试 我认为单元测试已经是无可争议的最佳开发实践之一.但是很多人并不同意这个观点.他们的说法无非是:写测试需要花很多时间,需求又经常变动,一但变动,一大片测试 ...
- CoreCRM 开发实录——Travis-CI 实现 .NET Core 程度在 macOS 上的构建和测试 [无水干货]
上一篇文章我提到:为了使用"国货",我把 Linux 上的构建和测试委托给了 DaoCloud,而 Travis-CI 不能放着不用啊.还好,这货支持 macOS 系统.所以就把 ...
- CoreCRM 开发实录——开始之新项目的技术选择
2016年11月,接受了一个工作,是对"悟空CRM"进行一些修补.这是一个不错的 CRM,开源,并提供一个 SaaS 的服务.正好微软的 .NET Core 和 ASP.NET C ...
- CoreCRM 开发实录 —— 单元测试之 Mock UserManager 和 SignInManager
单元测试的核心就是:只测试眼前的逻辑.这就要求所有的依赖项都要使用仿类来代替,也就是所谓的 Mock Object.在测试 ProfileRepository 和 AccountController ...
- CoreCRM 开发实录 —— 前后端分离的重构
虽然2月初就回来了,可 CoreCRM 一直到5月才开始恢复开发,期间是各种生活中的意外和不方便. 1. 为什么要重构 首先是一件很值得高兴的事情:CoreCRM 有了第一位 contributor! ...
- CoreCRM 开发实录——想用国货不容易
昨天(2016年12月29日)发了开始开发的文章.本来晚上准备在 Coding.NET 上添加几个任务开始搞起了.可是真的开始用的时候才发现:Coding.NET 的任务功能只针对私有的任务开放.我想 ...
- CoreCRM 开发实录 —— 基于 AntDesign 的新 UI
上一篇说到,因为有新朋友加入,对前端开发有了新的要求.原来基于 Bootstrap 的 UI 就不要了.在网上(其实是 GitHub 上)逛了几圈,最后使用了 antd-admin 这个框架做为基础模 ...
- 【视频开发】ONVIF、RTSP/RTP、FFMPEG的开发实录
ONVIF.RTSP/RTP.FFMPEG的开发实录 前言 本文从零基础一步步实现ONVIF协议.RTSP/RTP协议获取IPC实时视频流.FFMPEG解码.开发环境为WIN7 32位 + VS201 ...
- Google Chrome Native Messaging开发实录(二)Chrome Extension扩展
接上一篇<Google Chrome Native Messaging开发实录(一)背景介绍>的项目背景,话不多说,有关Chrome Extension介绍和文档就不展开了,直接上代码. ...
随机推荐
- 使用 .NET WinForm 开发所见即所得的 IDE 开发环境,实现不写代码直接生成应用程序
直接切入正题,这是我09年到11年左右业余时间编写的项目,最初的想法很简单,做一个能拖拖拽拽就直接生成应用程序的工具,不用写代码,把能想到的业务操作全部封装起来,通过配置的方式把这些业务操作组织起来运 ...
- 23种设计模式--单例模式-Singleton
一.单例模式的介绍 单例模式简单说就是掌握系统的至高点,在程序中只实例化一次,这样就是单例模式,在系统比如说你是该系统的登录的第多少人,还有数据库的连接池等地方会使用,单例模式是最简单,最常用的模式之 ...
- ASP.NET 5 RC1 升级 ASP.NET Core 1.0 RC2 记录
升级文档: Migrating from DNX to .NET Core Migrating from ASP.NET 5 RC1 to ASP.NET Core 1.0 RC2 Migrating ...
- 设计模式C#合集--工厂方法模式
简单工厂,代码: public interface ISpeak { public void Say(); } public class Hello : ISpeak { public void Sa ...
- OSGi规范的C#实现开源
这是大约在3-4年前完成的一个C#实现的OSGi框架,实现的过程参照了OSGi规范与与一些实现思路(感谢当时的那些资料与项目),此框架虽然仅在几个小型项目有过实际的应用,但OSGi的规范实现还是相对比 ...
- web服务器集群
概述 集群和分布式都是从集中式进化而来的.分布式和集群会相互合作的,同时的集群和分布式.在这里重点说说集群 集群是什么? 集群能提高单位时间内处理的任务数量,提升服务器性能 有多台服务器去处理任务,但 ...
- Xamarin Android 应用程序内图标上数字提示
最近在用 Xamarin 做一个 Android 应用,打开应用时,如果有新消息,需要在应用内的 Toolbar 或者首页的图标上显示数字提示.在这里和大家分享一下实现方法,如果你有更新好的实现方法, ...
- 巧用location.hash保存页面状态
在我们的项目中,有大量ajax查询表单+结果列表的页面,由于查询结果是ajax返回的,当用户点击列表的某一项进入详情页之后,再点击浏览器回退按钮返回ajax查询页面,这时大家都知道查询页面的表单和结果 ...
- Android Starting Window(Preview Window)
当打开一个Activity时,如果这个Activity所属的应用还没有在运行,系统会为这个Activity所属的应用创建一个进程,但进程的创建与初始化都需要时间,在这个动作完成之前系统要做什么呢?如果 ...
- ABP(现代ASP.NET样板开发框架)系列之10、ABP领域层——实体
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之10.ABP领域层——实体 ABP是“ASP.NET Boilerplate Project (ASP.NET样板 ...