1

My goal is to record wcf calls to one IIS hosted wcf service and replay them to a different wcf service. So far I have an IDispatchMessageInspector working following this example, it can log an incoming request and the corresponding reply to disk.

How can I read in a message from disk and then send it to the other service? Is there a way for the client to send a low level Message object to the service without going through the normal client proxy object?

BrandonAGr
  • 5,827
  • 5
  • 47
  • 72

2 Answers2

2

I was able to get it to work by simply creating an IRequestChannel, reading the following helped explain how it works

The code to send the message:

private static void TestDispatchingMessage()
{
    var reader = XmlDictionaryReader.CreateBinaryReader(new FileStream(@"path\request_6c6fc02f-45a7-4049-9bab-d6f2fff5cb2d.xml", FileMode.Open), XmlDictionaryReaderQuotas.Max);
    var message = Message.CreateMessage(reader, int.MaxValue, MessageVersion.Soap11);
    message.Headers.To = new System.Uri(@"url");


    BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None)
    {
        MessageEncoding = WSMessageEncoding.Mtom,
        MaxReceivedMessageSize = int.MaxValue,
        SendTimeout = new TimeSpan(1, 0, 0),
        ReaderQuotas = { MaxStringContentLength = int.MaxValue, MaxArrayLength = int.MaxValue, MaxDepth = int.MaxValue }
    };

    var cf = new ChannelFactory<IRequestChannel>(binding, new EndpointAddress(@"url"));

    foreach (OperationDescription op in cf.Endpoint.Contract.Operations)
    {
        op.Behaviors.Remove<DataContractSerializerOperationBehavior>();
        op.Behaviors.Add(new ProtoBehaviorAttribute());
    }

    cf.Open();
    var channel = cf.CreateChannel();
    channel.Open();

    var result = channel.Request(message);

    Console.WriteLine(result);

    channel.Close();
    cf.Close();
}

This is what was in the IDispatchMessageInspector class:

public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
    var callId = Guid.NewGuid();

    var action = request.Headers.Action.Substring(request.Headers.Action.LastIndexOf('/'));
    var fileName = string.Format(@"path\{0}_{1}.data", action, callId);

    try
    {
        var buffer = request.CreateBufferedCopy(int.MaxValue);

        var writeRequest = buffer.CreateMessage();
        using (var stream = new FileStream(fileName, FileMode.CreateNew))
        {
            using (var writer = XmlDictionaryWriter.CreateBinaryWriter(stream))
            {
                writeRequest.WriteMessage(writer);
                writer.Flush();
            }
        }

        request = buffer.CreateMessage();
        buffer.Close();
    }
    catch (Exception ex)
    {
        Log.ErrorException("Error writing", ex);
    }

    Log.Info("Call {0}", callId);

    return callId;
}
BrandonAGr
  • 5,827
  • 5
  • 47
  • 72
1

Yes, sending raw messages should be easy if you work at the communication protocol level. Here's one of my old examples.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106