REST Webservice for HTML5 Server Side Events - c#

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 ;)

Related

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

Get XML response when calling webservice method

Is it possible to get XML response parallel with calling webservice method;
For example:
var ws = new WebReference.WService();
String result = ws.HelloWorld();
I need to get XML response from webservice for HelloWorld() function like
<string xmlns="http://tempuri.org/">Hello World</string>
and parallel string result in variable result = "Hello World"
In order to avoid calling the same method twice, you'll need to move to a WCF approach, implementing an IEndpointBehavior behavior to read the raw communication with your webservice endpoint.
An example for such behavior can be found at Generic WCF Host.
This is answer https://stackoverflow.com/a/13779722/1179895. But it is necessary to add service reference to project as a service, NOT webservice.

How to upload data with Microsoft.Net.Http?

In the past I made a class that shunk the request on an endpoint. Now, I create a dll that include this method, this is the code that I'm trying to convert on this library:
using (var client = new HttpClient())
{
string requestJson = JsonConvert.SerializeObject(data);
client.DefaultRequestHeaders.Add("token", token);
byte[] responseArray = client. 'there is no upload data method
// the bottom code is of the old method
byte[] responseArray = client.UploadData(requestURI, method, Encoding.UTF8.GetBytes(requestJson));
return Encoding.ASCII.GetString(responseArray);
}
In the not portable library System.Net I can call client.UploadData, but here I see only : postAsync and putAsync, there is a method that independent from the put or post request allow me to send the data from the client to the server? Thanks in advance.
In your old code you used some method passed in method parameter to send data with UploadData method, and it was probably POST or PUT. If you do not specify the method for UploadData, POST is being used. So you should use PostAsyncor PutAsync, based on you current code and the value of method parameter you pass to UploadData.
The simplest way would be to use something like this:
using(var client = new HttpClient())
{
var response = await client.PostAsJsonAsync(requestUrl, data);
return await response.Content.ReadAsStringAsync();
}
The code for PUT would be the same, but with PutAsJsonAsync
In an HTTP request PUT and POST are the correct ways to transmit data to a server, it does not make sense to send data independently of these methods. When you are using a client such as that available in System.Net this is merely being abstracted away from you.

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

WCF deserialization trying to convert xml parameter to object when I just want the string

I am writing a WCF service stub to 'mimic' an existing VB6 service that exists. The stub needs to accept a single parameter which is a string, perform some logic and return a string.
The issue I am having is given the following method on the service contract
[OperationContract]
[WebInvoke(Method = "POST",
UriTemplate = "lookup")]
string LookupItem(string requestXml);
When I post a message in fiddler I get the error
The server encountered an error
processing the request. The exception
message is 'Unable to deserialize XML
body with root name 'XmlRoot' and
root namespace '' (for operation
'LookupItem' and contract
('IServiceStub',
'http://tempuri.org/')) using
DataContractSerializer. Ensure that
the type corresponding to the XML is
added to the known types collection of
the service.'.
Is WCF trying to deserialize my XML into an object, even though I don't want it to? The string is being sent as text/xml because the service it's mimicking has to receive the POST as text/xml. Is there something I'm missing?
Overcame this with the following:
public Stream LookupItem(Message requestXml)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
string responseXml = "<whatever />";
return new MemoryStream(Encoding.UTF8.GetBytes(responseXml ));
}

Categories