博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

转载来的wcf学习笔记04

Posted on 2008-05-28 16:46  wuhang  阅读(157)  评论(0编辑  收藏  举报
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) 文档。