相关文章
第零回.序和属性
第一回.真的了解.NET CF吗?
第二回.初窥CF类型加载器
第三回.让.NET CF CLR有条不紊
第四回.多窗体应用的性能与编程调试
第五回.WCF Mobile--Part 1
第五回.WCF Mobile--Part 2
第五回. WCF Mobile(Part 3 & final)
摘要:本文是我前两篇WCF Mobile文章的续篇,主要阐述如何使用Compact WCF特有的Email Transport的消息模型在我们的应用程序中进行实际的开发。
Keywords:
WCF, Windows Mobile,.NET Compact Framework, Email, C#, Exchange Server 2007
四个月以前写的两篇blog中阐述了Compact WCF和HTTP传输方式的消息模型,前两天建强兄在整理精化本的时候收录了我的前两篇有关WCF on Windows Mobile的文章在阅读本文之前,严重推荐您先阅读这两篇文章J
http://www.cnblogs.com/fox23/archive/2008/03/28/wmadv5.html
http://www.cnblogs.com/fox23/archive/2008/03/30/wmadv5-2.html
前几个月因为种种原因,没有时间来把那个系列继续完成,现在来继续写下去,better late than never, isn't it :-)
How it works?
在前面的随笔中已经提到,Email Transport提供了给设备定址的能力。也就是说,消息可以被准确的发送给移动设备,而且可以被存储起来,在下一次同步的时候再发送出去。这使得移动设备应用程序的开发人员可以在程序中将消息暂存在本地,在同步的时候再经Exchange 2007 发送给邮件中心。而在服务端,消息也可以根据邮件地址被Push到各个与之对应的移动设备上。使用这种Email可本地存储的方式来存放消息,使得我们的客户端(设备端)应用程序即使重起,或者设备重起也不会对消息产生干扰。下图演示了基于Windows Mobile和Exchange Server 2007的Email Transport的工作原理:

Tips 这里的移动设备和服务器建立的“长连接”要用到ActiveSync的Always Up to Date技术(AUDT),关于Exchange和AUDT请参考:http://technet.microsoft.com/en-us/library/cc164312(EXCHG.65).aspx 。关于Direct Push技术请参考:Direct Push---甚好甚强巨
作为程序员关心的重点,消息处理层是不希望受到邮件传输层的影响的,或者说程序员通常希望不管是什么传输方式都对他的消息处理层没有什么影响,WCF Email Transport的消息处理层结构如下:

Email Transport采用的是邮件地址+信道名称的绑定方式对移动Client定址,这有点类似于IP地址+端口的定址方式,邮件地址用于给设备定址,信道名(ChannelName)用于给应用程序定址。Compact WCF提供的邮件信道是一个单向的信道(意思是单次的行为总是单向的),就是说Message要么从Server到Device,要么从Device到Server,在等待消息发送的时候信道处于阻塞态。所以跟很多通信程序一样,建议您最好在服务器上为每一个信道的listener分配一个单独的线程去完成数据的处理工作,这样就不用因这种阻塞而干扰主程序的执行。
Email消息的传输过程需要Exchange Server 2007的支持,呃,我的意思是实实在在的需要Exchange 2007,不仅仅需要我们的设备能连接到它,而且还要在Server端做一些工作,才能使这个Email Transport的过程跑起来。
Tips这里Server端的用于Email Transport的WCF类库是通过Exchange Web Service与Exchange Server通信的,这些Service在早些版本的Exchange Server中是不完全支持的。所以你需要Exchange Server 2007(相信Exchange Server在企业信息化的过程中还是会慢慢普及的)。
Let’s begin!
好了,有了一个大概的认识,现在我们可以试着编程了。还是跟这里一样,我们先从比较熟悉的PC端控制台程序开始。它尝试以Email的形式给设备发送消息。在开始之前别忘了添加以下两项引用:
Ø Microsoft.ServiceModel.Mail.dll
Ø Microsoft.ServiceModel.Channels.Mail.ExchangeWebService;
同时,这里我们要用到之前这篇blog中的两个类:TransmittedObject和XMLSerialHelper,分别用作消息体对象和序列化工具。
PC端的代码相对简单一些,首先添加以下命名空间:
using Microsoft.ServiceModel.Channels.Mail.ExchangeWebService;
using System.ServiceModel.Channels;
using System.Net;
using System.ServiceModel;
using Microsoft.ServiceModel.Channels.Mail;

Main函数如下:

private fields#region private fields
private static Uri ExchangeServer = new Uri("http://CCMTCExServer");
private static string UserEmail = "test@CCMTCExServer.com";
private static string Password = "abc123!";
private static string DestinationEmail = "test1@CCMTCExServer.com";
private static string OutputChannelName = "PrivateNotification";
#endregion

static void Main(string[] args)

{
ExchangeWebServiceMailBinding mailBinding;
IChannelFactory<IOutputChannel> factory;
IOutputChannel outputChannel;
XMLSerialHelper serializer;
Message message;

// 如果Exchange采用了Windows集成认证的话
//这里NetworkCredential可以设为Null
mailBinding = new ExchangeWebServiceMailBinding(
Program.ExchangeServer,
new NetworkCredential(Program.UserEmail, Program.Password));

factory = mailBinding.BuildChannelFactory<IOutputChannel>(
new BindingParameterCollection());
factory.Open();

//打开指定的信道
outputChannel = factory.CreateChannel(
new EndpointAddress(MailUriHelper.Create(
OutputChannelName,
DestinationEmail)));
outputChannel.Open();
//创建消息对象
serializer = new XMLSerialHelper(typeof(string));
message = Message.CreateMessage(
MessageVersion.Default,//SOAP版本
"AddEmployee",//消息描述
"Jeff Smith", //消息体对象
serializer //消息体序列化器
);

Console.Write("Sending the update
");
outputChannel.Send(message);
Console.WriteLine("done.");

//清理资源
outputChannel.Close();
factory.Close();
mailBinding.Close();
}
好,下面来看看WM端的程序,先前说了PC端是用来Push消息的,那么设备端我们将创建一个特定的信道监听器,让它运行在后台线程。一旦它受到消息,它会将消息获取出来显示到listbox中。
首先还是得添加引用:
Ø Microsoft.ServiceModel.Mail.dll
Ø Microsoft.ServiceModel.Mail.WindowsMobile.dll
然后需要在我们的Form1中添加以下命名空间:
using Microsoft.ServiceModel.Channels.Mail.WindowsMobile;
using System.ServiceModel.Channels;
using System.Threading;
using Microsoft.ServiceModel.Channels.Mail;

测试程序如下:
public void TestMessage()

{
//创建消息体
TransmittedObject wcfMsg = new TransmittedObject();
wcfMsg.StrContent = "hello";
wcfMsg.Count = 0;
//创建序列化器
XMLSerialHelper wrapper =
new XMLSerialHelper(typeof(TransmittedObject));
//创建WCF消息对象
Message m =
Message.CreateMessage(MessageVersion.Soap11, "urn:test", wcfMsg, wrapper);
// 创建一个BasicHttpBinding模式的信道
BasicHttpBinding binding = new BasicHttpBinding();
BindingParameterCollection parameters =
new BindingParameterCollection();

IChannelFactory<IRequestChannel> channelFactory =
binding.BuildChannelFactory<IRequestChannel>(parameters);

channelFactory.Open();

//从指定服务节点的创建并打开信道
IRequestChannel outChannel =
channelFactory.CreateChannel(
new EndpointAddress(
new Uri("http://222.20.35.46:10008/")));
outChannel.Open(TimeSpan.MaxValue);

//发送消息并等待回应.
Message reply = outChannel.Request(m, TimeSpan.MaxValue);

//获取并处理返回的消息体
TransmittedObject to1 = reply.GetBody<TransmittedObject>(new
XMLSerialHelper(typeof(TransmittedObject)));
MessageBox.Show(to1.StrContent + " | from Server");

//别忘了释放资源
m.Close();
reply.Close();
outChannel.Close();
channelFactory.Close();
}


总结
基于 WCF Exchange Server 邮件传输构建的应用程序可以从 WCF 的各项基本功能中获益。WCF 为各种基础协议和传输提供了一个统一的编程模型,并能够将应用程序逻辑与 WCF 终结点分开。这样的编程模型提供了多种好处,包括支持多种不同的网络,例如通用分组无线业务 (GPRS)、Wi-Fi 以及可以访问电子邮件服务器的任何其他网络。使得 WCF Exchange Server 邮件传输开发应用程序与使用 HTTP 信道等 WCF 信道开发应用程序非常相似。
参考资源
.NET Compact Framework 中的消息处理
介绍 .NET Compact Framework 中对 WCF 消息处理层的支持。
如何:使用 HTTP 传输
介绍如何从运行 .NET Compact Framework 的设备连接至桌面上现有的 WCF 服务。
如何:使用传输安全
介绍如何在从运行 .NET Compact Framework 的设备连接至桌面上的现有 WCF 服务时实现相互身份验证。
WCF Exchange Server 邮件传输
介绍 WCF Exchange Server 邮件传输,此机制基于将电子邮件用作桌面 .NET Framework 和 .NET Compact Framework 上运行的 WCF 应用程序的传输。
演练:使用 WCF Exchange Server 邮件传输
提供基于 WCF Exchange Server 邮件传输的应用程序的示例。
如何:在 WCF Exchange Server 邮件传输中使用消息安全性
提供有关如何在 WCF Exchange Server 邮件传输中使用 SOAP 消息安全性的示例。
如何:序列化 WCF 应用程序中的消息
提供可用于序列化 WCF 应用程序中的消息的对象序列化程序。
enjoy it!
黄季冬