Wednesday 31 July 2013

List<string> to string

var strings = new List<string> { "blah", "de", "hoo", "ha" };

var result = strings.Aggregate((i, j) => i + " " + j);

Console.Write(result);
image001

And with a complex type, where a response has a collection of messages, each with a text property:

var messages = this.Response
.Messages
.Select(m => m.Text)
.Aggregate((i, j) => i + " " + j);

Friday 19 July 2013

Sequential vs Parallel Service Requests

Sequential

image
public async Task<HttpResponseMessage> DownloadWithHttpClient()
{
var httpClient = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "http://stevenhollidge.com/sample.json?" + DateTime.Now.Ticks);
var response = await httpClient.SendAsync(request);
return response;
}

private async void HttpClientGoButton_OnClick(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 9; i++)
{
await DownloadWithHttpClient();
}
}

Parallel


image
public async Task<HttpResponseMessage> DownloadWithHttpClient()
{
var httpClient = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "http://stevenhollidge.com/sample.json?" + DateTime.Now.Ticks);
var response = await httpClient.SendAsync(request);
return response;
}

private async void HttpClientGoButton_OnClick(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 9; i++)
{
DownloadWithHttpClient();
}
}

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

Calling a WCF service over SSL with a certificate

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="binding_Default" maxReceivedMessageSize="2147483647">
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="endpointBehavior">
<clientCredentials>
<clientCertificate storeLocation="CurrentUser"
storeName="My"
findValue="28dfc90a0d22763ca41bb937e91925e10f9de7a4"
x509FindType="FindByThumbprint"/>
<serviceCertificate>
<authentication certificateValidationMode="None" revocationMode="NoCheck"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="https://SERVERNAME/SERVICENAME"
binding="basicHttpBinding"
bindingConfiguration="binding_Default"
contract="NAMESPACE.INTERFACE"
name="MyServiceEndpoint"
behaviorConfiguration="endpointBehavior">
</endpoint>
</client>
</system.serviceModel>
</configuration>

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