WCF技术内幕 第2章 (2)

2.7 标记消息地址
序列化地址到消息中也会改善处理效率,特别是当更高级的消息发行行为要实现时。
<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 为什么要面向服务

面向服务契约的普遍自然属性把发送者和接收者从实现中解耦出来,因此使得版本控制与升级的周期变短。(版本控制)

面向服务的应用程序可以更容易扩展应用系统需要,降低了总的成本,而且简化了配置管理工作。(扩展性)

面向服务的应用系统是与平台无关的。(互操作性)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值