Поделиться через


Making One-Way HTTP Requests, Part 1

I promised yesterday that we would start using the HttpListener test program to look at some HTTP requests. I'm going to start by creating a fictional IPing service and a simple custom binding over HTTP. The test listener from yesterday was very basic so it can passively receive requests but doesn't make any meaningful replies. That means that we have to make the binding and service all use one-way calls so that they don't expect any real content to come back.

 [ServiceContract]
public interface IPing
{
   [OperationContract(IsOneWay = true)]
   void Ping(string clientInfo, DateTime lastSeen);
}

I'm going to magic up the client proxy for this service. This is exactly what you would get back from svcutil if you ran it against the IPing service contract. There's nothing actually exciting going on in this client class.

 [System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class PingClient : ClientBase<IPing>, IPing
{
   public PingClient()
   {
   }

   public PingClient(string endpointConfigurationName)
      : base(endpointConfigurationName)
   {
   }

   public PingClient(string endpointConfigurationName, string remoteAddress)
      : base(endpointConfigurationName, remoteAddress)
   {
   }

   public PingClient(string endpointConfigurationName, EndpointAddress remoteAddress)
      : base(endpointConfigurationName, remoteAddress)
   {
   }

   public PingClient(Binding binding, EndpointAddress remoteAddress)
      : base(binding, remoteAddress)
   {
   }

   public void Ping(string clientInfo, DateTime lastSeen)
   {
      base.Channel.Ping(clientInfo, lastSeen);
   }
}

We never need to write a service implementation because we're going to hit the listener test program. Now, we can hit the "service" with an operation call to see what happens on the wire. I've got a trivial test client that creates the binding and sends a single call using the generated client.

 class client
{
   static void Main(String[] args)
   {
      CustomBinding binding = new CustomBinding(
         new OneWayBindingElement(),
         new TextMessageEncodingBindingElement(),
         new HttpTransportBindingElement()
      );
      PingClient client = new PingClient(binding, new EndpointAddress("https://localhost:8000/"));
      client.Open();
      client.Ping("my info", DateTime.Now);
      client.Close();
   }
}

This gives us a view of the SOAP goo and serialized service request. I didn't change the defaults for the SOAP envelope and WS addressing versions, which means that we'll have more goo than actual message.

 HTTP/1.1 POST https://localhost:8000/
::1:1146 --> ::1:8000

[Headers]
Connection: Keep-Alive
Content-Length: 412
Content-Type: application/soap+xml; charset=utf-8
Expect: 100-continue
Host: localhost:8000

[Request]
<s:Envelope xmlns:s="https://www.w3.org/2003/05/soap-envelope" xmlns:a="https://www.w3.org/2005/08/addressing">
  <s:Header>
    <a:Action s:mustUnderstand="1">https://tempuri.org/IPing/Ping</a:Action>
    <a:To s:mustUnderstand="1">https://localhost:8000/</a:To>
  </s:Header>
  <s:Body>
    <Ping xmlns="https://tempuri.org/">
      <clientInfo>my info</clientInfo>
      <lastSeen>2006-08-15T00:10:04.32525-07:00</lastSeen>
    </Ping>
  </s:Body>
</s:Envelope>

Everything has worked very smoothly so far, but things start going wrong if we try to use the POX message encoder. We'll look at that next time.

Next time: Making One-Way HTTP Requests, Part 2