翻译:使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 设计和开发站点 - 6 - 业务逻辑

Part 3: 设计逻辑层:核心开发

如前所述,我们的解决方案如下所示:

下面我们讨论整个应用的结构,根据应用中不同组件的逻辑相关性,分离到不同的层中,层与层之间的通讯通过或者不通过限制。分层属于架构风格,在应用的长时间生命周期中,解决维护和扩展问题。
所以,让我们在解决方案中添加一个类库项目,命名为 Application.Common.

Application.Common :

这是一个类库项目, 提供公共功能,可以被不同的业务逻辑层使用。例如:安全,日志,跟踪,验证等等. 定义在这个层中的组件,不仅可以被不同的层使用,还可以在不同的应用中使用。为了未来容易使用,我们使用依赖注入和抽象,在应用中实现最小化的修改。

例如,在我们马上用到的,验证组件用来验证数据,定制的日志器来记录错误或者警告。

在添加了 Common 类库之后,解决方案的文件夹如下所示:

Application.Core:

这个层实现系统的核心处理逻辑,封装相关的所有业务逻辑。从基本上说,这个层通常实现领域处理的逻辑。这个层还经常通过核心层的工作单元,以便完成 PI 特性,主要的目标是明确区分和分离核心领域的逻辑与基础架构的具体细节,例如,数据访问和数据仓储的具体技术,像 ORM ,或者简单的数据访问库,或者面向方面的架构等等。通过分离系统的核心功能,我们就可以进一步增强系统的可维护性,甚至可以替换底层的组件,而很少影响到整个应用。


下一步,我们将在解决方案中添加名为 Application.DAL 的类库。

Application.DAL:

DAL 的职责是提供数据访问和数据的持久化处理;维护多个会话,连接到不同的数据库等等。这里的主要目标是通过接口和约定包装 EF 数据访问上下文对象,使得核心层不会直接依赖 EF。数据持久化组件提供驻留在系统内的数据访问,也提供系统外的数据访问。比如对外部系统提供服务的 Web 服务。因此,这里既包含类似 仓储模式的机制来支持对系统内的数据访问,还提供服务代理来使用其它外部系统通过 Web 服务提供的数据,另外,层中还提供可以对所有仓储使用的基类和组件。


下一步,我们将会在解决方案中添加一个名为 Application.Repository 的类库。

Application.Repository:

这个类库仅仅可以通过 Application.Manager 访问,对于领域中的每一个根实体对象,我们需要创建一个仓储,基本上,所谓的仓储就是封装了访问应用数据的处理逻辑的类和组件。而且,它们处理数据处理的核心功能,使得整个应用有更好的可维护性,并且可以在 Manager 和 Core 之间进行解耦。


下一步,我们需要创建名为 Application.DTO 类库。

Application.DTO:

还是一个类库,包含了与实体不同的数据类,其中仅有表示数据的属性,但是没有处理数据的方法,用来在表示层 Applicaiton.Web 和服务层 Application.Manager 之间进行通讯。数据传输对象是用来封装数据的对象,用来从系统的一个子系统将数据传递到另外一个子系统。这里我们使用 DTO 对象在 Manager 层和 UI 层之间传递数据。使用 DTO 的主要优点是可以在分布式的系统中减少数据的流量,在 MVC 模式中,也是重要的一个部分。我们也可以为方法的调用来封装数据,在方法包含4,5个以上的参数的时候,经常使用 DTO 来传递参数。


下一步,我们创建 Application.Manager 类库。

Application.Manager :

这个类库仅仅被 Applicaiton.Web 访问,对于我们在 Manager 中定义的每个模块,Manager 的主要职责是接受来自 UI 的请求,将数据传递到仓储中的领域对象中进行处理,将处理结果返回到界面层,这个层是 UI 层和仓储层之间的中间层。

Application.Web:

在前面的文章中,我们已经使用 javascript 中的模拟数据实现过该层。这里并不仅仅依赖于 ASP.NET MVC,界面可以包含用户的界面组件,像 HTML,.aspx, cshtml,MVC 等等,它也可以是是任何的 Windows 应用。这里通过方法与 Manager 层通讯,封装返回的结果,选择将错误信息显示在页面1 或者页面2 中。这个层使用 javascript 来家在表示层的模型,但实际的数据处理通过 ajax 请求发送到服务器处理,所以,服务器负责处理业务立即。而表示层处理表示逻辑问题。


要理解各层之间通讯的最好方式,就是让我们重温一下初始的需求。

Screen 1: 联系人列表 - 显示所有联系人

1.1 界面需要显示数据库中所有的联系人信息. 
1.2 用户可以删除联系人.
1.3 用户可以编辑联系人信息.
1.4 用户可以创建新的联系人.

为了填充表格中的数据,在页面加载的时候,我们调用 ContactController 的 GetAllProfiles() 方法,这个方法返回数据库中所有的联系人信息,然后以 JSON 的形式返回到页面,我们将数据以 self.Profiles 的形式绑定到一个 javascript 对象,下面就是 contact.js 代码中 GetAllProfiles() 方法的定义。

var ProfilesViewModel = function () {
var self = this;
var url = "/contact/GetAllProfiles";
var refresh = function () {
$.getJSON(url, {}, function (data) {
self.Profiles(data);
});
};

在点击删除按钮的时候,我们调用 ContactController 的 GetAllProfiles() 方法,这个方法从数据库中删除联系人信息。下面是 contact.js 中 DeleteProfile() 方法的定义。

self.removeProfile = function (profile) {
if (confirm("Are you sure you want to delete this profile?")) {
var id = profile.ProfileId;
waitingDialog({});
$.ajax({
type: 'DELETE', url: 'Contact/DeleteProfile/' + id,
success: function () { self.Profiles.remove(profile); },
error: function (err) {
var error = JSON.parse(err.responseText);
$("<div></div>").html(error.Message).dialog({ modal: true,
title: "Error", buttons: { "Ok":
function () { $(this).dialog("close"); } } }).show();
},
complete: function () { closeWaitingDialog(); }
});
}
};

对于创建和编辑按钮来说,我们仅仅重定向到 CreateEdit 页面,如果 id 参数是 0 表示创建新联系人,对于编辑来说,id 就是编辑的联系人编号了。下面的代码就是 contact.js 中 的 createProfile 和  editProfile 方法

self.createProfile = function () {
window.location.href = '/Contact/CreateEdit/0';
}; self.editProfile = function (profile) {
window.location.href = '/Contact/CreateEdit/' + profile.ProfileId;
};

下面的图展示了主要的三个层之间的关系。

Screen 2: 创建新联系人

界面提供一个空白的联系人界面,并且提供一下功能.

2.1 用户可以输入用户的姓,名,邮件地址
2.2 通过点击添加号码按钮,允许添加任何个电话号码
2.3 用户可以删除任意电话号码. 
2.4 通过点击添加地址按钮,允许添加任意多个地址. 
2.5 用户可以删除任意的地址. 
2.6 点击保存按钮,可以保存用户输入的所有信息到数据库中,然后回到联系人列表页面. 
2.7 点击返回按钮,可以回到联系人列表. 

Screen 3: 更新联系人信息

这个界面显示联系人的详细信息.

3.1 用户可以编辑联系人的姓,名,邮件地址.
3.2 用户可以通过点击添加,删除号码按钮来添加,删除用户的电话号码.
3.3 用户可以通过点击添加,删除地址按钮来添加,删除用户的地址。
3.4 点击保存可以将用户的详细信息更新到数据库中,然后返回联系人列表
3.5 点击返回按钮可以回到联系人列表

如前面的实现所见,创建和编辑的需求使用的是同一个页面 CreateEdit.cshtml,通过 profileId 来进行区分,如果 profileId 是 0,表示新建,否则,就是编辑存在的信息,下面是实现的细节。

在任何情况下,在页面加载和初始化 PhoneType 和 AddressType 的时候,在 ContactController 控制器的 InitializePageData() 方法中,在 CreateEdit.js 中的下列代码初始化数组。

var AddressTypeData;
var PhoneTypeData; $.ajax({
url: urlContact + '/InitializePageData',
async: false,
dataType: 'json',
success: function (json) {
AddressTypeData = json.lstAddressTypeDTO;
PhoneTypeData = json.lstPhoneTypeDTO;
}
});

然后,对于编辑联系人信息来说,我们需要获取详细信息,通过 ContactController 中的GetProfileById() 方法实现,我们修改 CreateEdit.js 。

$.ajax({
url: urlContact + '/GetProfileById/' + profileId,
async: false,
dataType: 'json',
success: function (json) {
self.profile = ko.observable(new Profile(json));
self.phoneNumbers = ko.observableArray(ko.utils.arrayMap(json.PhoneDTO, function (phone) {
return phone;
}));
self.addresses = ko.observableArray(ko.utils.arrayMap(json.AddressDTO, function (address) {
return address;
}));
}
});

最后,我们使用两个方法保存数据,如果我们是创建新的联系人,调用 ContactController 的 SaveProfileInformtion() 方法,否则调用 UpdateProfileInformation() 方法,我们将 CreateEdit.js 修改如下。

$.ajax({
type: (self.profile().ProfileId > 0 ? 'PUT' : 'POST'),
cache: false,
dataType: 'json',
url: urlContact + (self.profile().ProfileId > 0 ? '/UpdateProfileInformation?id=' +
self.profile().ProfileId : '/SaveProfileInformation'),
data: JSON.stringify(ko.toJS(self.profile())),
contentType: 'application/json; charset=utf-8',
async: false,
success: function (data) {
window.location.href = '/contact';
},
error: function (err) {
var err = JSON.parse(err.responseText);
var errors = "";
for (var key in err) {
if (err.hasOwnProperty(key)) {
errors += key.replace("profile.", "") + " : " + err[key];
}
}
$("<div></div>").html(errors).dialog({ modal: true,
title: JSON.parse(err.responseText).Message, buttons: { "Ok":
function () { $(this).dialog("close"); } } }).show();
},
complete: function () {
}
});

总结

就是这样,希望你喜欢这篇文章,我不是一个专家,我希望你享受这个系列并且能够学到些什么。

如果有任何问题欢迎进行讨论,谢谢。

How to use code

从这里可以下载数据库的脚本:
Application_DB.sql
   在 VS 中运行程序,需要启用 Allow NuGet to download missing packages during build ,

或者看下面的链接说明。

http://docs.nuget.org/docs/workflows/using-nuget-without-committing-packages

最后,修改你的 Application.Web 项目中的数据库连接串。

参考资料

  • http://knockoutjs.com/
  • https://github.com/ericmbarnard/Knockout-Validation/wiki/Configuration
  • http://twitter.github.com/bootstrap/
  • http://docs.castleproject.org/Windsor.MainPage.ashx
  • http://microsoftnlayerapp.codeplex.com/
  • http://msdn.microsoft.com/en-us/library/ff921348.aspx

Last edited Jan 18 at 6:41 AM by anandranjanpandey, version 5

使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 设计和开发站点 - 6 - 业务逻辑的更多相关文章

  1. 翻译:使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 设计和开发站点 - 6 - 业务逻辑

    Part 3: 设计逻辑层:核心开发 如前所述,我们的解决方案如下所示: 下面我们讨论整个应用的结构,根据应用中不同组件的逻辑相关性,分离到不同的层中,层与层之间的通讯通过或者不通过限制.分层属于架构 ...

  2. 翻译:使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 设计和开发站点 - 3

    原文地址:http://ddmvc4.codeplex.com/ 原文名称:Design and Develop a website using ASP.NET MVC 4, EF, Knockout ...

  3. 翻译:使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 设计和开发站点 - 1

    原文地址:http://ddmvc4.codeplex.com/ 原文名称:Design and Develop a website using ASP.NET MVC 4, EF, Knockout ...

  4. 翻译:使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 设计和开发站点 - 4 - 验证

    验证: 快要完成我们程序的界面部分了.剩下的事情就是在用户点击 "保存" 的时候管理验证问题了.验证是主要需求,今天就是最无知的应用也不会忽视它.通过正确的验证,用户可以知道应该输 ...

  5. 翻译:使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 设计和开发站点 - 5 - 数据库设计

    数据库方面我们需要的主要功能如下: 联系人有姓名和电子邮件地址. 联系人可以拥有多个地址. 联系人可以拥有多个电话. 为了实现目标,我们需要在数据库中创建下列表.表与表的关系如下图所示: 数据库的脚本 ...

  6. 翻译:使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 设计和开发站点 - 2

    我们的目标: 需求 Screen 1: 联系人列表 - 查看所有联系人 1.1 这个 screen 将显示数据库中的所有联系人. 1.2 用户可以删除任何联系人.1.3 用户可以编辑任何联系人的详细信 ...

  7. ASP.NET MVC和EF集成AngularJS开发

    参考资料: 如何在ASP.NET MVC和EF中使用AngularJS AngularJS+ASP.NET MVC+SignalR实现消息推送 [AngularJs + ASP.NET MVC]使用A ...

  8. ASP.NET MVC 中应用Windows服务以及Webservice服务开发分布式定时器

    ASP.NET MVC 中应用Windows服务以及Webservice服务开发分布式定时器一:闲谈一下:1.现在任务跟踪管理系统已经开发快要结束了,抽一点时间来写一下,想一想自己就有成就感啊!!  ...

  9. 如何在ASP.NET MVC和EF中使用AngularJS

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) AngularJS作为一个越来越流行的前端框架,在使用ASP.NET MVC和实体框架开发W ...

随机推荐

  1. Com组件的内存分配和释放,CredentialProvider SHStrDup 字符串拷贝问题

    一.简单介绍 熟悉CredentialProvider的同学应该知道,他为一个Com组件,于是,在这里的内存分配(字符串拷贝)的一系列操作就要依照con的标准来. 二.Com组件的内存分配和释放 CO ...

  2. CSS3+HTML5特效8 - 顶部和右侧固定,左侧随窗口变化的布局

    原文:CSS3+HTML5特效8 - 顶部和右侧固定,左侧随窗口变化的布局 效果演示 实现原理 使用3个div(一个是顶部栏,一个是左侧栏,一个是右侧栏): 使用checkbox作为判断是否显示和隐藏 ...

  3. struts2源代码分析(个人觉得非常经典)

    读者如果曾经学习过Struts1.x或者有过Struts1.x的开发经验,那么千万不要想当然地以为这一章可以跳过.实际上Struts1.x与Struts2并无我们想象的血缘关系.虽然Struts2的开 ...

  4. SQL_修改表结构

    ***********************************************声明*************************************************** ...

  5. php中echo(),print(),print_r()用法

    原文 php中echo(),print(),print_r()用法 从我对echo(),print(),print_r()这个函数的理解是echo可输入字符串变量常量,print与echo差不多,但p ...

  6. jquery.validate 以alert方式显示错误方法

    $.validator.setDefaults({ submitHandler: function() { alert("submitted!");return false; } ...

  7. JAVA学习课第五十三届 — IO流程(七)File打靶 &amp; Properties设置

    一个.锻炼 深度遍历目录 深度遍历非常自然而然想到递归,而递归就非常自然的想到事实上现的底层算法是栈 对指定文件夹下列出全部内容(包括子文件夹的内容) PS:建议不要遍历C盘 import java. ...

  8. elasticsearch集群搭建实例

    elasticsearch集群搭建实例 下个月又开始搞搜索了,几个月没动这块还好没有落下. 晚上在自己虚拟机上搭建了一个简易搜索集群,分享一下. 操作系统环境: Red Hat 4.8.2-16 el ...

  9. 使用hibernate在5秒内插入11万条数据,你觉得可能吗?

    需求是这样的,需要查询某几个表的数据,然后插入到另外一个表. 一看到需求,很多人都会用hibernate去把这些数据都查询出来,然后放到list中, 然后再用for循环之类的进行遍历,一条一条的取出数 ...

  10. Google Dataflow

    十分钟了解分布式计算:Google Dataflow 介绍 Google Cloud Dataflow是一种构建.管理和优化复杂数据处理流水线的方法,集成了许多内部技术,如用于数据高效并行化处理的Fl ...