# [.NET领域驱动设计实战系列]专题二:结合领域驱动设计的面向服务架构来搭建网上书店
## 一、前言
在前面专题一中,我已经介绍了我写这系列文章的初衷了。由于dax.net中的DDD框架和Byteart Retail案例并没有对其形成过程做一步步分析,而是把整个DDD的实现案例展现给我们,这对于一些刚刚接触领域驱动设计的朋友可能会非常迷茫,从而觉得领域驱动设计很难,很复杂,因为学习中要消化一个整个案例的知识,这样未免很多人消化不了就打退堂鼓,就不继续研究下去了,所以这样也不利于DDD的推广。然而本系列可以说是刚接触领域驱动设计朋友的福音,本系列将结合领域驱动设计的思想来一步步构建一个网上书店,从而让大家学习DDD不再枯燥和可以看到一个DDD案例的形成历程。最后,再DDD案例完成之后,将从中抽取一个领域驱动的框架,从而大家也可以看到一个DDD框架的形成历程,这样就不至于一下子消化一整个框架和案例的知识,而是一步步消化。接下来,该专题将介绍的是:结合领域驱动设计的SOA架构来构建网上书店,本专题中并没有完成网上书店的所有页面和覆盖DDD中的所有内容,而只是一部分,后面的专题将会在本专题的网上书店进行一步步完善,通过一步步引入DDD的内容和重构来完成整个项目。
## 二、DDD分层架构
从概念上说,领域驱动设计架构主要分为四层,分别为:基础设施层、领域层、应用层和表现层。
* 基础结构层:该层专为其他各层提供各项通用技术框架支持。像一些配置文件处理、缓存处理,事务处理等都可以放在这里。
* 领域层:简单地说就是业务所涉及的领域对象(包括实体、值对象)、领域服务等。该层就是所谓的领域模型了,领域驱动设计提倡是富领域模型,富领域模型指的是:尽量将业务逻辑放在归属于它的领域对象中。而之前的三层架构中的领域模型都是贫血领域模型,因为在三层中的领域模型只包含业务属性,而不包含任何业务逻辑。本专题的网上书店领域模型目前还没有包含任何业务逻辑,在后期将会完善。
**实体可以认为对应于数据库的表,而值对象一般定义在实体类中。**
* 应用层:该层不包含任何领域逻辑,它主要用来对任务进行协调,它构建了表现层和领域层的桥梁。SOA架构就是在该层进行实现的。
* 表现层:指的是用户界面,例如Asp.net mvc网站,WPF、Winform和控制台等。它主要用来想用户展现内容。
下面用一个图来形象展示DDD的分层架构:
![52029421305](https://box.kancloud.cn/2016-01-23_56a2eb4ae9d0c.gif)
本系列介绍的领域驱动设计实战,则自然少了领域驱动设计分层架构的实现了,上面简单介绍了领域驱动的分层架构,接下来将详细介绍在网上书店中各层是如何去实现的。
## 三、网上书店领域模型层的实现
在应用领域驱动设计的思想来构建一个项目,则第一步就是了解需求,明白项目的业务逻辑,了解清楚业务逻辑后,则把业务逻辑抽象成领域对象,领域对象所放在的位置也就是领域模型层了。该专题介绍的网上书店主要完成了商品所涉及的页面,包括商品首页,单个商品的详细信息等。所以这里涉及的领域实体包括2个,一个是商品类,另外一个就是类别类,因为在商品首页中,需要显示所有商品的类别。在给出领域对象的实现之前,这里需要介绍领域层中所涉及的几个概念。
* 聚合根:聚合根也是实体,但与实体不同的是,聚合根是由实体和值对象组成的系统边界对象。举个例子来说,例如订单和订单项,根据业务逻辑,我们需要跟踪订单和订单项的状态,所以设计它们都为实体,但只有订单才是聚合根对象,而订单项不是,因为订单项只有在订单中才有意义,意思就是说:用户不能直接看到订单项,而是先查询到订单,然后再看到该订单下的订单项。所以聚合根可以理解为用户直接操作的对象。在这里商品类和类别类都是一个聚合根。
根据面向接口编程原则,我们在领域模型中应该定义一个实体接口和聚合根接口,而因为聚合根也是属于实体,所以聚合根接口继承于实体接口,而商品类和类别类都是聚合根,所以它们都实现聚合根接口。如果像订单项只是实体不是聚合根的类则实现实体接口。有了上面的分析,则领域模型层的实现也就自然出来了,下面是领域对象的具体实现:
```
// 商品类
public class Product : AggregateRoot
{
public string Name { get; set; }
public string Description { get; set; }
public decimal UnitPrice { get; set; }
public string ImageUrl { get; set; }
public bool IsNew{ get; set; }
public override string ToString()
{
return Name;
}
}
```
```
// 类别类
public class Category : AggregateRoot
{
public string Name { get; set; }
public string Description { get; set; }
public override string ToString()
{
return this.Name;
}
}
```
另外,领域层除了实现领域对象外,还需要定义仓储接口,而仓储层则是对仓储接口的实现。仓储可以理解为在内存中维护一系列聚合根的集合,而聚合根不可能一直存在于内存中,当它不活动时会被持久化到数据中。而仓储层完成的任务是持久化聚合根对象到数据或从数据库中查询存储的对象来重新创建领域对象。
仓储层有几个需要明确的概念:
1. 仓储里面存放的对象一定是聚合根,因为领域模型是以聚合根的概念去划分的,聚合根就是我们操作对象的一个边界。所以我们都是对某个聚合根进行操作的,而不存在对聚合内的值对象进行操作。因此,仓储只针对聚合根设计。
2. 因为仓储只针对聚合根设计,所以一个聚合根需要实现一个仓储。
3. 不要把仓储简单理解为DAO,仓储属于领域模型的一部分,代表了领域模型向外界提供接口的一部分,而DAO是表示数据库向上层提供的接口表示。一个是针对领域模型而言,而另一个针对数据库而言。两者侧重点不一样。
4. 仓储分为定义部分和实现部分,在领域模型中定义仓储的接口,**而在基础设施层实现具体的仓储**。这样做的原因是:由于仓储背后的实现都是在和数据库打交道,但是我们又不希望客户(如应用层)把重点放在如何从数据库获取数据的问题上,因为这样做会导致客户(应用层)代码很混乱,很可能会因此而忽略了领域模型的存在。所以我们需要提供一个简单明了的接口,供客户使用,确保客户能以最简单的方式获取领域对象,从而可以让它专心的不会被什么数据访问代码打扰的情况下协调领域对象完成业务逻辑。这种通过接口来隔离封装变化的做法其实很常见。由于客户面对的是抽象的接口并不是具体的实现,所以我们可以随时替换仓储的真实实现,这很有助于我们做单元测试。在本专题的案例中,我们把仓储层的实现单独从基础设施层拎出来了,作为一个独立的层存在。这也就是为什么DDD分层中没有定义仓储层啊,而本专题的案例中多了一个仓储层的实现。
5. 仓储在设计查询接口时,会经常用到规约模式(Specification Pattern)。本专题的案例中没有给出,这点将会在后面专题添加上去。
6. 仓储一般不负责事务处理,一般事务处理会交给“工作单元(Unit Of Work)”去处理,同样本专题也没有涉及工作单元的实现,这点同样会在后面专题继续完善。这里列出来让大家对后面的专题可以有个清晰的概念,而不至于是空穴来风的。
介绍完仓储之后,接下来就在领域层中定义仓储接口,因为本专题中涉及到2个聚合根,则自然需要实现2个仓储接口。根据面向接口编程原则,我们让这2个仓储接口都实现与一个公共的接口:IRepository接口。另外仓储接口还需要定义一个仓储上下接口,因为在Entity Framework中有一个[DbContex](https://msdn.microsoft.com/zh-cn/library/system.data.entity.dbcontext%28v=vs.113%29.aspx?f=255&MSPPError=-2147217396)类,所以我们需要定义一个EntityFramework上下文对象来对DbContex进行包装。也就自然有了仓储上下文接口了。经过上面的分析,仓储接口的实现也就一目了然了。
```
// 仓储接口
public interface IRepository<TAggregateRoot>
where TAggregateRoot :class, IAggregateRoot
{
void Add(TAggregateRoot aggregateRoot);
IEnumerable<TAggregateRoot> GetAll();
// 根据聚合根的ID值,从仓储中读取聚合根
TAggregateRoot GetByKey(Guid key);
}
```
这样我们就完成了领域层的搭建了,接下面,我们就需要对领域层中定义的仓储接口进行实现了。我这里将仓储接口的实现单独弄出了一个层,当然你也可以放在基础设施层中的Repositories文件夹中。不过我看很多人都直接拎出来的。我这里也是直接作为一个层。
## 四、网上书店Repository(仓储)层的实现
定义完仓储接口之后,接下来就是在仓储层实现这些接口,完成领域对象的序列化。首先是产品仓储的实现:
```
// 商品仓储的实现
public class ProductRepository : IProductRepository
{
#region Private Fields
private readonly IEntityFrameworkRepositoryContext _efContext;
#endregion
#region Public Properties
public IEntityFrameworkRepositoryContext EfContext
{
get { return this._efContext; }
}
#endregion
#region Ctor
public ProductRepository(IRepositoryContext context)
{
var efContext = context as IEntityFrameworkRepositoryContext;
if (efContext != null)
this._efContext = efContext;
}
#endregion
public IEnumerable<Product> GetNewProducts(int count = 0)
{
var ctx = this.EfContext.DbContex as OnlineStoreDbContext;
if (ctx == null)
return null;
var query = from p in ctx.Products
where p.IsNew == true
select p;
if (count == 0)
return query.ToList();
else
return query.Take(count).ToList();
}
public void Add(Product aggregateRoot)
{
throw new NotImplementedException();
}
public IEnumerable<Product> GetAll()
{
var ctx = this.EfContext.DbContex as OnlineStoreDbContext;
if (ctx == null)
return null;
var query = from p in ctx.Products
select p;
return query.ToList();
}
public Product GetByKey(Guid key)
{
return EfContext.DbContex.Products.First(p => p.Id == key);
}
}
```
接下来是类别仓储的实现:
```
// 类别仓储的实现
public class CategoryRepository :ICategoryRepository
{
#region Private Fields
private readonly IEntityFrameworkRepositoryContext _efContext;
public CategoryRepository(IRepositoryContext context)
{
var efContext = context as IEntityFrameworkRepositoryContext;
if (efContext != null)
this._efContext = efContext;
}
#endregion
#region Public Properties
public IEntityFrameworkRepositoryContext EfContext
{
get { return this._efContext; }
}
#endregion
public void Add(Category aggregateRoot)
{
throw new System.NotImplementedException();
}
public IEnumerable<Category> GetAll()
{
var ctx = this.EfContext.DbContex as OnlineStoreDbContext;
if (ctx == null)
return null;
var query = from c in ctx.Categories
select c;
return query.ToList();
}
public Category GetByKey(Guid key)
{
return this.EfContext.DbContex.Categories.First(c => c.Id == key);
}
}
```
由于后期除了实现基于EF仓储的实现外,还想实现基于MongoDb仓储的实现,所以在仓储层中创建了一个EntityFramework的文件夹,并定义了一个IEntityFrameworkRepositoryContext接口来继承于IRepositoryContext接口,由于EF中持久化数据主要是由DbContext对象来完成了,为了有自己框架模型,我在这里定义了OnlineStoreDbContext来继承DbContext,从而用OnlineStoreDbContext来对DbContext进行了一次包装。经过上面的分析之后,接下来对于实现也就一目了然了。首先是OnlineStoreDbContext类的实现:
```
public sealed class OnlineStoreDbContext : DbContext
{
#region Ctor
public OnlineStoreDbContext()
: base("OnlineStore")
{
this.Configuration.AutoDetectChangesEnabled = true;
this.Configuration.LazyLoadingEnabled = true;
}
#endregion
#region Public Properties
public DbSet<Product> Products
{
get { return this.Set<Product>(); }
}
public DbSet<Category> Categories
{
get { return this.Set<Category>(); }
}
// 后面会继续添加属性,针对每个聚合根都会定义一个DbSet的属性
// ...
#endregion
}
```
接下来就是IEntityFrameworkRepositoryContext接口的定义以及它的实现了。具体代码如下所示:
```
public class EntityFrameworkRepositoryContext : IEntityFrameworkRepositoryContext
{
// 引用我们定义的OnlineStoreDbContext类对象
public OnlineStoreDbContext DbContex
{
get { return new OnlineStoreDbContext(); }
}
}
```
这样,我们的仓储层也就完成了。接下来就是应用层的实现。
## 五、网上书店应用层的实现
应用层应用了面向服务结构进行实现,采用了微软面向服务的实现WCF来完成的。网上书店的整个架构完全遵循着领域驱动设计的分层架构,用户通过UI层(这里实现的是Web页面)来进行操作,然后UI层调用应用层来把服务进行分发,通过调用基础设施层中仓储实现来对领域对象进行持久化和重建。这里应用层主要采用WCF来实现的,其中引用了仓储接口。针对服务而言,首先就需要定义服务契约了,这里我把服务契约的定义单独放在了一个服务契约层,当然你也可以在应用层中创建一个服务契约文件夹。首先就去看看服务契约的定义:
```
// 商品服务契约的定义
[ServiceContract(Namespace="")]
public interface IProductService
{
#region Methods
// 获得所有商品的契约方法
[OperationContract]
IEnumerable<Product> GetProducts();
// 获得新上市的商品的契约方法
[OperationContract]
IEnumerable<Product> GetNewProducts(int count);
// 获得所有类别的契约方法
[OperationContract]
IEnumerable<Category> GetCategories();
// 根据商品Id来获得商品的契约方法
[OperationContract]
Product GetProductById(Guid id);
#endregion
}
```
接下来就是服务契约的实现,服务契约的实现我放在应用层中,具体的实现代码如下所示:
```
// 商品服务的实现
public class ProductServiceImp : IProductService
{
#region Private Fields
private readonly IProductRepository _productRepository;
private readonly ICategoryRepository _categoryRepository;
#endregion
#region Ctor
public ProductServiceImp(IProductRepository productRepository, ICategoryRepository categoryRepository)
{
_categoryRepository = categoryRepository;
_productRepository = productRepository;
}
#endregion
#region IProductService Members
public IEnumerable<Product> GetProducts()
{
return _productRepository.GetAll();
}
public IEnumerable<Product> GetNewProducts(int count)
{
return _productRepository.GetNewProducts(count);
}
public IEnumerable<Category> GetCategories()
{
return _categoryRepository.GetAll();
}
public Product GetProductById(Guid id)
{
var product = _productRepository.GetByKey(id);
return product;
}
#endregion
}
```
最后就是创建WCF服务来调用服务契约实现了。创建一个后缀为.svc的WCF服务文件,WCF服务的具体实现如下所示:
```
// 商品WCF服务
public class ProductService : IProductService
{
// 引用商品服务接口
private readonly IProductService _productService;
public ProductService()
{
_productService = ServiceLocator.Instance.GetService<IProductService>();
}
public IEnumerable<Product> GetProducts()
{
return _productService.GetProducts();
}
public IEnumerable<Product> GetNewProducts(int count)
{
return _productService.GetNewProducts(count);
}
public IEnumerable<Category> GetCategories()
{
return _productService.GetCategories();
}
public Product GetProductById(Guid id)
{
return _productService.GetProductById(id);
}
}
```
到这里我们就完成了应用层面向服务架构的实现了。从商品的WCF服务实现可以看到,我们有一个ServiceLocator的类。这个类的实现采用服务定位器模式,关于该模式的介绍可以参考d[ax.net的服务定位器模式](http://www.cnblogs.com/daxnet/archive/2013/01/05/2846055.html)的介绍。该类的作用就是调用方具体的实例,简单地说就是通过服务接口定义具体服务接口的实现,将该实现返回给调用者的。这个类我这里放在了基础设施层来实现。目前基础设施层只有这一个类的实现,后期会继续添加其他功能,例如缓存功能的支持。
另外,在这里使用了Unity依赖注入容器来对接口进行注入。主要的配置文件如下所示:
```
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework"/>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
<!-- Entity Framework 配置信息-->
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
<parameters>
<parameter value="Data Source=(LocalDb)\v11.0; Initial Catalog=OnlineStore; Integrated Security=True; Connect Timeout=120; MultipleActiveResultSets=True; AttachDBFilename=|DataDirectory|\OnlineStore.mdf"/>
</parameters>
</defaultConnectionFactory>
</entityFramework>
<!--Unity的配置信息-->
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
<!--仓储接口的注册-->
<register type="OnlineStore.Domain.Repositories.IRepositoryContext, OnlineStore.Domain" mapTo="OnlineStore.Repositories.EntityFramework.EntityFrameworkRepositoryContext, OnlineStore.Repositories"/>
<register type="OnlineStore.Domain.Repositories.IProductRepository, OnlineStore.Domain" mapTo="OnlineStore.Repositories.EntityFramework.ProductRepository, OnlineStore.Repositories"/>
<register type="OnlineStore.Domain.Repositories.ICategoryRepository, OnlineStore.Domain" mapTo="OnlineStore.Repositories.EntityFramework.CategoryRepository, OnlineStore.Repositories"/>
<!--应用服务的注册-->
<register type="OnlineStore.ServiceContracts.IProductService, OnlineStore.ServiceContracts" mapTo="OnlineStore.Application.ServiceImplementations.ProductServiceImp, OnlineStore.Application"/>
</container>
</unity>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5"/>
<httpRuntime targetFramework="4.5.1"/>
</system.web>
<!--WCF 服务的配置信息-->
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="OnlineStore.Application.ServiceImplementations.ProductServiceImp" behaviorConfiguration="">
<endpoint address="" binding="wsHttpBinding" contract="OnlineStore.ServiceContracts.IProductService"/>
<!--<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />-->
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
```
## 六、基础设施层的实现
基础设施层在本专题中只包含了服务定位器的实现,后期会继续添加对其他功能的支持,ServiceLocator类的具体实现如下所示:
```
// 服务定位器的实现
public class ServiceLocator : IServiceProvider
{
private readonly IUnityContainer _container;
private static ServiceLocator _instance = new ServiceLocator();
private ServiceLocator()
{
_container = new UnityContainer();
_container.LoadConfiguration();
}
public static ServiceLocator Instance
{
get { return _instance; }
}
#region Public Methods
public T GetService<T>()
{
return _container.Resolve<T>();
}
public IEnumerable<T> ResolveAll<T>()
{
return _container.ResolveAll<T>();
}
public T GetService<T>(object overridedArguments)
{
var overrides = GetParameterOverrides(overridedArguments);
return _container.Resolve<T>(overrides.ToArray());
}
public object GetService(Type serviceType, object overridedArguments)
{
var overrides = GetParameterOverrides(overridedArguments);
return _container.Resolve(serviceType, overrides.ToArray());
}
#endregion
#region Private Methods
private IEnumerable<ParameterOverride> GetParameterOverrides(object overridedArguments)
{
var overrides = new List<ParameterOverride>();
var argumentsType = overridedArguments.GetType();
argumentsType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.ToList()
.ForEach(property =>
{
var propertyValue = property.GetValue(overridedArguments, null);
var propertyName = property.Name;
overrides.Add(new ParameterOverride(propertyName, propertyValue));
});
return overrides;
}
#endregion
#region IServiceProvider Members
public object GetService(Type serviceType)
{
return _container.Resolve(serviceType);
}
#endregion
}
```
## 七、UI层的实现
根据领域驱动的分层架构,接下来自然就是UI层的实现了,这里UI层的实现采用Asp.net MVC 技术来实现的。UI层主要包括商品首页的实现,和详细商品的实现,另外还有一些附加页面的实现,例如,关于页面,联系我们页面等。关于UI层的实现,这里就不一一贴出代码实现了,大家可以在最后的源码链接自行下载查看。
## 八、系统总体架构
经过上面的所有步骤,本专题中的网上书店构建工作就基本完成了,接下来我们来看看网上书店的总体架构图(这里架构图直接借鉴了dax.net的图了,因为本系列文章也是对其Byteart Retail项目的剖析过程):
![](http://images.cnblogs.com/cnblogs_com/daxnet/201211/201211131559014210.png)
最后附上整个解决方案的结构图:
![](https://box.kancloud.cn/2016-01-23_56a2eb4b08198.png)
## 九、网上书店运行效果
实现完之后,大家是不是都已经迫不及待地想看到网上书店的运行效果呢?下面就为大家来揭晓,目前网上书店主要包括2个页面,一个是商品首页的展示和商品详细信息的展示。首先看下商品首页的样子吧:
![](https://box.kancloud.cn/2016-01-23_56a2eb4b1be46.png)
图书的详细信息页面:
![](https://box.kancloud.cn/2016-01-23_56a2eb4b4bebf.png)
## 十、总结
到这里,本专题的内容就介绍完了, 本专题主要介绍面向领域驱动设计的分层架构和面向服务架构。然后结合它们在网上书店中进行实战演练。在后面的专题中我会在该项目中一直进行完善,从而形成一个完整了DDD案例。在接下来的专题会对仓储的实现应用规约模式,在应用之前,我会先写一个专题来介绍规约模式来作为一个准备工作。
GitHub 开源地址:[https://github.com/lizhi5753186/OnlineStore](https://github.com/lizhi5753186/OnlineStore)。
- C# 基础知识系列
- C# 基础知识系列 专题一:深入解析委托——C#中为什么要引入委托
- C# 基础知识系列 专题二:委托的本质论
- C# 基础知识系列 专题三:如何用委托包装多个方法——委托链
- C# 基础知识系列 专题四:事件揭秘
- C# 基础知识系列 专题五:当点击按钮时触发Click事件背后发生的事情
- C# 基础知识系列 专题六:泛型基础篇——为什么引入泛型
- C# 基础知识系列 专题七: 泛型深入理解(一)
- C# 基础知识系列 专题八: 深入理解泛型(二)
- C# 基础知识系列 专题九: 深入理解泛型可变性
- C#基础知识系列 专题十:全面解析可空类型
- C# 基础知识系列 专题十一:匿名方法解析
- C#基础知识系列 专题十二:迭代器
- C#基础知识 专题十三:全面解析对象集合初始化器、匿名类型和隐式类型
- C# 基础知识系列 专题十四:深入理解Lambda表达式
- C# 基础知识系列 专题十五:全面解析扩展方法
- C# 基础知识系列 专题十六:Linq介绍
- C#基础知识系列 专题十七:深入理解动态类型
- 你必须知道的异步编程 C# 5.0 新特性——Async和Await使异步编程更简单
- 全面解析C#中参数传递
- C#基础知识系列 全面解析C#中静态与非静态
- C# 基础知识系列 C#中易混淆的知识点
- C#进阶系列
- C#进阶系列 专题一:深入解析深拷贝和浅拷贝
- C#进阶系列 专题二:你知道Dictionary查找速度为什么快吗?
- C# 开发技巧系列
- C# 开发技巧系列 使用C#操作Word和Excel程序
- C# 开发技巧系列 使用C#操作幻灯片
- C# 开发技巧系列 如何动态设置屏幕分辨率
- C# 开发技巧系列 C#如何实现图片查看器
- C# 开发技巧 如何防止程序多次运行
- C# 开发技巧 实现属于自己的截图工具
- C# 开发技巧 如何使不符合要求的元素等于离它最近的一个元素
- C# 线程处理系列
- C# 线程处理系列 专题一:线程基础
- C# 线程处理系列 专题二:线程池中的工作者线程
- C# 线程处理系列 专题三:线程池中的I/O线程
- C# 线程处理系列 专题四:线程同步
- C# 线程处理系列 专题五:线程同步——事件构造
- C# 线程处理系列 专题六:线程同步——信号量和互斥体
- C# 多线程处理系列专题七——对多线程的补充
- C#网络编程系列
- C# 网络编程系列 专题一:网络协议简介
- C# 网络编程系列 专题二:HTTP协议详解
- C# 网络编程系列 专题三:自定义Web服务器
- C# 网络编程系列 专题四:自定义Web浏览器
- C# 网络编程系列 专题五:TCP编程
- C# 网络编程系列 专题六:UDP编程
- C# 网络编程系列 专题七:UDP编程补充——UDP广播程序的实现
- C# 网络编程系列 专题八:P2P编程
- C# 网络编程系列 专题九:实现类似QQ的即时通信程序
- C# 网络编程系列 专题十:实现简单的邮件收发器
- C# 网络编程系列 专题十一:实现一个基于FTP协议的程序——文件上传下载器
- C# 网络编程系列 专题十二:实现一个简单的FTP服务器
- C# 互操作性入门系列
- C# 互操作性入门系列(一):C#中互操作性介绍
- C# 互操作性入门系列(二):使用平台调用调用Win32 函数
- C# 互操作性入门系列(三):平台调用中的数据封送处理
- C# 互操作性入门系列(四):在C# 中调用COM组件
- CLR
- 谈谈: String 和StringBuilder区别和选择
- 谈谈:程序集加载和反射
- 利用反射获得委托和事件以及创建委托实例和添加事件处理程序
- 谈谈:.Net中的序列化和反序列化
- C#设计模式
- UML类图符号 各种关系说明以及举例
- C#设计模式(1)——单例模式
- C#设计模式(2)——简单工厂模式
- C#设计模式(3)——工厂方法模式
- C#设计模式(4)——抽象工厂模式
- C#设计模式(5)——建造者模式(Builder Pattern)
- C#设计模式(6)——原型模式(Prototype Pattern)
- C#设计模式(7)——适配器模式(Adapter Pattern)
- C#设计模式(8)——桥接模式(Bridge Pattern)
- C#设计模式(9)——装饰者模式(Decorator Pattern)
- C#设计模式(10)——组合模式(Composite Pattern)
- C#设计模式(11)——外观模式(Facade Pattern)
- C#设计模式(12)——享元模式(Flyweight Pattern)
- C#设计模式(13)——代理模式(Proxy Pattern)
- C#设计模式(14)——模板方法模式(Template Method)
- C#设计模式(15)——命令模式(Command Pattern)
- C#设计模式(16)——迭代器模式(Iterator Pattern)
- C#设计模式(17)——观察者模式(Observer Pattern)
- C#设计模式(18)——中介者模式(Mediator Pattern)
- C#设计模式(19)——状态者模式(State Pattern)
- C#设计模式(20)——策略者模式(Stragety Pattern)
- C#设计模式(21)——责任链模式
- C#设计模式(22)——访问者模式(Vistor Pattern)
- C#设计模式(23)——备忘录模式(Memento Pattern)
- C#设计模式总结
- WPF快速入门系列
- WPF快速入门系列(1)——WPF布局概览
- WPF快速入门系列(2)——深入解析依赖属性
- WPF快速入门系列(3)——深入解析WPF事件机制
- WPF快速入门系列(4)——深入解析WPF绑定
- WPF快速入门系列(5)——深入解析WPF命令
- WPF快速入门系列(6)——WPF资源和样式
- WPF快速入门系列(7)——深入解析WPF模板
- WPF快速入门系列(8)——MVVM快速入门
- WPF快速入门系列(9)——WPF任务管理工具实现
- ASP.NET 开发
- ASP.NET 开发必备知识点(1):如何让Asp.net网站运行在自定义的Web服务器上
- ASP.NET 开发必备知识点(2):那些年追过的ASP.NET权限管理
- ASP.NET中实现回调
- 跟我一起学WCF
- 跟我一起学WCF(1)——MSMQ消息队列
- 跟我一起学WCF(2)——利用.NET Remoting技术开发分布式应用
- 跟我一起学WCF(3)——利用Web Services开发分布式应用
- 跟我一起学WCF(3)——利用Web Services开发分布式应用
- 跟我一起学WCF(4)——第一个WCF程序
- 跟我一起学WCF(5)——深入解析服务契约 上篇
- 跟我一起学WCF(6)——深入解析服务契约 下篇
- 跟我一起学WCF(7)——WCF数据契约与序列化详解
- 跟我一起学WCF(8)——WCF中Session、实例管理详解
- 跟我一起学WCF(9)——WCF回调操作的实现
- 跟我一起学WCF(10)——WCF中事务处理
- 跟我一起学WCF(11)——WCF中队列服务详解
- 跟我一起学WCF(12)——WCF中Rest服务入门
- 跟我一起学WCF(13)——WCF系列总结
- .NET领域驱动设计实战系列
- .NET领域驱动设计实战系列 专题一:前期准备之EF CodeFirst
- .NET领域驱动设计实战系列 专题二:结合领域驱动设计的面向服务架构来搭建网上书店
- .NET领域驱动设计实战系列 专题三:前期准备之规约模式(Specification Pattern)
- .NET领域驱动设计实战系列 专题四:前期准备之工作单元模式(Unit Of Work)
- .NET领域驱动设计实战系列 专题五:网上书店规约模式、工作单元模式的引入以及购物车的实现
- .NET领域驱动设计实战系列 专题六:DDD实践案例:网上书店订单功能的实现
- .NET领域驱动设计实战系列 专题七:DDD实践案例:引入事件驱动与中间件机制来实现后台管理功能
- .NET领域驱动设计实战系列 专题八:DDD案例:网上书店分布式消息队列和分布式缓存的实现
- .NET领域驱动设计实战系列 专题九:DDD案例:网上书店AOP和站点地图的实现
- .NET领域驱动设计实战系列 专题十:DDD扩展内容:全面剖析CQRS模式实现
- .NET领域驱动设计实战系列 专题十一:.NET 领域驱动设计实战系列总结