2.7 标记消息地址
序列化地址到消息中也会改善处理效率,特别是当更高级的消息发行行为要实现时。
每一个服务包含一个地址,一个契约和一个绑定。这些机制常常被称为WCF的ABC。
XML请求示例:
序列化地址到消息中也会改善处理效率,特别是当更高级的消息发行行为要实现时。
<Envelope>
<Header>
<MessageID></MessageID> <!--消息标识元素,GUID-->
<To>Http://anders.com/ReceiveService</To> <!--指定最终接收者-->
<From>http://anders.com/SendService</From> <!--指定初始发送者-->
<Error>http://anders.com/ErrorService</Error> <!--指定错误发送地址-->
<RelatedTo></RelatedTo> <!--导致错误的信息,用于系统调试,故障分析-->
<ReplyTo>http://anders.com/OrderReplyService</ReplyTo> <!--增加一个返回消息的地址,监听消息的地址-->
<Action>urn:ProcessOrder</Action> <!--表示ProcessOrder操作应该在此消息上执行-->
</Header>
</Envelope>
2.8 WS-Addressing
HTTP URLs和PUT/DELETE/GET/POST HTTP动词不能满足所有服务。
HTTP通常是正确的传输方式。
安全通过HTTPS提供。
需要加密传输(从客户端到服务端)。
可以发送包含会话规定参数的请求。
URI:统一资源标识符,是一个可以用来定位或命名空间中的一个点的字符串。
URL:统一资源定位符,严格定位资源。
URN:统一资源名称,用来表示资源的名称。
从不同角度来理解,URL和URN都是URI集合的成员。
2.9 面向服务的4个原则
边界清晰 服务自治 契约共享(Service接口) 策略兼容(服务必须能够描述其他服务与之交互的底层环境)。
2.10概念总结
//契约:
using System.ServiceModel;
using System.ServiceModel.Channels;
namespace OrderServiceExample
{
//Interface契约
//面向服务系统开发首先应该创建契约。契约可以被编译为一个程序集。一旦编译完成,
//程序集可以指派给发送者和接收者。程序集代表了发送者和接收者之间的契约。
[ServiceContract]
public interface IOrder
{
//定义Action
[OperationContract(Action="urn:SubmitOrder")]
void SubmitOrder(Message order);
}
}
//Service API
using System;
using System.IO;
using System.ServiceModel.Channels;
using System.Xml;
namespace OrderServiceExample
{
//Order API service
public class OrderService : IOrder
{
public void SubmitOrder(Message order)
{
string fileName = string.Format("Order{0}.xml",order.Headers.MessageId.ToString());
//提示消息到达
Console.WriteLine("Message ID {0} received", order.Headers.MessageId.ToString());
XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(new FileStream(fileName, FileMode.Create));
//写消息到文件里
order.WriteMessage(writer);
writer.Close();
}
}
}
每一个服务包含一个地址,一个契约和一个绑定。这些机制常常被称为WCF的ABC。
//宿主程序,Server端
using System;
using System.ServiceModel;
using OrderServiceExample;
namespace HostApp
{
class Program
{
static void Main(string[] args)
{
//定义服务绑定
WSHttpBinding binding = new WSHttpBinding(SecurityMode.None);
//定义消息编码
binding.MessageEncoding = WSMessageEncoding.Text;
//定义服务地址
Uri addressUri = new Uri("http://localhost:1234/Order");
//使用OrderService实例化宿主
ServiceHost svc = new ServiceHost(typeof(OrderService));
//给服务增加一个终结点,ServiceHost没有默认的终结点,所以必须通过AddServiceEndpoint方法增加自己的终结点
//契约Contract,Binding服务绑定,Uri服务地址
svc.AddServiceEndpoint(typeof(IOrder), binding, addressUri.ToString());
//打开服务宿主开始侦听
svc.Open();
Console.WriteLine("The receiver is ready...");
Console.ReadKey();
svc.Close();
}
}
}
//客户端,请求端
using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;
using System.Xml;
using OrderServiceExample;
namespace RequestSideApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press ENTER when the receiver is ready");
Console.ReadLine();
//接收程序的地址
EndpointAddress address = new EndpointAddress(@"http://localhost:1234/Order");
WSHttpBinding binding = new WSHttpBinding(SecurityMode.None);
binding.MessageEncoding = WSMessageEncoding.Text;
ChannelFactory<IOrder> channel = new ChannelFactory<IOrder>(binding, address);
IOrder proxy = channel.CreateChannel();
Message msg = null;
for (Int32 i = 0; i < 10; i++)
{
msg = GenerateMessage(i, i);
UniqueId uniqueID = new UniqueId(i.ToString());
//SOAP消息头里添加MessageId
msg.Headers.MessageId = uniqueID;
Console.WriteLine("Send Message #{0}", uniqueID.ToString());
//SOAP消息头里添加Action
msg.Headers.Action = @"urn:SubmitOrder";
proxy.SubmitOrder(msg);
}
}
//创建消息的方法
private static Message GenerateMessage(Int32 productID, Int32 qty)
{
MemoryStream stream = new MemoryStream();
XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8, false);
writer.WriteStartElement("SubmitOrder");
writer.WriteElementString("ProdID", productID.ToString());
writer.WriteElementString("Qty", qty.ToString());
writer.WriteEndElement();
writer.Flush();
stream.Position = 0;
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, XmlDictionaryReaderQuotas.Max);
return Message.CreateMessage(MessageVersion.Soap12WSAddressing10, string.Empty, reader);
}
}
}
XML请求示例:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">urn:SubmitOrder</a:Action>
<a:MessageID>0</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">http://localhost:1234/Order</a:To>
</s:Header>
<s:Body>
<SubmitOrder>
<ProdID>0</ProdID>
<Qty>0</Qty>
</SubmitOrder>
</s:Body>
</s:Envelope>
2.11 为什么要面向服务
面向服务契约的普遍自然属性把发送者和接收者从实现中解耦出来,因此使得版本控制与升级的周期变短。(版本控制)
面向服务的应用程序可以更容易扩展应用系统需要,降低了总的成本,而且简化了配置管理工作。(扩展性)
面向服务的应用系统是与平台无关的。(互操作性)