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

1 comment:

  1. I have set up my iis and fiddler and when i try to fire up my console app i get the following exception on the console app and it blows up

    '\\chi-file-01b\users\dpinto\my documents\visual studio 2013\Projects\ConsoleApp
    lication2\ConsoleApplication2\bin\Debug'
    CMD.EXE was started with the above path as the current directory.
    UNC paths are not supported. Defaulting to Windows directory.

    Unhandled Exception: System.Reflection.TargetInvocationException: An exception o
    ccurred during the operation, making the result invalid. Check InnerException f
    or exception details. ---> System.Net.WebException: An exception occurred during
    a WebClient request. ---> System.Configuration.ConfigurationErrorsException: Er
    ror creating the Web Proxy specified in the 'system.net/defaultProxy' configurat
    ion section. ---> System.Net.Sockets.SocketException: An invalid argument was su
    pplied
    at System.Net.SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily
    addressFamily, SocketType socketType, ProtocolType protocolType, Boolean autoRes
    et, Boolean signaled)
    at System.Net.NetworkAddressChangePolled..ctor()
    at System.Net.AutoWebProxyScriptEngine.AutoDetector.Initialize()
    at System.Net.AutoWebProxyScriptEngine.AutoDetector.get_CurrentAutoDetector()

    at System.Net.AutoWebProxyScriptEngine..ctor(WebProxy proxy, Boolean useRegis
    try)
    at System.Net.WebProxy.UnsafeUpdateFromRegistry()
    at System.Net.WebProxy..ctor(Boolean enableAutoproxy)
    at System.Net.Configuration.DefaultProxySectionInternal..ctor(DefaultProxySec
    tion section)
    at System.Net.Configuration.DefaultProxySectionInternal.GetSection()
    --- End of inner exception stack trace ---
    at System.Net.Configuration.DefaultProxySectionInternal.GetSection()
    at System.Net.WebRequest.get_InternalDefaultWebProxy()
    at System.Net.HttpWebRequest..ctor(Uri uri, ServicePoint servicePoint)
    at System.Net.HttpRequestCreator.Create(Uri Uri)
    at System.Net.WebRequest.Create(Uri requestUri, Boolean useUriBase)
    at System.Net.WebRequest.Create(Uri requestUri)
    at System.Net.WebClient.GetWebRequest(Uri address)
    at System.Net.WebClient.OpenReadAsync(Uri address, Object userToken)
    --- End of inner exception stack trace ---
    --- End of inner exception stack trace ---
    at System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary()
    at System.Net.OpenReadCompletedEventArgs.get_Result()
    at ConsoleApplication2.WebClientWrapper.OnOpenReadCompleted(Object sender, Op
    enReadCompletedEventArgs args) in \\chi-file-01b\users\dpinto\My Documents\Visua
    l Studio 2013\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 3
    0
    at System.Net.WebClient.OnOpenReadCompleted(OpenReadCompletedEventArgs e)
    at System.Net.WebClient.OpenReadOperationCompleted(Object arg)
    at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object sta
    te)
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionCo
    ntext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, C
    ontextCallback callback, Object state, Boolean preserveSyncCtx)
    at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWor
    kItem.ExecuteWorkItem()
    at System.Threading.ThreadPoolWorkQueue.Dispatch()
    at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
    Press any key to continue . . .

    ReplyDelete