[WCF 学习笔记] 4. 消息操作

WCF 的一切都是围绕着 Message 进行,那么 Message 究竟是什么样子?

[ServiceContract]
public interface ICalculate
{
  [OperationContract]
  double Add(double a, double b);
}

public class CalculateService : ICalculate
{
  public double Add(double a, double b)
  {
    Message msg = OperationContext.Current.RequestContext.RequestMessage;
    Console.WriteLine(msg);

    return a + b;
  }
}

public class WcfTest
{
  public static void Test()
  {
    AppDomain.CreateDomain("Server").DoCallBack(delegate
    {
      ServiceHost host = new ServiceHost(typeof(CalculateService));
      host.AddServiceEndpoint(typeof(ICalculate), new BasicHttpBinding(),
        "http://localhost:8080/calc");

      host.Open();
    });

    ChannelFactory<ICalculate> factory = new ChannelFactory<ICalculate>(new BasicHttpBinding(),
      "http://localhost:8080/calc");
    ICalculate o = factory.CreateChannel();
    Console.WriteLine(o.Add(1, 2));
  }
}

 

输出

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <To s:mustUnderstand="1" xmlns="http://...">http://localhost:8080/calc</To>
    <Action s:mustUnderstand="1" xmlns="http://...">http://tempuri.org/ICalculate/Add</Action>
  </s:Header>
  <s:Body>
    <Add xmlns="http://tempuri.org/">
      <a>1</a>
      <b>2</b>
    </Add>
  </s:Body>
</s:Envelope>


事实上我们可以直接基于 Message Layer 进行编程,利用 OperationContract.Action 捕获特定 Action 的消息。

[ServiceContract]
public interface ICalculate
{
  [OperationContract(Action = "Add", ReplyAction="Add")]
  Message ProcessMessage(Message m);
}

public class CalculateService : ICalculate
{
  public Message ProcessMessage(Message m)
  {
    Data d = m.GetBody<Data>();
    Console.WriteLine(d.I);
    
    return Message.CreateMessage(MessageVersion.Soap11, "Add", new Data(9999));
  }
}

[DataContract]
public class Data
{
  [DataMember]
  public int I;

  public Data(int i)
  {
    this.I = i;
  }
}

public class WcfTest
{
  public static void Test()
  {
    AppDomain.CreateDomain("Server").DoCallBack(delegate
    {
      ServiceHost host = new ServiceHost(typeof(CalculateService));
      host.AddServiceEndpoint(typeof(ICalculate), new BasicHttpBinding(),
        "http://localhost:8080/calc");

      host.Open();
    });

    ChannelFactory<IRequestChannel> factory = new ChannelFactory<IRequestChannel>(
      new BasicHttpBinding(), "http://localhost:8080/calc");
    IRequestChannel channel = factory.CreateChannel();
    channel.Open();

    Message request = Message.CreateMessage(MessageVersion.Soap11, "Add", new Data(1234));
    Message reply = channel.Request(request);
    Console.WriteLine("-------------------");
    Console.WriteLine(reply);

    channel.Close();
    factory.Close();
  }
}    


输出:

1234
-------------------
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header />
  <s:Body>
    <Data xmlns="http://..." xmlns:i="http://...">
      <I>9999</I>
    </Data>
  </s:Body>
</s:Envelope>


正 如上面所看到的,所有的调用都被转换成消息后发送。这也符合 SOA 的规范,完全隔离,清晰的边界。(调用 "m.GetBody<Data>()" 后,会导致 Message.State 变更,再次访问会出错,有关详细信息请参考 MSDN 文档。)

我们还可以使用 MessageContractAttribute / MessageHeaderAttribute 来控制消息格式,这比 DataContractAttribute 要更加灵活。我们可以设置消息标头、消息体,包括是否对其中某些进行签名和加密处理。

[ServiceContract]
public interface ICalculate
{
  [OperationContract]
  void Add(Data d);
}

public class CalculateService : ICalculate
{
  public void Add(Data d)
  {
    Console.WriteLine(OperationContext.Current.RequestContext.RequestMessage);
    Console.WriteLine("----------------");
    Console.WriteLine("{0}/{1}", d.a, d.b);
  }
}

[MessageContract]
public class Data
{
  [MessageHeader]
  public double a = 1;

  [MessageBodyMember]
  public double b = 2;
}

public class WcfTest
{
  public static void Test()
  {
    AppDomain.CreateDomain("Server").DoCallBack(delegate
    {
      ServiceHost host = new ServiceHost(typeof(CalculateService));
      host.AddServiceEndpoint(typeof(ICalculate), new BasicHttpBinding(),
        "http://localhost:8080/calc");
      
      host.Open();
    });

    ChannelFactory<ICalculate> factory = new ChannelFactory<ICalculate>(new BasicHttpBinding(),
      "http://localhost:8080/calc");
    ICalculate o = factory.CreateChannel();

    Data d = new Data();
    d.a = 1234;
    d.b = 5678;
    o.Add(d);
  }
}


输出:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <h:a xmlns:h="http://tempuri.org/">1</h:a>
    <To s:mustUnderstand="1" xmlns="http://s...">http://localhost:8080/calc</To>
    <Action s:mustUnderstand="1" xmlns="http://...">http://tempuri.org/ICalculate/Add</Action>
  </s:Header>
  <s:Body>
    <Data xmlns="http://tempuri.org/">
      <b>2</b>
    </Data>
  </s:Body>
</s:Envelope>
----------------
1234/5678


有关 Message 更详细的信息,可以参考 MSDN (Microsoft Windows SDK) 文档。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值