Silverlight Networking - Getting credentials to work, unsuccessful.
TweetOne of the things the Silverlight Networking stack lacks is the support for credentials. Where we have things like the below in the full CLR, Silverlight doesn't have any support.
httpWebRequest.Credentials = new NetworkCredential(username, password);
Investigation
So what about some investigation of the use of credentials. I remembered something about the usage of request headers for sending credentials. After a few minutes googleing I got support from a page on Oreilly about HTTP Headers. I found out the headername is "Authorization" and the value consist of authorization scheme and the credentials base64 encoded.
Tryout in full CLR
I tried to get it to work within the full CLR. I made two extension methods, one to set the RequestHeader and the other to convert a string to base64 encoding. As you can see the username and password will be divided by a colon before encoding the string to base64.
This code seemed to work on the CLR. So I thought very nice, on to the limited Silverlight CLR.
1 internal static class Extensions 2 { 3 public static void SetCredentials(this WebRequest request, string username, string password) 4 { 5 request.Headers["Authorization"] = string.Format("Basic {0}", 6 string.Format("{0}:{1}",username, password).EncodeTo64()); 7 } 8 9 public static string EncodeTo64(this string toEncode) 10 { 11 byte[] toEncodeAsBytes 12 = Encoding.ASCII.GetBytes(toEncode); 13 14 string returnValue 15 = Convert.ToBase64String(toEncodeAsBytes); 16 return returnValue; 17 } 18 }
Trying to get it to work with the Silverlight CLR
The first thing I had to do was to change the Encoding to use Encoding.Unicode, the ASCII character set isn't available as it seems. After this all the compilation errors were gone. But something very frustrating came around: "Error: This header must be modified using the appropriate property." Was I doing something wrong? It worked on the full CLR, why not within Silverlight?
After an investigation with Reflector I found out about a line of code that checks if a header is supported. A few clicks further and there was the list of not allowed headers.
And this list sadly also contains the headername "Authorization". I also found out that the list of allowed headers has a length of 12 headers. But also new custom headers are supported. The lists below are read from doing some inspection with Reflector.
List of unsupported headers: Allow, Accept, Authorization, Accept-Charset, Accept-Encoding, Accept-Language, Cookie, Connection, Content-Type, Content-Range, Content-Length, Content-Location, Date, Expect, Host, Keep-Alive, Last-Modified, Max-Forwards, Proxy-Authorization, Range, Referer, TE, Trailer, Transfer-Encoding, Upgrade, User-Agent, Via, Warning, Allowed, Connect, Content-Transfer-Encoding, Delete, Get, Head, Options, Post, Proxy-Connection, Public, Put, Request-Range, Trace, Uri, X-Flash-Version, Accept-Ranges, Age, ETag, Location, Proxy-Authenticate, Retry-After, Server, Vary, WWW-Authenticate.
List of supported headers: Cache-Control, Content-Encoding, Content-Language, Content-MD5, Expires, From, If-Match, If-Range, If-None-Match, If-Modified-Since, If-Unmodified-Since, Pragma. Besides this also custom headers are supported.
I hope we get support for using credentials within requests as soon as possible. Almost all services on the web use some form of credentials don't they?




Mark Monster on SL Networking (2), Andy Beaulieu on finding XAML elements, chrishayuk with SL2 Wee Mee
I've also been looking for support of basic authentication in Silverlight, which seems to be missing from this current release. Hopefully, they'll add it in RC. I suppose the only way to go about this right now is to write a service that SL communicates with. Btw, which part of the assemblies did you find the restriction on the headers?
Nice work on the code above :)
<code>
static HeaderInfoTable()
{
HeaderInfo[] infoArray = new HeaderInfo[] {
new HeaderInfo("Allow", true, true), new HeaderInfo("Accept", true, true), new HeaderInfo("Authorization", true, true), new HeaderInfo("Accept-Charset", true, true), new HeaderInfo("Accept-Encoding", true, true), new HeaderInfo("Accept-Language", true, true), new HeaderInfo("Cookie", true, true), new HeaderInfo("Connection", true, true), new HeaderInfo("Content-MD5", false, false), new HeaderInfo("Content-Type", true, false), new HeaderInfo("Cache-Control", false, true), new HeaderInfo("Content-Range", true, false), new HeaderInfo("Content-Length", true, false), new HeaderInfo("Content-Encoding", false, true), new HeaderInfo("Content-Language", false, true), new HeaderInfo("Content-Location", true, false),
new HeaderInfo("Date", true, false), new HeaderInfo("Expect", true, true), new HeaderInfo("Expires", false, false), new HeaderInfo("From", false, false), new HeaderInfo("Host", true, false), new HeaderInfo("If-Match", false, true), new HeaderInfo("If-Range", false, false), new HeaderInfo("If-None-Match", false, true), new HeaderInfo("If-Modified-Since", false, false), new HeaderInfo("If-Unmodified-Since", false, false), new HeaderInfo("Keep-Alive", true, false), new HeaderInfo("Last-Modified", true, false), new HeaderInfo("Max-Forwards", true, false), new HeaderInfo("Pragma", false, true), new HeaderInfo("Proxy-Authorization", true, true), new HeaderInfo("Range", true, true),
new HeaderInfo("Referer", true, false), new HeaderInfo("TE", true, true), new HeaderInfo("Trailer", true, true), new HeaderInfo("Transfer-Encoding", true, true), new HeaderInfo("Upgrade", true, true), new HeaderInfo("User-Agent", true, false), new HeaderInfo("Via", true, true), new HeaderInfo("Warning", true, true), new HeaderInfo("Allowed", true, false), new HeaderInfo("Connect", true, false), new HeaderInfo("Content-Transfer-Encoding", true, false), new HeaderInfo("Delete", true, false), new HeaderInfo("Get", true, false), new HeaderInfo("Head", true, false), new HeaderInfo("Options", true, false), new HeaderInfo("Post", true, false),
new HeaderInfo("Proxy-Connection", true, false), new HeaderInfo("Public", true, false), new HeaderInfo("Put", true, false), new HeaderInfo("Request-Range", true, false), new HeaderInfo("Trace", true, false), new HeaderInfo("Uri", true, false), new HeaderInfo("X-Flash-Version", true, false), new HeaderInfo("Accept-Ranges", true, false), new HeaderInfo("Age", true, false), new HeaderInfo("ETag", true, false), new HeaderInfo("Location", true, false), new HeaderInfo("Proxy-Authenticate", true, false), new HeaderInfo("Retry-After", true, false), new HeaderInfo("Server", true, false), new HeaderInfo("Vary", true, false), new HeaderInfo("WWW-Authenticate", true, false)
};
HeaderHashTable = new Dictionary(infoArray.Length * 2, CaseInsensitiveAscii.StaticInstance);
for (int i = 0; i