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

文章转载于:http://www.cnblogs.com/haogj/

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

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

    翻译:使用 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操作过滤器记录日志

    [翻译] 使用ASP.NET MVC操作过滤器记录日志 原文地址:http://www.singingeels.com/Articles/Logging_with_ASPNET_MVC_Action_ ...

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

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

随机推荐

  1. 11、Struts2 的文件上传和下载

    文件上传 表单准备 要想使用 HTML 表单上传一个或多个文件 须把 HTML 表单的 enctype 属性设置为 multipart/form-data 须把 HTML 表单的method 属性设置 ...

  2. Hawk 7. 常见问题

    本页面您可以通过关键字搜索来获取信息. 理性使用爬虫 爬虫是一种灰色的应用,虽然作为Hawk的设计者,但我依然不得不这么说. 各大网站都在收集和整理数据上花费了大量的精力,因此抓取的数据应当仅仅作为科 ...

  3. 来吧,HTML5之基础标签(上)

    什么是html5 HTML 5 是下一代的 HTML.HTML5 仍处于完善之中.然而,大部分现代浏览器已经具备了某些 HTML5 支持. 学习过程中标签的理解 <a>标签  定义超链接, ...

  4. Log4net - 规则简介

    参考页面: http://www.yuanjiaocheng.net/CSharp/csharprumenshili.html http://www.yuanjiaocheng.net/entity/ ...

  5. VS2015使用scanf报错的解决方案

    1.在程序最前面加: #define _CRT_SECURE_NO_DEPRECATE 2.在程序最前面加: #pragma warning(disable:4996) 3.把scanf改为scanf ...

  6. [数据结构]——堆(Heap)、堆排序和TopK

    堆(heap),是一种特殊的数据结构.之所以特殊,因为堆的形象化是一个棵完全二叉树,并且满足任意节点始终不大于(或者不小于)左右子节点(有别于二叉搜索树Binary Search Tree).其中,前 ...

  7. 【Java每日一题】20170103

    20161230问题解析请点击今日问题下方的"[Java每日一题]20170103"查看(问题解析在公众号首发,公众号ID:weknow619) package Jan2017; ...

  8. Android之使用文件进行IPC

    一.文件进行IPC介绍 共享文件也是一种不错的进程间通信方式,两个进程通过读/写同一个文件来交换数据.在Windows上,一个文件如果被加了排斥锁将会导致其他线程无法对其进行访问,包括读写,而由于An ...

  9. android Handler介绍

    Handler使用介绍: Handler根据接收的消息,处理UI更新.Thread线程发出消息,通知Handler更新UI. Handler mHandler = new Handler() {  p ...

  10. java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE

    Android发出HTTP请求时出现了这个错误: java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INST ...