how to modify http header of request; web reference in C# - c#

I'm creating a .NET application that uses a web service. I need set the connection http header to "closed" in the request to that web service. I've been Googling this for a day but have not been able to get anything to work.
My best effort is the code below, which attempts to override the GetWebRequest method to add the header. This appears to fail - I place a breakpoint in it, and when I run my application, the breakpoint is never hit and the connection header does not appear to be set (I'm evaluating this not by viewing the http header but by the behavior of the system handling the web request).
Some information: when I added the web reference, using Visual Studio, I right-clicked on the project in the solution explorer, chose "Add Service Reference", "Advanced", then "Add Web Reference".
namespace System.Net
{
public class MyHttpProtocol : SoapHttpClientProtocol
{
protected override WebRequest GetWebRequest(Uri uri)
{
HttpWebRequest webRequest = (HttpWebRequest)base.GetWebRequest(uri);
webRequest.Headers.Add("connection", "closed");
return webRequest;
}
}
}

You need to use an IClientMessageInspector to alter the request as it's being constructed. This question is very similar and should give you the answer.
Many things in WCF involve creating behaviours and specifying them in the web config to override certain aspects of the process, which can be a bit fiddly but is very powerful. You can add your request in there.
Edit to address your comment, does your code look like this?
public object BeforeSendRequest(
ref System.ServiceModel.Channels.Message request,
System.ServiceModel.IClientChannel channel)
{
var httpRequestMessage = new HttpRequestMessageProperty();
httpRequestMessage.Headers.Add("connection", "closed");
request.Properties.Add(
HttpRequestMessageProperty.Name, httpRequestMessage);
return null;
}

Related

Setting Authorization Header to .Net Web Service Client

I know this has been asked a hundred times before, but I just can't get this working. I have a .Net web service client that needs to connect to an external web service that does not return 401 challenge response. I have to send the authentication header on the first call. I have overridden the GetWebRequest method of the generated proxy class by creating a partial class in another file. I have also added the method to the generated file to see if that makes a difference, but the code just does not get called. This was originally a .Net 3.5 Web Service Project created in VS 2013, but I have tried changing the target framework to 4.0, 4.5 e.t.c. and that does not have any effect.
The code I am using:
[System.Web.Services.WebServiceBindingAttribute(Name = "WSLDSD03_v1_webService_ValidationTicketCreation_Binder", Namespace = "http://llvap002d/WSLDSD03.v1.webService:ValidationTicketCreation")]
public partial class WSLDSD03_v1_webService_ValidationTicketCreation_Binder : System.Web.Services.Protocols.SoapHttpClientProtocol
{
protected override WebRequest GetWebRequest(Uri uri)
{
var request = base.GetWebRequest(uri);
string WSUID = ConfigurationManager.AppSettings["WSUID"];
string WSPWD = ConfigurationManager.AppSettings["WSPWD"];
string encoded = Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(WSUID + ":" + WSPWD));
request.Headers.Add("Authorization", "Basic " + encoded);
return request;
}
}
Update: I have since found that after a clean solution and rebuild the method does in fact get called if I move it into the generated class. It is the partial class in a separate file that appears to be the problem.
It turned out to be a simple coding error. I failed to notice that the namespace in the generated proxy file was like MyProject.WebReference, but in my separate file I used the main project namespace.

How to serialize an object into string\xml with its headers

I'm using a third side web service client (created by using the "Add service reference") in order to retrieve some data.
After filling the web service objects with proper data we need to add some data to the headers (encrypted password and some other predefined data)
Then, we are serializing every request sent to the web service, using the standard .net XmlSerializer.
However, in the result of the serialization I don't see the headers of the request. I've searched for a long time and couldn't find any way to "print" them as well.
Here is some example code:
Ibooking proxy = new BookingManager();
/* Init proxy Data...*/
GetAvailabilityRequest request = new GetAvailabilityRequest();
/*Fill more data on the request...*/
GetAvailabilityResponse response = proxy.GetAvailability(request); //Send request to the web service
var xmlString2 = response.Serialize(); //only body, no headers in the XML
/* Extension class to Serialize any object */
public static class ExtensionUtil
{
public static string Serialize<T>(this T value)
{
try
{
XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
var stringWriter = new StringWriter();
using (var writer = XmlWriter.Create(stringWriter))
{
xmlserializer.Serialize(writer, value);
return stringWriter.ToString();
}
}
catch (Exception ex)
{
throw new Exception("An error occurred", ex);
}
}
}
I've excluded the code that adds more data to the request since it's long and complicated (need to implement IEndpointBehavior and IClientMessageInspector to "catch" the request before we send it) - but currently as a workaround I put a BreakPoint on the Message object and convert it into string using Visual Studio. In this way I do see the headers but obviously this is bad practice since I want it to be automated in the serialization.
I would like to see an example of how you are adding these headers.
In most web services the message body is the part that is serialized into XML or JSON - the headers are not.
You may be able to inspect the service call by using Fiddler and a proxy implemented by a small change in your web.config as described in this article: http://weblog.west-wind.com/posts/2008/Mar/14/Debugging-Http-or-Web-Services-Calls-from-ASPNET-with-Fiddler.
The short version of this is to add the following to your web.config or app.config:
<system.net>
<defaultProxy>
<proxy proxyaddress="http://127.0.0.1:8888" />
</defaultProxy>
</system.net>
Download and run Fiddler while calling the service and you should see and be able to inspect the call in Fiddler.
If you want to inspect and/or modify the headers within your code base could look into implementing IClientMessageInspector or IDispatchMessageInspector. Here are a couple articles on the topic:
https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.iclientmessageinspector(v=vs.100).aspx
http://weblogs.asp.net/paolopia/writing-a-wcf-message-inspector
Here is an implementation I did. I didn't need access the headers, but rather to modify the xml namespaces created by the service client, but it should give you an idea on how to do the implementation: How can I create custom XML namespace attributes when consuming a legacy SOAP service?
OperationContext is your friend here. Use an OperationContextScope to wrap the call to the service, then use OperationContext.Current to get at all the hidden goodies you need.
https://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontextscope(v=vs.110).aspx
Note that you'll need to know the specific types of the headers you want to get at, and I've had some trouble getting at the values, rather than just the names, of headers if they're not marked as serializable when using XmlSerializer

C# Web API Request/Response Logging with OAuth

I am having a tough time figuring this out, but when I use a custom message handler in my Web API (created in VS2013) none of the /token request get processed through my handler.
What I'm trying to do is assist our support crew by implementing some logging to save request / response values for a few days. This will allow them to see the request and responses as raw as possible.
It's working, for everything except "/token" requests. We need to process the requests and responses for "/token" and "/authenticate" as a large percentage of our support calls end up being username and password issues.
I also need to do this in a message handler so I can isolate the code to message handlers.
Here is a sample handler I'm testing with in an isolated project. It's only in place ATM to debug/test this issue. I've also implemented a DelegatingHandler as well with the same results.
public class MyMessageProcessingHandler : MessageProcessingHandler {
protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) {
Trace.WriteLine(string.Format("{0} {1}", request.Method, request.RequestUri));
return request;
}
protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, System.Threading.CancellationToken cancellationToken) {
Trace.WriteLine("response!");
return response;
}
}
in WebApiConfig.Register method I add the message handler to the config's message handler collection.
(I also tried Global.asax.cs is the Application_Start method)
GlobalConfiguration.Configuration.MessageHandlers.Add(new MyMessageProcessingHandler());
The order doesn't seem to matter - I've tried it as the first line of code, or the last.I've tried to Insert after the passive message handler is added by
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new MyMessageProcessingHandler());
Whenever I make an api/Values request or any api/Controller request the custom message handler handles the request just fine. However, when I post (or get) to /token (yes-properly) the custom message handler doesn't process the request.
I would like to know how to use a Message Handler to process the /token & /authenticate requests. I appreciate all your help!
Thanks,
-Rick
I went with a custom IHttpModule. It ended doing what I wanted in the way I wanted it by giving me direct access to the requests and allowing me to inspect them; even the authentication requests.
Thanks to all that looked at my issue.

Get HTTP Header in WCF MessageEncoder

I'm currently writing a GZIP compression for my selfhosted WCF REST application. I have a custom implementation of the .NET 'MessageEncoder' class and a custom implementation of the 'WebContentTypeMapper' class .
How can I retrieve the http headers in the 'ReadMessage' function and in the 'GetMessageFormatForContentType' function? I'd like to check the incoming request for the 'Content-Encoding' header before decompressing the input.
Thank You.
This is what you can do
if (WebOperationContext.Current.IncomingRequest.Headers["Content-Encoding"] == WHAT YOU WANT)
{
// Do what you like to do here
}
Hope this helps.
Thanks.
You could try with WebOperationContext.Current or OperationContext.Current (depending of your binding).
But unfortunately i think you cannot do this within the MessageEncoder implementation itself because it's too late in the process because by the time the MessageEncoder is asked to write the message contents the message frame, in this case the HTTP headers, has already been written. So, you would also need additional behavior, in the form of an IOperationBehavior, applied to your operations that sets the headers accordingly.
In one of my personnal implementation, i have solved this by adding a GzipExtension in OperationContext with a custom message inspector.
As Alex said, IIS already have a feature called dynamic compression that can compression any configured content type.
I don't believe you will be able to get directly to the header from the CustomMessageEncoder. What you may be able to do is leverage the updated .NET 4.5 WCF BinaryMessageEncoderBindingElement. This now allows you to specify the compression type (such as Gzip) and automatically detects if the message body is compressed before attempting to decompress. See Whats's New in Windows Communication Foundation 4.5 for more details.
If you want to get to the header, one way you could try is to leverage HttpRequestMessageProperty in an implementation of IDispatchMessageInspector.
Simple example:
public class MyDispatchMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
object obj;
if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out obj))
{
var httpRequestMessageProperty = obj as HttpRequestMessageProperty;
if (httpRequestMessageProperty != null
&& !string.IsNullOrEmpty(httpRequestMessageProperty.Headers["content-encoding"]))
{
...
}
}
return null;
}
...
}
Another option is to access the OperationContext using the following:
int index = System.ServiceModel.OperationContext.Current.IncomingMessageHeaders.FindHeader("content-encoding", "");
string contentEncodeHeaderValue = System.ServiceModel.OperationContext.Current.IncomingMessageHeaders.GetHeader<string>(index);

What is the best way to download files via HTTP using .NET?

In one of my application I'm using the WebClient class to download files from a web server. Depending on the web server sometimes the application download millions of documents. It seems to be when there are lot of documents, performance vise the WebClient doesn't scale up well.
Also it seems to be the WebClient doesn't immediately close the connection it opened for the WebServer even after it successfully download the particular document.
I would like to know what other alternatives I have.
Update:
Also I noticed that for each and every download WebClient performs the authentication hand shake. I was expecting to see this hand shake once since my application only communicate with a single web server. Shouldn't the subsequent calls of the WebClient reuse the authentication session?
Update: My application also calls some web service methods and for these web service calls it seems to authentication session is reused. Also I'm using WCF to communicate with the web service.
I think you can still use "WebClient". However, you are better off using the "using" block as a good practice. This will make sure that the object is closed and is disposed off:-
using(WebClient client = new WebClient()) {
// Use client
}
I bet you are running into the default limit of 2 connections per server. Try running this code at the beginning of your program:
var cme = new System.Net.Configuration.ConnectionManagementElement();
cme.MaxConnection = 100;
System.Net.ServicePointManager.DefaultConnectionLimit = 100;
I have noticed the same behavior with the session in another project I was working on. To solve this "problem" I did use a static CookieContainer (since the session of the client is recognized by a value saved in a cookie).
public static class SomeStatics
{
private static CookieContainer _cookieContainer;
public static CookieContainer CookieContainer
{
get
{
if (_cookieContainer == null)
{
_cookieContainer = new CookieContainer();
}
return _cookieContainer;
}
}
}
public class CookieAwareWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
if (request is HttpWebRequest)
{
(request as HttpWebRequest).CookieContainer = SomeStatics.CookieContainer;
(request as HttpWebRequest).KeepAlive = false;
}
return request;
}
}
//now the code that will download the file
using(WebClient client = new CookieAwareWebClient())
{
client.DownloadFile("http://address.com/somefile.pdf", #"c:\\temp\savedfile.pdf");
}
The code is just an example and inspired on Using CookieContainer with WebClient class and C# get rid of Connection header in WebClient.
The above code will close your connection immediately after the file is download and it will reuse the authentication.
WebClient is probably the best option. It doesn't close the connection straight away for a reason: so it can use the same connection again, without having to open a new one. If you find that it's not reusing the connection as expected, that's usually because you're not Close()ing the response from the previous request:
var request = WebRequest.Create("...");
// populate parameters
var response = request.GetResponse();
// process response
response.Close(); // <-- make sure you don't forget this!

Categories