«
January 2009
»
PreAuthenticate Property of WebRequest - Solution
The previous post explained that using the PreAuthenticate property of System.Net.WebRequest does not prevent two round-trips when making the first request for an HTTP resource protected by Basic Authentication. The workaround for this is to generate and set the HTTP Authorization header explicitly like this:
static string CreateAuthorization(string realm,
string userName, string password)
{
string auth = ((realm != null) && (realm.Length > 0) ?
realm + @"\" : "") + userName + ":" + password;
auth = Convert.ToBase64String(Encoding.Default.GetBytes(auth));
return auth;
}
The return value from this function can be used to set the Authorization header:
WebRequest req = WebRequest.Create(uri);
string auth = CreateAuthorization("cookcomputing.com", "user",
"password");
req.Headers["Authorization"] = "Basic " + auth;
This will result in a single round-trip for each request:
-
Client: GET /foo/foo.html HTTP/1.1
Authorization: Basic c3RvY2tsZXkuYXZheWEuY29tXGNoY29vazpBcmVuaWcxNjAh - Server: HTTP/1.1 200 OK
-
Client: GET /foo/bar.html HTTP/1.1
Authorization: Basic c3RvY2tsZXkuYXZheWEuY29tXGNoY29vazpBcmVuaWcxNjAh - Server: HTTP/1.1 200 OK
The same technique can be used with XML-RPC.NET, for example:
using System;
using System.Text;
using CookComputing.XmlRpc;
[XmlRpcUrl("http://localhost:81/xmlrpc/RPC2.ashx")]
public interface IStateName : IXmlRpcProxy
{
[XmlRpcMethod("examples.getStateName")]
string GetStateName(int stateNumber);
}
class Program
{
static string CreateAuthorization(string realm,
string userName, string password)
{
string auth = ((realm != null) && (realm.Length > 0) ?
realm + @"\" : "") + userName + ":" + password;
auth = Convert.ToBase64String(Encoding.Default.GetBytes(auth));
return auth;
}
static void Main(string[] args)
{
IStateName proxy = XmlRpcProxyGen.Create<IStateName>();
string auth = CreateAuthorization("cookcomputing.com", "user", "password");
proxy.Headers["Authorization"] = "Basic " + auth;
string ret = proxy.GetStateName(1);
}
}
PreAuthenticate Property of WebRequest - Problem
There is a common misunderstanding about how the PreAuthenticate property of .NET's System.Net.WebRequest class works, for example when using Basic Authentication. In this post I'll explain how it actually works and in the next post I'll describe how to use WebRequest to get the behaviour that is often erroneously expected when PreAuthenticate is used. Say this code is used to retrieve two HTTP resources:
using System;
using System.IO;
using System.Net;
class Program
{
static string Get(string uri)
{
WebRequest req = WebRequest.Create(uri);
req.Credentials = new NetworkCredential("user", "password",
"cookcomputing.com");
req.PreAuthenticate = false; // default for WebRequest
Stream stm = req.GetResponse().GetResponseStream();
string ret = new StreamReader(stm).ReadToEnd();
return ret;
}
static void Main(string[] args)
{
Console.WriteLine(Get("http://localhost:81/foo/foo.html"));
Console.WriteLine(Get("http://localhost:81/foo/bar.html"));
}
}
There will be four round-trips between the client and server (for the time being assume the server does not have HTTP Keep-Alive enabled):
- Client: GET /foo/foo.html HTTP/1.1
-
Server: HTTP/1.1 401 Access Denied
WWW-Authenticate: Basic realm=" cookcomputing.com" -
Client: GET /foo/foo.html HTTP/1.1
Authorization: Basic c3RvY2tsZXkuYXZheWEuY29tXGNoY29vazpBcmVuaWcxNjAh - Server: HTTP/1.1 200 OK
- Client: GET /foo/bar.html HTTP/1.1
-
Server: HTTP/1.1 401 Access Denied
WWW-Authenticate: Basic realm="cookcomputing.com" -
Client: GET /foo/bar.html HTTP/1.1
Authorization: Basic c3RvY2tsZXkuYXZheWEuY29tXGNoY29vazpBcmVuaWcxNjAh - Server: HTTP/1.1 200 OK
req.PreAuthenticate = true;
In fact this is what actually happens:
- Client: GET /foo/foo.html HTTP/1.1
-
Server: HTTP/1.1 401 Access Denied
WWW-Authenticate: Basic realm=" cookcomputing.com" -
Client: GET /foo/foo.html HTTP/1.1
Authorization: Basic c3RvY2tsZXkuYXZheWEuY29tXGNoY29vazpBcmVuaWcxNjAh - Server: HTTP/1.1 200 OK
- Client: GET /foo/bar.html HTTP/1.1
- Server: HTTP/1.1 200 OK
Note that if the server has enabled HTTP KeepAlive and the default value of true for HttpWebRequest.KeepAlive has not been changed, then assuming the connection remains open for the second request, the successful authorization for the first request will still apply and the use of PreAuthenticate is not required.
Avoiding Custom Delegates
I've been using the Func<...> and Action<...> delegates for a while now but I recently declared a custom delegate where I could have used Action<...>. Brad Abram's post Framework Design Guidelines: Avoiding custom delegates prompted me to change my code.
For reference here are the different versions of Action and Func:
public delegate void Action() public delegate void Action<T1>(T1 arg1) public delegate void Action<T1, T2>(T1 arg1, T2 arg2) public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3) public delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4) public delegate TResult Func<TResult>() public delegate TResult Func<T, TResult>(T arg) public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2) public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3) public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4)
Configuring a Factory with Unity
I've just started using Unity (v1.2) and in one scenario I need to be able to configure Unity with a factory for a type, rather than default to Unity creating an object of the type configured for the requested type. In my case the object implementing the interface is a Remoting proxy but say, for example, I have interface IFoo implemented by class Foo and I want instances of IFoo returned by Unity to be instances of Foo created by a factory class:
interface IFoo
{
void DoFoo();
}
class Foo : IFoo
{
public void DoFoo()
{
Console.WriteLine("DoFoo: CreatedBy = {0}", CreatedBy);
}
public string CreatedBy { get; set; }
}
class FooFactory
{
static public IFoo CreateInstance()
{
Console.WriteLine("CreateInstance");
var foo = new Foo();
foo.CreatedBy = "Factory";
return foo;
}
}
The solution is to use Unity's StaticFactoryExtension. After creating the container, add the extension to the container and then register the factory:
using Microsoft.Practices.Unity; using Microsoft.Practices.Unity.StaticFactory; // ... IUnityContainer container = new UnityContainer(); container.AddNewExtension<StaticFactoryExtension>(); IStaticFactoryConfiguration config = container.Configure<IStaticFactoryConfiguration>(); config.RegisterFactory<IFoo>(unity => FooFactory.CreateInstance());
Finally we can request an instance of IFoo from the container:
IFoo foo = container.Resolve<IFoo>(); foo.DoFoo();
The following assembly references are required:
- Microsoft.Practices.ObjectBuilder2
- Microsoft.Practices.Unity
- Microsoft.Practices.Unity.StaticFactory
Use XmlWriter to Create XML without Encoding Attribute
I am currently modifiying XML-RPC.NET to support Silverlight 2. One problem I encountered is that when you use XmlWriter.Create to create an XML writer on top of a stream it is not possible pass a null encoding to specify that you don't want an encoding attribute in the XML declaration at the start of the document.
By default a StreamWriter created on top of the stream will result in an encoding of "utf-8". For example this program:
class Program
{
static void Main(string[] args)
{
FileStream stm = new FileStream(@"c:\temp\test.xml",
FileMode.OpenOrCreate | FileMode.Truncate);
WriteXml(stm);
}
static void WriteXml(Stream stm)
{
var stmWriter = new StreamWriter(stm);
var settings = new XmlWriterSettings();
var xmlWriter = XmlWriter.Create(stmWriter, settings);
xmlWriter.WriteStartDocument();
xmlWriter.WriteElementString("foo", "bar");
xmlWriter.Close();
}
}
Creates this document:
<?xml version="1.0" encoding="utf-8"?><foo>bar</foo>
If you try to specify a null encoding:
StreamWriter stmWriter = new StreamWriter(stm, null);
An instance of ArgumentNullException is thrown. A solution is to derive a class from StreamWriter and override the Encoding property:
public class EncodingStreamWriter : StreamWriter
{
Encoding _encoding;
public EncodingStreamWriter(Stream stm, Encoding encoding)
: base(stm)
{
_encoding = encoding;
}
public override Encoding Encoding
{
get { return _encoding; }
}
}
And then use this instead of StreamWriter:
var stmWriter = new EncodingStreamWriter(stm, null);
To create the desired XML document:
<?xml version="1.0"?><foo>bar</foo>