I need to calculate a HMAC signature of a request and then set a request header value of that signature, before sending the request of a JsonServiceClient.
I started down the track of handling the JsonSericeClient.RequestFilter, but quickly discovered that I cannot read the body form the request.GetRequestStream() in that context. (Exception: when I try to copy it stream.CopyTo()).
How can I get the body of the request from a JonServiceClient in time to set a header value?
It’s not possible to re-read a Request Stream as it’s a forward only Stream. I’ve made SerializeRequestToStream protected in this commit so you can override it in a sub class. You’ll need to write it to a MemoryStream so you can read it back to get a copy of the bytes then use it write to the Request Stream and calculate the hash.
This change is available from v4.5.7 that’s now on MyGet.
Before I go there. Isn’t it also possible to override Send() and calculate my hash and set the headers there too?
(I think I saw you do something similar in the EncryptedServiceClient)
EncryptedServiceClient works differently, it’s not overriding Send, it’s converting the Request DTO into another EncryptedMessage Request DTO and sending that using an internal client instead.
Now looking at the call to SerializeRequestToStream from SendRequest the IRequest is going to be null, which means once I override and calculate my hash, I wont be able to set the value of the hash to a headers of the request.
How am I going to do this?
var hash = calculateHash(stream);
request.Headers.Add("X-Hub-Signature", hash);
OK we now have a problem in the example you gave me.
SerializeRequestStream, line: 912 closes the passed in [MemoryStream] stream, so the example throws because the stream is closed before we can use it to calculate the hash, and then write it to the requestStream again.
I could override SerializeRequestToStream and not close the stream, but first I’d need to know why you were closing it in the first place.
Can you remember why the stream is closed in this context? I see a few lines before that new streams are used in compression. Its a little hard to decipher what the intention was here.
Perhaps an optional parameter on the method to keep the stream open (by default not)?
OK any chance you could change the signature to include the optional param: keepOpen
protected virtual void SerializeRequestToStream(object request, Stream requestStream, bool keepOpen = false)
{
var str = request as string;
var bytes = request as byte[];
var stream = request as Stream;
if (str != null)
{
requestStream.Write(str);
}
else if (bytes != null)
{
requestStream.Write(bytes, 0, bytes.Length);
}
else if (stream != null)
{
stream.WriteTo(requestStream);
}
else
{
#if !SL5
if (RequestCompressionType == CompressionTypes.Deflate)
{
requestStream = new DeflateStream(requestStream, CompressionMode.Compress);
}
else if (RequestCompressionType == CompressionTypes.GZip)
{
requestStream = new GZipStream(requestStream, CompressionMode.Compress);
}
#endif
SerializeToStream(null, request, requestStream);
if (!keepOpen)
{
requestStream.Close();
}
}
}
Its not going to break anything, since you only just made the method protected.
AND I would not have to worry about COMPILER variables like SL5 in our library.
I could then call it with KeepOpen = true and close the stream after I’ve done my thing with it.