Showing posts with label WebApi. Show all posts
Showing posts with label WebApi. Show all posts

Tuesday, 22 October 2013

Saturday, 6 July 2013

C# client for Server Side Events (EventSource)

Examples of one way streaming from server to client can be found on the web but it’s pretty much always JavaScript clients.  Here is a working example using the .NET stack, with WebAPI as the server and a C# console application as the client.

Download and run this WebAPI chat application which emits Server Side Events:

https://github.com/filipw/html5-push-asp.net-web-api/

I then open Visual Studio running as admin, update the code to use IIS with my machine name (Zeus) and a virtual directory, clicking the create virtual directory button, so I can track requests using Fiddler:

image

Then update the JavaScript within the app to use the same path:

image

The create a Console application, using NUGET add Json.NET and paste this code in:

using System;
using System.IO;
using System.Net;
using System.Text;
using Newtonsoft.Json;

namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
new WebClientWrapper();
Console.ReadKey();
}
}

public class WebClientWrapper
{
WebClient wc { get; set; }

public WebClientWrapper()
{
InitialiseWebClient();
}

// When SSE (Server side event) occurs this fires
private void OnOpenReadCompleted(object sender, OpenReadCompletedEventArgs args)
{
using (var streamReader = new StreamReader(args.Result, Encoding.UTF8))
{
var cometPayload = streamReader.ReadLine();
var jsonPayload = cometPayload.Substring(5);
var message = JsonConvert.DeserializeObject<Message>(jsonPayload);
Console.WriteLine("Message received: {0} {1} {2}", message.dt, message.username, message.text);
InitialiseWebClient();
}
}

private void InitialiseWebClient()
{
wc = new WebClient();
wc.OpenReadAsync(new Uri("http://zeus/chatapp/api/chat/"));
wc.OpenReadCompleted += OnOpenReadCompleted;
}
}

public class Message
{
public string username { get; set; }
public string text { get; set; }
public string dt { get; set; }
}
}


You’ll need to update the code for your machine name.


Now run Fiddler, the WebAPI project and the console app and add a message in the chat window:


image


In Fiddler, select the request your console just made and select Raw, you’ll see nothing.  Now right click and select COMETPeek and you’ll see the payload that was streamed.


image

Wednesday, 3 July 2013

WebApi.SelfHost

using System.Web.Http;
using System.Web.Http.SelfHost;

namespace Workflow.Console
{
class Program
{
static void Main(string[] args)
{
var config = new HttpSelfHostConfiguration("http://localhost:8080");

config.Routes.MapHttpRoute(
"API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional });

using (var server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
System.Console.WriteLine("Press Enter to quit.");
System.Console.ReadLine();
}
}
}
}
using System.Collections.Generic;
using System;
using System.Web.Http;
using System.Threading;
using System.Threading.Tasks;

namespace Workflow.Console
{
public class DocumentUploadController : ApiController
{
public Guid Post([FromBody] DocumentRequest reportData)
{
var id = Guid.NewGuid();
Task.Factory.StartNew(() => CreateReport(id.ToString(), reportData.Parameter1));
return id;
}

private void CreateReport(string key, string documentData)
{
Thread.Sleep(5000);
DocumentDownloadController.Cache.Add(key, "GENERATED DOCUMENT: " + documentData);
}
}

public class DocumentDownloadController : ApiController
{
public static Dictionary<string, string> Cache = new Dictionary<string, string>();

public DocumentResponse Get(string id)
{
string document;
var response = new DocumentResponse { Id = id };
if (Cache.TryGetValue(id, out document))
{
response.IsAvailable = true;
response.Document = document;
}
else
{
response.IsAvailable = false;
}
return response;
}
}

public class DocumentRequest
{
public string Parameter1 { get; set; }
}

public class DocumentResponse
{
public string Id { get; set; }
public bool IsAvailable { get; set; }
public string Document { get; set; }
}
}
image

image


image


image


With XML:


image


or add this line to Program Main and you can remove the namespace from the xml:

config.Formatters.XmlFormatter.UseXmlSerializer = true;

image

Saturday, 2 March 2013

How to return Jsonp from WebApi

This allows you to make service requests from jQuery to a different domain (cross site scripting).

1. Add a Formatters folder to your WebApi project and add the following class:

public class JsonpMediaTypeFormatter : JsonMediaTypeFormatter
{
private readonly HttpRequestMessage _request;
private string _callbackQueryParameter;

public JsonpMediaTypeFormatter()
{
SupportedMediaTypes.Add(DefaultMediaType);
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));

MediaTypeMappings.Add(new UriPathExtensionMapping("jsonp", "application/json"));
}

public JsonpMediaTypeFormatter(HttpRequestMessage request)
: this()
{
_request = request;
}

public string CallbackQueryParameter
{
get { return _callbackQueryParameter ?? "callback"; }
set { _callbackQueryParameter = value; }
}

public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
{
if (type == null)
throw new ArgumentNullException("type");
if (request == null)
throw new ArgumentNullException("request");

return new JsonpMediaTypeFormatter(request) { SerializerSettings = SerializerSettings };
}

public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext)
{
string callback;
if (IsJsonpRequest(_request, out callback))
{

var writer = new StreamWriter(stream);
writer.Write(callback + "(");
writer.Flush();

return base.WriteToStreamAsync(type, value, stream, content, transportContext).ContinueWith(_ =>
{

//TODO: Inspecting the task status and acting on that is better
writer.Write(")");
writer.Flush();
});
}

return base.WriteToStreamAsync(type, value, stream, content, transportContext);
}

private bool IsJsonpRequest(HttpRequestMessage request, out string callback)
{
callback = null;

if (request == null || request.Method != HttpMethod.Get)
{
return false;
}

var query = HttpUtility.ParseQueryString(request.RequestUri.Query);
callback = query[CallbackQueryParameter];

return !string.IsNullOrEmpty(callback);
}
}
image

2. Add a FormatterConfig class to your App_Start folder

public class FormatterConfig
{
public static void RegisterFormatters(MediaTypeFormatterCollection formatters)
{
formatters.Remove(formatters.JsonFormatter);
formatters.Insert(0, new JsonpMediaTypeFormatter
{
SerializerSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
}
});
}
}
image

3. Update your Global.asax.cs file to register the FormatterConfig

public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
FormatterConfig.RegisterFormatters(GlobalConfiguration.Configuration.Formatters);
}
}

That's it!


How to test your service call


Now your services can be called for Json or Jsonp.


Json


You can continue to get your Json response in the normal way:  http://localhost:2626/api/underlyings


image



image


image


Jsonp


You can now call your service passing in the callback to receive Jsonp:

$.getJSON("http://localhost:2626/api/underlyings/jsonp?callback=?", function (result) {
// process response
});

You’ll see here that the response wraps the data in a jQuery function.


image


image


image


Here’s the HTML code I used in this example:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Jsonp test</title>
<script src="Scripts/jquery-1.9.1.min.js" type="text/javascript"></script>
</head>
<body>
<button id="getjsonp">Get JSONP</button>
<h4>Request result:</h4>
<div id="jsonp"></div>

<script type="text/javascript">
$(document).ready(function () {
$("#getjsonp").click(function () {
$.getJSON("http://localhost:2626/api/underlyings/jsonp?callback=?", function (result) {
$(result).each(function(index, item) {
$('#jsonp').append('<p>' + item.currencyPair + '</p>');
});
});
});
})
</script>
</body>
</html>





For a working downloadable example I recommend downloading the WebApiContrib solution for Jsonp:


https://github.com/WebApiContrib/WebApiContrib.Formatting.Jsonp