跟着Artech学习WCF(5) Responsive Service 与自定义Soap Message Header
记得以前看.NET各类框架教程在介绍SOAP时经常提到Soap Header 以前一直认为这个玩意就是个理论
应该和具体的编码和应用无关
后来在看到一些关于SOAP安全的书可以在header里 进行加密解密信息的存储 用于安全方面的验证
但一直苦于这个玩意到底是神马东西,一直没见过代码,今天Artech在介绍wcf时无意间解开期神秘的面纱,真是令人感到意外的惊喜
项目结构图如下
代码如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Configuration; using System.ServiceModel; using System.Messaging; using bsContract; namespace bsClient { class Program { static void Main(string[] args) { Order order1 = new Order(Guid.NewGuid(), DateTime.Today.AddDays(5), Guid.NewGuid(), "Supplier A"); Order order2 = new Order(Guid.NewGuid(), DateTime.Today.AddDays(-5), Guid.NewGuid(), "Supplier A"); string path = ConfigurationManager.AppSettings["msmqPath"]; Uri address = new Uri(path); OrderResponseContext context = new OrderResponseContext(); context.ResponseAddress = address; ChannelFactory<IOrderProcessor> channelFactory = new ChannelFactory<IOrderProcessor>("defaultEndpoint"); IOrderProcessor orderProcessor = channelFactory.CreateChannel(); using (OperationContextScope contextScope = new OperationContextScope(orderProcessor as IContextChannel)) { Console.WriteLine("Submit the order of order No.: {0}", order1.OrderNo); OrderResponseContext.Current = context; orderProcessor.Submit(order1); } using (OperationContextScope contextScope = new OperationContextScope(orderProcessor as IContextChannel)) { Console.WriteLine("Submit the order of order No.: {0}", order2.OrderNo); OrderResponseContext.Current = context; orderProcessor.Submit(order2); } Console.Read(); } } }
=============================
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.Runtime.Serialization; namespace bsContract { [ServiceContract] [ServiceKnownType(typeof(Order))] public interface IOrderProcessor { [OperationContract(IsOneWay = true)] void Submit(Order order); } }
============================
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.Runtime.Serialization; namespace bsContract { [ServiceContract] public interface IOrderRessponse { [OperationContract(IsOneWay = true)] void SubmitOrderResponse(Guid orderNo, FaultException exception); } }
========================================
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; namespace bsContract { [DataContract] public class Order { #region Private Fields private Guid _orderNo; private DateTime _orderDate; private Guid _supplierID; private string _supplierName; #endregion #region Constructors public Order(Guid orderNo, DateTime orderDate, Guid supplierID, string supplierName) { this._orderNo = orderNo; this._orderDate = orderDate; this._supplierID = supplierID; this._supplierName = supplierName; } #endregion #region Public Properties [DataMember] public Guid OrderNo { get { return _orderNo; } set { _orderNo = value; } } [DataMember] public DateTime OrderDate { get { return _orderDate; } set { _orderDate = value; } } [DataMember] public Guid SupplierID { get { return _supplierID; } set { _supplierID = value; } } [DataMember] public string SupplierName { get { return _supplierName; } set { _supplierName = value; } } #endregion #region Public Methods public override string ToString() { string description = string.Format("Order No.\t: {0}\n\tOrder Date\t: {1}\n\tSupplier No.\t: {2}\n\tSupplier Name\t: {3}", this._orderNo, this._orderDate.ToString("yyyy/MM/dd"), this._supplierID, this._supplierName); return description; } #endregion } }
===============================
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; using System.ServiceModel; namespace bsContract { [DataContract] public class OrderResponseContext { private Uri _responseAddress; [DataMember] public Uri ResponseAddress { get { return _responseAddress; } set { _responseAddress = value; } } public static OrderResponseContext Current { get { if (OperationContext.Current == null) { return null; } return OperationContext.Current.IncomingMessageHeaders.GetHeader<OrderResponseContext>("OrderResponseContext", "Contract"); } set { MessageHeader<OrderResponseContext> header = new MessageHeader<OrderResponseContext>(value); OperationContext.Current.OutgoingMessageHeaders.Add(header.GetUntypedHeader("OrderResponseContext", "Contract")); } } } }
========================================================
using System.Linq; using System.Text; using System.ServiceModel; using System.Configuration; using System.Messaging; using bsService; using bsContract; namespace bsHosting { class Program { static void Main(string[] args) { string path = ConfigurationManager.AppSettings["msmqPath"]; if (!MessageQueue.Exists(path)) { MessageQueue.Create(path); } using (ServiceHost host = new ServiceHost(typeof(OrderProcessorService))) { host.Opened += delegate { Console.WriteLine("The Order Processor service has begun to listen"); }; host.Open(); Console.Read(); } } } }
===================================================
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Configuration; using System.ServiceModel; using System.Messaging; using bsLocalService; using bsContract; namespace bsLocalhHosting { class Program { static void Main(string[] args) { string path = ConfigurationManager.AppSettings["msmqPath"]; if (!MessageQueue.Exists(path)) { MessageQueue.Create(path); } using (ServiceHost host = new ServiceHost(typeof(OrderRessponseService))) { host.Opened += delegate { Console.WriteLine("The Order Response service has begun to listen"); }; host.Open(); Console.Read(); } } } }
=============================================
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using bsContract; namespace bsLocalService { public class OrderRessponseService : IOrderRessponse { #region IOrderRessponse Members public void SubmitOrderResponse(Guid orderNo, FaultException exception) { if (exception == null) { Console.WriteLine("It's successful to process the order!\n\tOrder No.: {0}", orderNo); } else { Console.WriteLine("It's fail to process the order!\n\tOrder No.: {0}\n\tReason: {1}", orderNo, exception.Message); } } #endregion } }
==================================
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.Net.Security; using bsContract; namespace bsService { public class OrderProcessorService:IOrderProcessor { private void ProcessOrder(Order order) { if (order.OrderDate < DateTime.Today) { throw new Exception(); } } void IOrderProcessor.Submit(Order order) { Console.WriteLine("Begin to process the order of the order No.: {0}", order.OrderNo); FaultException exception = null; if (order.OrderDate < DateTime.Today) { exception = new FaultException(new FaultReason("The order has expried"), new FaultCode("sender")); Console.WriteLine("It's fail to process the order.\n\tOrder No.: {0}\n\tReason:{1}", order.OrderNo, "The order has expried"); } else { Console.WriteLine("It's successful to process the order.\n\tOrder No.: {0}", order.OrderNo); } NetMsmqBinding binding = new NetMsmqBinding(); binding.ExactlyOnce = false; binding.Security.Transport.MsmqAuthenticationMode = MsmqAuthenticationMode.None; binding.Security.Transport.MsmqProtectionLevel = ProtectionLevel.None; ChannelFactory<IOrderRessponse> channelFacotry = new ChannelFactory<IOrderRessponse>(binding); OrderResponseContext responseContext = OrderResponseContext.Current; IOrderRessponse channel = channelFacotry.CreateChannel(new EndpointAddress(responseContext.ResponseAddress)); using (OperationContextScope contextScope = new OperationContextScope(channel as IContextChannel)) { channel.SubmitOrderResponse(order.OrderNo, exception); } } } }
=====================================
配置部分
bsClient 的配置
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="msmqPath" value="net.msmq://localhost/private/orderresponse"/> </appSettings> <system.serviceModel> <bindings> <netMsmqBinding> <binding name="MsmqBinding" exactlyOnce="false" useActiveDirectory="false"> <security> <transport msmqAuthenticationMode="None" msmqProtectionLevel="None" /> </security> </binding> </netMsmqBinding> </bindings> <client> <endpoint address="net.msmq://localhost/private/orderprocessor" binding="netMsmqBinding" bindingConfiguration="MsmqBinding" contract="bsContract.IOrderProcessor" name="defaultEndpoint" /> </client> </system.serviceModel> </configuration>
==============
bsHosting 的配置
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="msmqPath" value=".\private$\orderprocessor"/> </appSettings> <system.serviceModel> <bindings> <netMsmqBinding> <binding name="MsmqBinding" exactlyOnce="false" useActiveDirectory="false"> <security> <transport msmqAuthenticationMode="None" msmqProtectionLevel="None" /> </security> </binding> </netMsmqBinding> </bindings> <services> <service name="bsService.OrderProcessorService"> <endpoint address="net.msmq://localhost/private/orderprocessor" binding="netMsmqBinding" bindingConfiguration="MsmqBinding" contract="bsContract.IOrderProcessor" /> </service> </services> </system.serviceModel> </configuration>
================================================
bsLocalhHosting 配置
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="msmqPath" value=".\private$\orderresponse"/> </appSettings> <system.serviceModel> <bindings> <netMsmqBinding> <binding name="msmqBinding" exactlyOnce="false"> <security> <transport msmqAuthenticationMode="None" msmqProtectionLevel="None" /> </security> </binding> </netMsmqBinding> </bindings> <services> <service name="bsLocalService.OrderRessponseService"> <endpoint address="net.msmq://localhost/private/orderresponse" binding="netMsmqBinding" bindingConfiguration="msmqBinding" contract="bsContract.IOrderRessponse" /> </service> </services> </system.serviceModel> </configuration>
test