WCF搭建

前言:前面三篇分享了下DDD里面的两个主要特性:聚合和仓储。领域层的搭建基本完成,当然还涉及到领域事件和领域服务的部分,后面再项目搭建的过程中慢慢引入,博主的思路是先将整个架构走通,然后一步一步来添加相关元素,使架构慢慢变得丰满。这篇打算分享下应用层的搭建。根据DDD的设计原则,应用层不包含任何领域逻辑,它主要的作用是协调任务,或者叫调度任务,维护应用程序状态。根据博主的理解,应用层是用来隔离领域层的,假设没有应用层,那么我们的界面层可以直接调用领域层的逻辑,也就是说可以直接访问领域的model,这样的坏处显而易见:一是领域model不是纯粹的数据model,它含有领域的行为,直接将其传到前台会造成调用的混乱;二是仓储是和数据持久化打交道了,界面直接调用仓储,也就是界面直接和数据打交道,也不符合一般分层的原则。所以我们引入应用层,本文应用层是一个以控制台项目为宿主的WCF服务。我们来看代码设计。

一、WCF简介

WCF(Windows Communication Foundation)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口,它是.NET框架的一部分。由 .NET Framework 3.0 开始引入。WCF的最终目标是通过进程或不同的系统、通过本地网络或是通过Internet收发客户和服务之间的消息。关于WCF的理论知识,需要我们了解的是经典的ABC。

  • Address: 每一个WCF的Service都有一个唯一的地址。这个地址给出了Service的地址和传输协议(Transport Protocol)。
  • Binding:绑定制定了服务通过什么形式访问。只要类比传输协议, encoding (text, binary, etc) 以及 WS-* 协议,像transactional支持以及可信任的消息队列。
  • Contract:Contract描述了Service能提供的各种服务。Contract有四种,包括Service Contract, Data Contract, Fault Contract和Message Contract。

关于WCF的理论在此就不再展开,下面结合我们的项目代码我们从零开始一步一步来搭建一个自己的WCF服务吧。

二、WCF代码示例

1、代码结构图

项目按照模块为单位划分服务,比如权限模块,我们就有一个权限的接口契约IPowerManageWCFService。IService文件夹里面放了3个接口,分别对应系统3个模块的接口契约,Service文件夹里面分别对应了3个接口的实现。ServiceAttribute.cs里面定义了两个特性,表示接口是WCF的服务。我们来看看具体的代码。

2、代码示例

2.1 ServiceAttribute.cs文件定义契约接口和实现的特性类:

namespace ESTM.WCF.Service
{
//标记此特性的为WCF服务接口
public class ServiceInterfaceAttribute : Attribute
{
} //标记此特性的为WCF服务接口实现类
public class ServiceClassAttribute : Attribute
{
}
}

2.2 接口契约代码:

    /// <summary>
/// 工厂布局模块接口契约
/// </summary>
[ServiceInterface]
[ServiceContract]
public interface IFactoryLayoutWCFService
{
[OperationContract]
List<DTO_TM_PLANT> GetAllPlant();
}
    /// <summary>
/// 权限管理模块接口契约
/// </summary>
[ServiceContract]
[ServiceInterface]
public interface IPowerManageWCFService
{
[OperationContract]
IList<DTO_TB_DEPARTMENT> GetAllDepartment();
}
    /// <summary>
/// 产品管理模块接口契约
/// </summary>
[ServiceContract]
[ServiceInterface]
public interface IProductWCFService
{
[OperationContract]
IList<DTO_TP_PRODUCT> GetAllProduct();
}

接口契约[ServiceContract]表示该接口遵守接口契约协定,[OperationContract]操作契约,这两个特性都是WCF内置的东西。[ServiceInterface]的用处我们待会说。

2.3 接口实现代码

    [ServiceClass]
public class FactoryLayoutWCFService : IFactoryLayoutWCFService
{
public List<DTO_TM_PLANT> GetAllPlant()
{
throw new NotImplementedException();
}
}
    [ServiceClass]
public class ProductWCFService : IProductWCFService
{
public IList<DTO_TP_PRODUCT> GetAllProduct()
{
throw new NotImplementedException();
}
}
    [ServiceClass]
public class PowerManageWCFService : IPowerManageWCFService
{
public IList<DTO_TB_DEPARTMENT> GetAllDepartment()
{
throw new NotImplementedException();
}
}

[ServiceClass]特性和接口上面的[ServiceInterface]特性对应,用于标记契约和实现。

2.4 Bootstrapper.cs里面定义了服务的启动方法

   public class Bootstrapper
{
private string strBaseServiceUrl = ConfigurationManager.AppSettings["ServiceUrl"].ToString(); //启动所有的服务
public void StartServices()
{
//1.读取此程序集里面的有服务契约的接口和实现类
var assembly = Assembly.Load(typeof(Bootstrapper).Namespace);
var lstType = assembly.GetTypes();
var lstTypeInterface = new List<Type>();
var lstTypeClass = new List<Type>();
foreach (var oType in lstType)
{
//2.通过接口上的特性取到需要的接口和实现类
var lstCustomAttr = oType.CustomAttributes;
if (lstCustomAttr.Count() <= 0)
{
continue;
}
var oInterfaceServiceAttribute = lstCustomAttr.FirstOrDefault(x => x.AttributeType.Equals(typeof(ServiceInterfaceAttribute)));
if (oInterfaceServiceAttribute != null)
{
lstTypeInterface.Add(oType);
continue;
}
var oClassServiceAttribute = lstCustomAttr.FirstOrDefault(x => x.AttributeType.Equals(typeof(ServiceClassAttribute)));
if (oClassServiceAttribute != null)
{
lstTypeClass.Add(oType);
}
} //3.启动所有服务
foreach (var oInterfaceType in lstTypeInterface)
{
         //通过反射找到接口的实现类,找到配对然后启动服务
var lstTypeClassTmp = lstTypeClass.Where(x => x.GetInterface(oInterfaceType.Name) != null).ToList();
if (lstTypeClassTmp.Count <= 0)
{
continue;
}
if(lstTypeClassTmp[0].GetInterface(oInterfaceType.Name).Equals(oInterfaceType))
{
var oTask = Task.Factory.StartNew(() =>
{
OpenService(strBaseServiceUrl + "/" + oInterfaceType.Name, oInterfaceType, lstTypeClassTmp[0]);
});
}
}
} //通过服务接口类型和实现类型启动WCF服务
private void OpenService(string strServiceUrl, Type typeInterface, Type typeclass)
{
Uri httpAddress = new Uri(strServiceUrl);
using (ServiceHost host = new ServiceHost(typeclass))
{
///////////////////////////////////////添加服务节点///////////////////////////////////////////////////
host.AddServiceEndpoint(typeInterface, new WSHttpBinding(), httpAddress);
if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
{
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = httpAddress;
host.Description.Behaviors.Add(behavior);
}
host.Opened += delegate
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("服务启动成功。服务地址:" + strServiceUrl);
}; host.Open();
while (true)
{
Console.ReadLine();
}
}
}
}

对应的App.Config里面对应的服务的URL

  <appSettings>
<add key="ServiceUrl" value="http://127.0.0.1:1234/MyWCF.Server"/>
</appSettings>

StartServices()方法通过反射和两个特性[ServiceClass]与[ServiceInterface],依次启动三个服务。

然后再Program里面调用

     static void Main(string[] args)
{
var oBootstrapper = new Bootstrapper();
oBootstrapper.StartServices();
Console.ReadLine();
}

得到结果:

我们随便选择一个服务,通过浏览器访问,测试服务是否启动成功。

至此,WCF服务基本完成。

三、DTO说明

DTO,全称Data Transfer Object,数据传输对象。DTO是一个贫血模型,也就是它里面基本没有方法,只有一堆属性,并且所有属性都具有public的getter和setter访问器。为什么需要一个DTO对象?这个问题在C#进阶系列——MEF实现设计上的“松耦合”(终结篇:面向接口编程)这篇里面介绍过,它的作用其实很单一,就是用于数据传递和数据绑定。至于DTO如何设计,博主的项目里,DTO是按照聚合来划分的,也就是一个聚合对应一个DTO,DTO里面属性的定义可以根据项目需求来定。我们来看看代码:

    /// <summary>
/// 所有DTO model的父类,用作泛型约束
/// </summary>
[DataContract]
public class DTO_BASEMODEL
{
}
/// <summary>
/// TB_DEPARTMENT
/// </summary>
[DataContract]
public class DTO_TB_DEPARTMENT : DTO_BASEMODEL
{
[DataMember]
public string DEPARTMENT_ID { get; set; } [DataMember]
public string DEPARTMENT_NAME { get; set; } [DataMember]
public string PARENT_ID { get; set; } [DataMember]
public string DEPARTMENT_LEVEL { get; set; } [DataMember]
public string STATUS { get; set; }
}

其他DTO都和这个类似,就不一一列举了。由于DTO需要由WCF传递到Web前台,所以要求这个对象可以序列化,需要标记[DataContract]和[DataMember]两个特性,DTO_BASEMODEL作为所有DTO的父类, 用作泛型约束和定义DTO的一些公用特性。到此,WCF的搭建基本完成,下篇我们来介绍下Automapper的使用。累死我了,今天先到这吧,也不早了,博主也要安歇了。晚安!

还是附上 源码 吧,要不然园友们要说博主小气呢~~有兴趣可以看看。

 
分类: C#.Net

WCF搭建的更多相关文章

  1. C#进阶系列——DDD领域驱动设计初探(四):WCF搭建

    前言:前面三篇分享了下DDD里面的两个主要特性:聚合和仓储.领域层的搭建基本完成,当然还涉及到领域事件和领域服务的部分,后面再项目搭建的过程中慢慢引入,博主的思路是先将整个架构走通,然后一步一步来添加 ...

  2. 支持ajax跨域调用的WCF搭建示例

    支持ajax 跨域调用的WCF搭建 1.新建一个"ASP.NET空Web应用程序"项目. 2.新建一个“WCF服务(支持ajax)”. 3.修改WCFAjaxService.svc ...

  3. DDD领域驱动设计初探(四):WCF搭建

    前言:前面三篇分享了下DDD里面的两个主要特性:聚合和仓储.领域层的搭建基本完成,当然还涉及到领域事件和领域服务的部分,后面再项目搭建的过程中慢慢引入,博主的思路是先将整个架构走通,然后一步一步来添加 ...

  4. 利用WCF搭建RESTful--纯代码启动

    最近学习了这几年忽略了的当前几乎所有的开发技术,有深有浅,而服务层最有兴趣的是RESTfull,看的是java的书.因为不熟悉JSP,于是找了本书细细研读了一次. dotnet的实现也相对简单,网上也 ...

  5. .Net MVC框架 + WCF 搭建 集群开发

    http://www.cnblogs.com/zhijianliutang/archive/2012/01/28/2258844.html

  6. WCF快速搭建Demo

    WCF快速搭建Demo ps:本Demo只是演示如何快速建立WCF 1.首先完成IBLL.BLL.Model层的搭建,由于数据访问层不是重点,WCF搭建才是主要内容,所以本Demo略去数据访问层. 新 ...

  7. C#进阶系列——DDD领域驱动设计初探(七):Web层的搭建

    前言:好久没更新博客了,每天被该死的业务缠身,今天正好一个模块完成了,继续来完善我们的代码.之前的六篇完成了领域层.应用层.以及基础结构层的部分代码,这篇打算搭建下UI层的代码. DDD领域驱动设计初 ...

  8. Web层的搭建

    Web层的搭建 前言:好久没更新博客了,每天被该死的业务缠身,今天正好一个模块完成了,继续来完善我们的代码.之前的六篇完成了领域层.应用层.以及基础结构层的部分代码,这篇打算搭建下UI层的代码. DD ...

  9. WCF系列_WCF影响客户端导出Excel文件的实现

    需求:WCF搭建服务端提供导出并下载Excel文件接口,客户端使用ajax发起请求,浏览器直接下载Excel文件. 难点:WCF中并没有HttpContext对象,因此,服务端总是获取不到HttpCo ...

随机推荐

  1. Android定义自己的面板共享系统

    在Android分享知道有一个更方便的方法.调用的共享面板来分享我们的应用程序的系统.主要实现例如,下面的: public Intent getShareIntent(){ Intent intent ...

  2. JS判断用户连续输入

    方案1 // // $('#element').donetyping(callback[, timeout=1000]) // Fires callback when a user has finis ...

  3. C# Windows Phone 8 WP8 开发,取得手机萤幕大小两种方法。

    原文:C# Windows Phone 8 WP8 开发,取得手机萤幕大小两种方法. 一般我们在开发Windows Phone App时,需要取得萤幕的大小来自定义最佳化控制项的大小,但是开如何取得萤 ...

  4. projecteuler----&gt;problem=14----Longest Collatz sequence

    title: The following iterative sequence is defined for the set of positive integers: n n/2 (n is eve ...

  5. JAVA IP地址转成长整型方法

    JAVA IP地址转成长整型方法 代码例如以下: /** * IP转成整型 * @param ip * @return */ public static Long ip2int(String ip) ...

  6. 代码的未来读书笔记&lt;二&gt;

    代码的未来读书笔记<二> 3.1语言的设计 对Ruby JavaScript Java Go 从服务端client以及静态动态这2个角度进行了对照. 这四种语言因为不同的设计方针,产生了不 ...

  7. React Native是一套使用 React 构建 Native app 的编程框架

    React Native是一套使用 React 构建 Native app 的编程框架 React Native at first sight what is React Native? 跟据官方的描 ...

  8. oracle物化视图使用+hibernate

    使用过程 ----删除 TRUNCATE TABLE mlog$_xxx_lxz_tmp;DROP MATERIALIZED VIEW LOG ON xxx_lxz_tmp; drop materia ...

  9. SecureCRT 6.7.1 RI和谐 皴 补丁 方法

    它之前被使用SecureCRT 6.5.3 版本号,咋看和谐补丁,即使中国版本也可(现在才发现SecureCRT.6.2.0) 可是换为 6.7.1 后就怎么也注冊不了了.. 没办法试了各种办法: 先 ...

  10. OCP-1Z0-051-题目解析-第14题

    14. Using the CUSTOMERS table,  you need to generate a report that shows 50% of each credit        a ...