I wrote this helper class to assist with processing an Http Request via Silverlight 2. Since we can't provide a custom class by deriving from BrowserHttpWebRequest because it is internal I wrote this helper that will create and send the request and raise an event when the request completes. I am using it in my current game to send commands to the server and process the responses.
Edit: I revised the class slightly based on finding from Mike Briseno:
Edit: Some folks have experienced issues with this class after installing Silverlight 2 Beta 2. Be sure to check your domain access policy xml file for the new changes in beta 2 but if you experience issues feel free to contact me and we can try and figure them out.
Edit: Added HttpUtility.UrlEncode to the post values before writing them to the stream. Thanks for the suggestion Stefan!
using System;using System.Collections.Generic;using System.IO;using System.Windows;using System.Windows.Browser;using System.Windows.Controls;using System.Windows.Documents;using System.Windows.Ink;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Animation;using System.Windows.Shapes;using System.Net;namespace Lionsguard{ public class HttpHelper { private HttpWebRequest Request { get; set; } public Dictionary<string, string> PostValues { get; private set; } public event HttpResponseCompleteEventHandler ResponseComplete; private void OnResponseComplete(HttpResponseCompleteEventArgs e) { if (this.ResponseComplete != null) { this.ResponseComplete(e); } } public HttpHelper(Uri requestUri, string method, params KeyValuePair<string, string>[] postValues) { this.Request = (HttpWebRequest)WebRequest.Create(requestUri); this.Request.ContentType = "application/x-www-form-urlencoded"; this.Request.Method = method; this.PostValues = new Dictionary<string, string>(); if (postValues != null && postValues.Length > 0) { foreach (var item in postValues) { this.PostValues.Add(item.Key, item.Value); } } } public void Execute() { this.Request.BeginGetRequestStream(new AsyncCallback(HttpHelper.BeginRequest), this); } private static void BeginRequest(IAsyncResult ar) { HttpHelper helper = ar.AsyncState as HttpHelper; if (helper != null) { if (helper.PostValues.Count > 0) { using (StreamWriter writer = new StreamWriter(helper.Request.EndGetRequestStream(ar))) { foreach (var item in helper.PostValues) { writer.Write("{0}={1}&", item.Key, HttpUtility.UrlEncode(item.Value)); } } } helper.Request.BeginGetResponse(new AsyncCallback(HttpHelper.BeginResponse), helper); } } private static void BeginResponse(IAsyncResult ar) { HttpHelper helper = ar.AsyncState as HttpHelper; if (helper != null) { HttpWebResponse response = (HttpWebResponse)helper.Request.EndGetResponse(ar); if (response != null) { Stream stream = response.GetResponseStream(); if (stream != null) { using (StreamReader reader = new StreamReader(stream)) { helper.OnResponseComplete(new HttpResponseCompleteEventArgs(reader.ReadToEnd())); } } } } } } public delegate void HttpResponseCompleteEventHandler(HttpResponseCompleteEventArgs e); public class HttpResponseCompleteEventArgs : EventArgs { public string Response { get; set; } public HttpResponseCompleteEventArgs(string response) { this.Response = response; } }}
And this is how I am using it in my app:
private void ProcessCommand(short cmd, string msg) { App app = App.Current as App; HttpHelper helper = new HttpHelper(app.ServerUri, "POST", new KeyValuePair<string, string>("authKey", app.AuthKey), new KeyValuePair<string, string>("cmd", cmd.ToString()), new KeyValuePair<string, string>("msg", msg)); helper.ResponseComplete += new HttpResponseCompleteEventHandler(this.CommandComplete); helper.Execute(); } private void CommandComplete(HttpResponseCompleteEventArgs e) { txtAlert.Text = e.Response; }
For the VB Developers out there David Thiessen has converted my code to VB:
' Usage....'Private Sub ProcessCommand(ByVal cmd As Short, ByVal msg As String)' Dim app As App = TryCast(App.Current, App)' Dim helper As New HttpHelper(app.ServerUri, "POST", New KeyValuePair(Of String, String)("authKey", app.AuthKey), New KeyValuePair(Of String, String)("cmd", cmd.ToString()), New KeyValuePair(Of String, String)("msg", msg))' AddHandler helper.ResponseComplete, AddressOf CommandComplete' helper.Execute()'End Sub'Private Sub CommandComplete(ByVal e As HttpResponseCompleteEventArgs)' txtAlert.Text = e.Response'End Sub''' <summary>''' Converted C# code from http://www.cameronalbert.com/post/2008/03/HttpWebRequest-Helper-for-Silverlight-2.aspx''' </summary>''' <remarks></remarks>Public Class HttpHelper Private Property Request() As HttpWebRequest Get Return _Request End Get Set(ByVal value As HttpWebRequest) _Request = value End Set End Property Private _Request As HttpWebRequest Public Property PostValues() As Dictionary(Of String, String) Get Return _PostValues End Get Private Set(ByVal value As Dictionary(Of String, String)) _PostValues = value End Set End Property Private _PostValues As Dictionary(Of String, String) Public Event ResponseComplete As HttpResponseCompleteEventHandler Private Sub OnResponseComplete(ByVal e As HttpResponseCompleteEventArgs) RaiseEvent ResponseComplete(e) End Sub Public Sub New(ByVal requestUri As Uri, ByVal method As String, ByVal ParamArray postValues As KeyValuePair(Of String, String)()) Me.Request = DirectCast(WebRequest.Create(requestUri), HttpWebRequest) Me.Request.ContentType = "application/x-www-form-urlencoded" Me.Request.Method = method Me.PostValues = New Dictionary(Of String, String)() For Each item In postValues Me.PostValues.Add(item.Key, item.Value) Next End Sub Public Sub Execute() Me.Request.BeginGetRequestStream(New AsyncCallback(AddressOf HttpHelper.BeginRequest), Me) End Sub Private Shared Sub BeginRequest(ByVal ar As IAsyncResult) Dim helper As HttpHelper = TryCast(ar.AsyncState, HttpHelper) If helper IsNot Nothing Then Using writer As New StreamWriter(helper.Request.EndGetRequestStream(ar)) For Each item In helper.PostValues writer.Write("{0}={1}&", item.Key, HttpUtility.UrlEncode(item.Value)) Next End Using helper.Request.BeginGetResponse(New AsyncCallback(AddressOf HttpHelper.BeginResponse), helper) End If End Sub Private Shared Sub BeginResponse(ByVal ar As IAsyncResult) Dim helper As HttpHelper = TryCast(ar.AsyncState, HttpHelper) If helper IsNot Nothing Then Dim response As HttpWebResponse = DirectCast(helper.Request.EndGetResponse(ar), HttpWebResponse) If response IsNot Nothing Then Dim stream As Stream = response.GetResponseStream() If stream IsNot Nothing Then Using reader As New StreamReader(stream) helper.OnResponseComplete(New HttpResponseCompleteEventArgs(reader.ReadToEnd())) End Using End If End If End If End SubEnd ClassPublic Delegate Sub HttpResponseCompleteEventHandler(ByVal e As HttpResponseCompleteEventArgs)Public Class HttpResponseCompleteEventArgs Inherits EventArgs Public Property Response() As String Get Return _Response End Get Set(ByVal value As String) _Response = value End Set End Property Private _Response As String Public Sub New(ByVal response As String) Me.Response = response End SubEnd Class
3/7/2008