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

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

Related

How to: c# XML InfoSet to JSON

So WCF takes a JSON, and for whatever reason translates that to an XML Infoset (see: https://stackoverflow.com/a/5684703/497745). It then reads back this XML Infoset internally using the JsonReaderDelegator (see: https://referencesource.microsoft.com/#System.Runtime.Serialization/System/Runtime/Serialization/Json/JsonReaderDelegator.cs,c0d6a87689227f04).
I am doing some very in-depth modification of the WCF execution flow, and I need to reverse the XML Infoset back to the original JSON.
Is there a library either in .NET or external that can take the XML Infoset generated by WCF and convert that back to its original JSON?
Found an answer that works in my scenario with some limited modifications.
This article: https://blogs.msdn.microsoft.com/carlosfigueira/2011/04/18/wcf-extensibility-message-inspectors/ explains how to log the JSON that originally came in to WCF, even though it is only exposed as an XML InfoSet. This was the key insight. Specifically, look at its MessageToString implementation.
Below is the relevant portion of my code, based on the implementation of MessageToString in the above link, running within a class internal class MessageFormatInspector : IDispatchMessageInspector, IEndpointBehavior that I have written to inject into the WCF stack:
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
...
var s = GetJsonFromMessage(request);
...
}
private static string GetJsonFromMessage(ref Message request)
{
using (MemoryStream ms = new MemoryStream())
{
using (XmlDictionaryWriter writer = JsonReaderWriterFactory.CreateJsonWriter(ms))
{
request.WriteMessage(writer);
writer.Flush();
string json = Encoding.UTF8.GetString(ms.ToArray()); //extract the JSON at this point
//now let's make our copy of the message to support the WCF pattern of rebuilding messages after consuming the inner stream (see: https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.idispatchmessageinspector.afterreceiverequest(v=vs.110).aspx and https://blogs.msdn.microsoft.com/carlosfigueira/2011/05/02/wcf-extensibility-message-formatters/)
ms.Position = 0; //Rewind. We're about to make a copy and restore the message we just consumed.
XmlDictionaryReader reader = JsonReaderWriterFactory.CreateJsonReader(ms, XmlDictionaryReaderQuotas.Max); //since we used a JsonWriter, we read the data back, we need to use the correlary JsonReader.
Message restoredRequestCopy = Message.CreateMessage(reader, int.MaxValue, request.Version); //now after a lot of work, create the actual copy
restoredRequestCopy.Properties.CopyProperties(request.Properties); //copy over the properties
request = restoredRequestCopy;
return json;
}
}
}
Unfortunately, the above code only works within the context of a WCF message inspector.
However, it is able to take an XMLDictionary, which has the XML InfoSet, and to using WCF's own built in JsonWriter to reverse the conversion WCF did and emit the original JSON.
I hope this helps someone save some time in the future.

Using JSON and HTTP Request in C#

I'm currently developing an Android app and I'm using Connect Android to MS SQL Server Tutorial to link my MSSQL server to the code.
And the first part is good though the second part is using a third party program to code which I don't want to. I want to write the whole code in C# (I'm using Xamarin).
I found out Json.NET / Json.NET for Xamarin website.
Though how am I supposed to use the HTTPUtils and requests in C# ? An example would be great.
Also, I have kind of a newbie question, I'm trying to get to the root of the code I sent, the .aspx file, and I don't quite understand where the web method is, I am used to a seperate .asmx file containing [Web Method]s that define them and then I can use them freely by creating a web reference on an .aspx file, so, where is the web method in the code I sent ?
public static String getJsonData(String webServiceName,String parameter)
{
try
{
String urlFinal=SERVICE_URI+"/"+webServiceName+"?parameter=";
HttpPost postMethod = new HttpPost(urlFinal.trim()+""+URLEncoder.encode(parameter,"UTF-8"));
postMethod.setHeader("Accept", "application/json");
postMethod.setHeader("Content-type", "application/json");
HttpClient hc = new DefaultHttpClient();
HttpResponse response = hc.execute(postMethod);
Log.i("response", ""+response.toString());
HttpEntity entity = response.getEntity();
String responseText = EntityUtils.toString(entity);
string=responseText;
Log.i("Output", ""+responseText);
}
catch (Exception e) {
// TODO: handle exception
}
return string;
}

REST Webservice for HTML5 Server Side Events

At the moment I have an C# console application that exposes Web Services through WebServiceHost those web services are being used by an website but now I'm trying to add SSE to the site.
The code at the client is:
var source = new EventSource(server+'eventSource');
source.onmessage = function (event) {
alert(event.data);
};
But on the server side, when I try to define the contract:
[OperationContract]
[WebGet]
String EventSource();
What the service is returning service is a xml with a String.
What should I do on the server side to create a document available for SSE?
Thanks in advace
If you have an OperationContract, the return Type is always serialized as XML or optionaly as JSON. If you do not want the return value to be serialized define it as Stream.
[OperationContract]
[WebGet]
Stream EventSource();
// Implementation Example for returning an unserialized string.
Stream EventSource()
{
// These 4 lines are optional but can spare you a lot of trouble ;)
OutgoingWebResponseContext context = WebOperationContext.Current.OutgoingResponse;
context.Headers.Clear();
context.Headers.Add("cache-control", "no-cache");
context.ContentType = "text/event-stream"; // change to whatever content type you want to serve.
return new System.IO.MemoryStream(Encoding.ASCII.GetBytes("Some String you want to return without the WCF serializer interfering."));
}
If you build the stream yourself remember to exectute .Seek(0, SeekOrigin.Begin); before you return it.
EDIT:
Changed the command order to set the ContentType AFTER the Header gets cleard. Otherwise you would clear the freshly set ContentType too ;)

RESTful web service returning XML not JSON

I have this simple web service, right now it just looks to see if the part number is A123456789 and then it returns a model number. This will be replaced by logic that will be connecting into a database to check the partno against and then return the actual model number. But at this point I just need it to return some dummy JSON data. However when I use Fiddler and look at the call in the web broswer of http://localhost:PORT/Scan/Model/A123456789 it returns this
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Model: CVS-1679</string>
But when I do a GET in fiddler of the same URI I get
"Model: CVS-1679"
Only under the textview tab.
Why is it being returned in XML (in the browser and text in Fiddler) and not JSON, when I have setup my ResponseFormat to be JSON?
My Code:
[WebGet(UriTemplate = "Model/{partno}", ResponseFormat = WebMessageFormat.Json)]
public string Model(string partno)
{
if (partno == "A123456789")
{
string modelno = "CVS-1679";
return "Model: " + modelno;
}
else
{
string modelno = "CVS-1601";
return "Model: " + modelno;
}
}
ASP.NET webservice return XML / SOAP message by default. In case you want to return Json string, you would need to decorate the Webservice with [ScriptService] attribute. This inform the IIS that this service would be used by ASP.NET AJAX calls. These attribute are part of System.Web.Extensions.
You can define the web method response format by decorating the webmethod with ScriptMethod attribute.
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
However even after decorating the webservice and webmethod by these attribute, the response can still be in XML format. This behaviour happen when the client which makes the request does not set the Request Header content type as “application/json”.
Before return the method call from webmethod serialize to Json string using JavaScriptSerializer
Debugging WebService using Fiddler
It is quite easy to use fiddler to test webservice. Following figure is an example of how to call a Webservice which returns a json string. Note that the request content type is set to application/json. The parameters expected by webserivce is mentioed in the Request Body section.
Note that the request content type is set to application/json.
It is being returned in Json if you look at the format of the data you get...
key: value
or in your case
string Model = "CVS-1679"
When you view it in fiddler your seeing the raw serialization transport from one MS endpoint to the other. The serialisation & De-serialisation elements in the .NET framework take care of transporting it across the wire, so that when you get the object back into your .NET app at the calling end, you get a variable called Model with the value you expect.
If you try to send an entire class you'll see a lot of nested XML tags, but when you get the object in your code, you'll see a first class citizen in the object hierarchy.
The reason it appears in your browser is because, the browser doesn't know how to de-serialise it, and so just displays the text

Capturing raw HTTP POST Data during Exception

I have a WCF Service hosted in IIS/ASP.NET that accepts HTTP Post (not form post) of serialized objects.
If the client sends malformed requests (eg they're not serializing the object correctly) I'd like to log the message sent up.
We're already using ELMAH to capture unhandled exceptions, so simply attaching the post data would be the easiest option.
I can get the current HttpContext during an exception, however this does only contains the HTTP Header information.
My question is this: Is there some way of capturing the original HTTP POST request body? Or, failing that - a better way (without a reverse proxy) of capturing the input that caused the error?
Edit: Just to clarify, running packet-level capturing at all times isn't really suitable. I'm after a solution that I can deploy to Production servers, and which will have clients outside our control or ability to monitor.
Edit #2: A suggestion was made to access the Request.InputStream - this doesn't work if you're trying to read after WCF has read the request off the stream.
A sample piece of code to see how I've tried using this is here.
StringBuilder log = new StringBuilder();
var request = HttpContext.Current.Request;
if (request.InputStream != null)
{
log.AppendLine(string.Format("request.InputStream.Position = \"{0}\"", request.InputStream.Position));
if (request.InputStream.Position != 0)
{
request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
}
using (StreamReader sr = new StreamReader(request.InputStream))
{
log.AppendLine(string.Format("Original Input: \"{0}\"", sr.ReadToEnd()));
}
}
else
{
log.AppendLine("request.Inputstream = null");
}
log.ToString();
The ouput of log.ToString() is:
request.InputStream.Position = "0"
Original Input: ""
By the time it gets to your service the request is processed and not available to you.
However ... you could attach a message inspector. Message Inspectors allow you to fiddle with the message before it reaches your operation implementations. You could create a buffered copy of the message, and copy it into the OperationContext.Current.
Ugly hack of course, and it will mean memory overhead as now two copies of the message are floating about for every request.
Did you look at the System.Web.Request.InputStream Property? It should have exactly what you want.
How to "rewind" the InputStream Property.
if (Request.InputStream.Position != 0)
{
Request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
}
Another option you should look into is capturing this information with an HTTPModule on the BeginRequest event. The data should be there at BeginRequest event because I do not believe WCF picks up the request until after PostAuthenticateEvent.
from under ASP.NET (ASP web service under IIS) the following code helps:
if (request.InputStream.Position != 0)
{
request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
}
WCF maybe different (that is it Disposes InputStream after reading it)
Use fiddler. Free from MS. Works great.

Categories