5

As per http://ayende.com/blog/4599/hunt-the-bug, I've run into one of those scenarios whereby "Response is not available in this context".

Greatly simplified, the following throws an exception in certain scenarios on Windows Server 2008/IIS7/ASP.NET 4.0

public class Global : HttpApplication
{
       public void Application_Start(object sender, EventArgs e)
       {
            HttpUtility.UrlEncode("Error inside!");
       }
}    

The solutions that I've seen involve one of the following:

  1. Do as Ayende did and "write my own HttpUtility (well, take the one from Mono and modify it) to avoid this bug."
  2. or determine whether using HttpEncoder.Default instead does the trick. I'm trying to track down how best to do this.
  3. or use Uri.EscapeDataString as per Server.UrlEncode vs. HttpUtility.UrlEncode

Maybe it's not my best googling day, but how to implement HttpEncoder.Default?

Recommendations?

Community
  • 1
  • 1
Ted
  • 6,898
  • 8
  • 45
  • 73

2 Answers2

3

You can try this for encoding

public static string UrlEncode(string s)
{
    return typeof(System.Net.WebClient).InvokeMember("UrlEncode", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new[] { "[#encoded] <data>" }) as string;
}

// by @DmitryDzygin
public static string UrlDecode(string s)
{
    return typeof(System.Net.WebClient).Assembly.GetType("System.Net.HttpListenerRequest+Helpers").InvokeMember("UrlDecodeStringFromStringInternal", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { s, Encoding.UTF8 }) as string;
}

And if you don't feel comfortable with or your application is not running in FULL trust level, try this

public class HttpUtils : System.Web.Util.HttpEncoder
{
    private static HttpUtils _encoder;
    internal static HttpUtils Encoder
    {
        get { return _encoder ?? (_encoder = new HttpUtils()); }
    }

    internal string InternalUrlEncode(string s)
    {
        var bytes = System.Text.Encoding.UTF8.GetBytes(s);
        var encodedBytes = base.UrlEncode(bytes, 0, bytes.Length);

        return System.Text.Encoding.UTF8.GetString(encodedBytes);
    }

    public static string UrlEncode(string s)
    {
        return Encoder.InternalUrlEncode(s);
    }
}

I Know it is not still the best way but what could the best way be if we don't use HttpUtility.UrlEncode!..

Beygi
  • 1,858
  • 1
  • 16
  • 22
  • 1
    Good job. Here's reflection/decoder part public static string UrlDecode(string urlPart) { return typeof(System.Net.WebClient) .Assembly .GetType("System.Net.HttpListenerRequest+Helpers") .InvokeMember("UrlDecodeStringFromStringInternal", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { urlPart, Encoding.UTF8 }) as string; } – Dmitry Dzygin Jun 24 '11 at 09:12
  • 1
    Thanks for the response. Have marked it as the answer even though I'm likely going to just adapt the mono version (see https://github.com/mono/mono/blob/master/mcs/class/System.Web/System.Web/HttpUtility.cs) simply because then I can also get away from a dependency on System.Web that is only there because of HttpUtility.UrlEncode. – Ted Jun 27 '11 at 17:57
3

Requires FULL trust

public static class DefaultHttpEncoder
{
    public static string UrlEncode(string urlPart)
    {
        using (new NoHttpContext())
        {
            return HttpUtility.UrlEncode(urlPart);
        }
    }

    public static string UrlDecode(string urlPart)
    {
        using (new NoHttpContext())
        {
            return HttpUtility.UrlDecode(urlPart);
        }
    }

    private class NoHttpContext : IDisposable
    {
        private readonly HttpContext _context;

        public NoHttpContext()
        {
            _context = HttpContext.Current;
            HttpContext.Current = null;
        }

        public void Dispose()
        {
            HttpContext.Current = _context;
        }
    }
}
Dmitry Dzygin
  • 1,173
  • 12
  • 23
  • Well done!..., but for those who might think it's tricky, no it's not because .net is skipping request to HttpContext.Current if it's null, and when isn't is exactly when that the bug is showing it self. – Beygi Jun 25 '11 at 12:24
  • Thanks for the response. Nice solution that I'll keep in mind for the future! However, although I unfortunately don't mention it in my question, full trust is not an option. – Ted Jun 27 '11 at 17:55
  • Good solution. Worked well for me. – Jomy John Jun 07 '12 at 09:30