How to obtain header values from Client Message Inspector in WCF - c#

I'm creating a web test client for some services I'm working on, and as part of the requirements for that, I would like to be able to display the full request and response SOAP messages (and HTTP headers to the user).
I implemented a MessageInspector class implementing IClientMessageInspector, most notably the BeforeSendRequest and AfterReceiveReply methods to get access to the request & response messages respectively.
Capturing the response (AfterReceiveReply) works great, but capturing the request only partially works. I can access most of the message, however the SOAP header and HTTP headers are both empty. Viewing the request in Fiddler, I can see that WCF is sending a Security header in the SOAP message and "a bunch" of HTTP headers.
My BeforeSendRequest method is very simple...the gist of it is...
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
this.RequestMessage = request.ToString(); // Security header is missing from message
// Try to get HTTP headers
object req; // req is always null
if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out req))
{
this.RequestHeaders = ((HttpRequestMessageProperty)req).Headers;
}
return null;
}
I'm not sure why the HTTP and Security headers are missing. Is there a better way to do this?
Wayne

The inspectors look at the messages right after the message exists the formatter, and before it reaches any of the protocol channels (such as security) which will (potentially) change the message before passing it over (see the diagram in the post about WCF channels at https://learn.microsoft.com/en-us/archive/blogs/carlosfigueira/wcf-extensibility-channels). So at the inspector level you won't be able to find any additional SOAP headers added by the message. The HTTP headers are added by the transport which is also reached after the message passes through the message inspector.
If you want to see all the SOAP headers in the message, you can either create a new "protocol" channel (the sample at http://msdn.microsoft.com/en-us/library/ms751495.aspx does exactly that) or a new message encoder (it can wrap the existing encoder, and inspect the outgoing messages right before they're encoded).
To be able to see the HTTP headers it's harder, since the transport is the last part through which the message passes in WCF. I think you could write a custom transport channel to do that, but that would definitely be a lot of code.

Related

JSON Decoder in custom pipeline is not working

I am using BizTalk+ESB. I send a request to a REST service. Using this pipeline.
Which uses the JSONEncoder. The rest service posts a message in the event log, letting me know the process was completed. The issue is, on the response, I get this error:
"The content type application/json; charset=utf-8 of the response message does not match the content type of the binding (application/soap+xml; charset=utf-8)."*
This is the response pipeline:
It acts as if the JSONDecoder is not processing the response message.
The request is made using ESB Itinerary, and a WCF Web Service in BizTalk.
Any suggestions?
UPDATE - The call to the Rest service is in an Itinerary Service. WCF_WebHttp was not in the list of selections. Selected WCF-BasicHttp.
Now I receive the error: "There was a failure executing the response(send) pipeline: "PTwoMapPipeline.Part2RetMapPipeline, PTwoMapPipeline, Version=1.0.1.3, Culture=neutral, PublicKeyToken=7de7b3b357ccad5e" Source: "XML assembler" Receive Port: "WcfReceivePort_WCFInitiator/Service1" URI: "/WCFInitiator/Service1.svc" Reason: The document type "http://schemas.xmlsoap.org/soap/envelope/#Envelope" does not match any of the given schemas."
on the return Pipeline in my receive location. (Two way). Does this mean I need to add an Envelope schema. The Message is set in Receive location to use the body.
You need to use the WCF-WebHttp Adapter for a RESTful service. See WCF-WebHttp Adapter (Microsof.com)
Microsoft BizTalk Server uses the WCF-WebHttp adapter to send messages to RESTful services. The WCF-WebHttp send adapter sends HTTP messages to a service from a BizTalk message. The receive location receives messages from a RESTful service. For GET and DELETE request, the adapter does not use any payload. For POST and PUT request, the adapter uses the BizTalk message body part to the HTTP content/payload.
The WCF-WSHttp is expecting a SOAP envelope and XML see What Is the WCF-WSHttp Adapter? (Microsof.com).
The WCF-WSHttp adapter provides full access to the SOAP security, reliability, and transaction feature

C# WSDL Client Request Packages

I am currently adding a SOAP-WSDL Service to my project using "Add Service Reference". it creates all necessary classes and functions for me to call. Some of these functions dont give me a response. After 1 minute delay i get a timeout exception. However when i forge the request using Postman (a chrome extension for making network requests) it gets full response. i got suspicious and started to inspect network using Wireshark. after inspection i saw that problem was at the service. but i can't make them fix that. so i need to imitate Postman request using C#.
Main difference between mine and postman is, Postman posts all necessary data in single request for a response, but my client posts just http headers waits for a Http Continue and continues sending necessary data. i guess this breaks the service.
Here are wireshark screenshots for Postman and my client
(Postman is on the left of image and right one is my .net client - sorry for my perfect paint skills)
Is there any configuration on .net wsdl client with basicHttpBinding i can configure to make single request for a call?
edit: when i further investigated my C# client i saw that .net http layer send an initial POST with saying (Expect: 100 Continue), after it receives continue it continues to send SOAP Envelope
edit2: i changed my code to issue request using HttpWebRequest, but .net still sends header and post body with seperate requests (even when i disabled Expect: 100 Continue) and in my theory this breaks service.
question2: is there anyway to say HttpWebRequest, don't split header and body? send all of them in single request?
edit3: i solved the problem. but it wasn't about 100 Continue. service was being broken because of missing User-Agent Header
For HttpWebRequest you can add the following to your .config file - we use this on our service. I'm not, however, sure how it impacts WCF channels.
<configuration>
<system.net>
<settings>
<servicePointManager expect100Continue="false" />
</settings>
</system.net>
</configuration>
i finally solved the problem. after long inspections and tries i saw that remote service stops responding in the middle of the data communication if i dont add User-Agent HTTP Header. so i added http header using IClientMessageInspector before every request
here is wcf code if anybody needs it
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
HttpRequestMessageProperty realProp;
object property;
//check if this property already exists
if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out property))
{
realProp = (HttpRequestMessageProperty) property;
if (string.IsNullOrEmpty(realProp.Headers["User-Agent"])) //don't modify if it is already set
{
realProp.Headers["User-Agent"] = "doktorinSM/2.1";
}
return null;
}
realProp = new HttpRequestMessageProperty();
realProp.Headers["User-Agent"] = "doktorinSM/2.1";
request.Properties.Add(HttpRequestMessageProperty.Name, realProp);
return null;
}

Inspect headers set by WebClient proxy

I'm executing request through some free proxy servers, and I would like to know what headers each proxy server sets. Right now I'm visiting a page that prints out the result in the html body.
using(WebClient client = new WebClient())
{
WebProxy wp = new WebProxy("proxy url");
client.Proxy = wp;
string str = client
.DownloadString("http://www.pagethatprintsrequestheaders.com");
}
The WebClient doesn't show the modified headers, but the page prints the correct ones. Is there any way to find out what headers that are being set by the proxy without visiting a page that prints them like in my example? Do I have to create my own http listener?
When the proxy server sets its own headers, it is essentially performing its own web request. It can even hide or override some of the headers that you set using your WebProxy.
Consequently, only the target page (pagethatprintsrequestheaders.com) can reliably see the headers being set by the proxy. There is no guarantee that the proxy server will send back the headers that it had sent to the target, back to you.
To put it another way, it really depends on the proxy server implementation. if the proxy server you are using is based on Apache's ProxyPass, you'd probably see the headers being set! If it's a custom implementation, then you may not see it.
You can first try inspecting the client.ResponseHeaders property of the WebClient after your response comes back. If this does not contain headers matching what (pagethatprintsrequestheaders.com) reports, then it's indeed a custom or modified implementation.
You could then create your own proxy servers, but this is more involved. You would probably spin up an EC2 instance, install Squid/TinyProxy/YourCustomProxy on it and use that in your WebProxy call.
You may also want to modify your question and explain why you want to read the headers. There may be solutions to your overall goal that don't require reading headers at all but could be done in some other way.
It looks like your sending a request from your WebClient, through the proxy and its received by the host at www.pagethatprintsrequestheaders.com.
If the proxy is adding headers to the request, your webclient will never see them on it's request.
webclient proxys request
request with headers added
client -----------> proxy ----------------------> destination host
The webclient can only see the state of the request between it and the proxy. The proxy will create a new request to send to the destination host, and its that request to which the headers are added. It also that request that is received by the destination host (which is why when it echoes back the headers it can see those added by the proxy)
When the response comes back, the headers are set by the host. It's possible that the proxy will add some headers to the response, but even if it did, they are not likely to be the same headers it adds to a request.
response response
(forwarded by proxy) (headers set by host)
client <------------------- proxy <------------------------- destination host
Using a host that echo the headers back as part of the response payload is one option.
Another would be to use something between the proxy and the destination host to inspect the request there (e.g a packet sniffer or another proxy like Fiddler that lets you see the request headers).
If the proxy is outside of you network, getting between the proxy and the destination host will be difficult (unless the host is under your control).

Http Header Throws Exception C# HttpResponseMessage

Okay I'm developing a sevice application that runs on Cisco IP Phones. The application involves displaying messages to the phone.
I would like to make use of the way CISCO phones use the Expires header in a http Response. Basically a message i send to the phone will expire when the time specified in the header is reached (expired messages are removed from the message stack). The full documentation can be read at this address
http://www.cisco.com/en/US/docs/voice_ip_comm/cuipph/all_models/xsi/3_3_4/english/programming/guide/ip334ch5.html#wp1030621
In my C# WebService i construct the response using a HttpResponseMessage. Before i return my response i add the Expires header using
response.Headers.Add("Expires", "-1"); //Immediately expires.
My problem:
The previous line of code throws an InvalidOperationException
with the message Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage
I believe that the HttpResponseMessage is performing some validation and that Expires is not a valid response header. But its what the CISCO stuff requires.
Can i force this key value into the header even though its not strictly correct HTTP
The Expires header is on the Content object.
response.Content.Headers.Expires = new DateTimeOffset(DateTime.UtcNow.Add(new TimeSpan(0,0,0,5)));

.Net 4. View consumed web service headers and body from request and response

We're consuming a web service (web reference, not service reference), and I need a way to output the entire message being sent (including headers) and the message that gets received.
When I add the web reference, the generated base type of the client object to send the messages is System.Web.Services.Protocols.SoapHttpClientProtocol
I send the messages like so:
ApiService api = new ApiService();
// set the certificate and basic http network credentials
var response = api.SendRequest(messageObject);
I'm able to get the body of the request by serializing messageObject, but can't figure out how to get the full message with the headers.
Since I'm using a certificate and basic authentication, tools like Fiddler, etc. aren't getting me what I need, so I believe I have do something programmatically to pull whats sent and whats received prior to being encrypted with ssl.
EDIT
What I want to see if the data being sent and received to another service from within my WCF service.... e.g.:
// this function is within my WCF service
public ResponseModel Auth()
{
// call to another service here... need to trace this
}
If this is for tracing purposes I have had some success using the tracing capabilities of the System.Net libraries, you should be able to enable the tracing through configuration only.
It's described here: How to: Configure Network Tracing
The resulting log file isn't the easiest to follow, but is described here: Interpreting Network Tracing

Categories