Showing posts with label .net. Show all posts
Showing posts with label .net. Show all posts

Tuesday, January 26, 2010

Announcing ePubLib

I have published a project on CodePlex, ePubLib. ePub is quickly becoming the defacto standard for e readers, and after getting my hands on a (used and cheap) Sony Pocket Reader I wanted to be able to create documents to put on the device.

The format isn't particularly complicated, but there are a lot of little things that have to line up. This library makes it extremely easy. Create a Book object. Create 1 or more Chapter objects. Add the Chapter to Book.Chapters. Call Book.Save(). You can do the same thing for images as of the commit last night. The only knowledge that's required is basic XHTML skills and .NET to use the library.

I also wrote a utility to log me into The Economist's web site (I'm a paying subscriber) and scrape the Print Edition. It works great, a proper TOC, all of the articles and all of the images. I don't think I can upload that source to CodePlex due to perceived copyright concerns, but drop me a comment if you're interested.

Wednesday, December 16, 2009

Cookie Gotchas in ASP.NET

As a result of a recent security audit, we were asked to implement a more secure session identifier to help make session hijacking harder. Specifically, our requirements were:

  • Ensure that client-specified session IDs are system-generated
  • Generate a new session ID on login
  • Invalidate anonymous session IDs on login

We started following a strategy very similar to this solution on MSDN. If you don't click the link, the summary is, implement an HttpModule, in BeginRequest inspect the request cookie and extract & verify a hash from it, overwrite the Session ID cookie in the Request so that the underlying session implementation is unaware of any cookie mucking, and then on EndRequest write a new session cookie to the Response with a hash appended. The primary difference between that solution and ours is that ours encrypted the session ID and authentication information into the token so that we could meet the latter two requirements. (I'll blog about the specific solution at a later date.)

There's only one problem: it doesn't work. At all. You can't overwrite a Request cookie.

Sure, it works in trivial solution (including my POC), but if you modify the Response.Cookies collection, you lose your modifications to the Request.Cookies collection.

I cracked open Reflector to understand why. Take a look at System.Web.HttpCookieCollection.Remove(string):

public void Remove(string name)

{
    if (this._response != null)
    {

        this._response.BeforeCookieCollectionChange();
    }
    this.RemoveCookie(name);

    if (this._response != null)
    {
        this._response.OnCookieCollectionChange();

    }
}

And then System.Web.HttpResponse.OnCookieCollectionChange():

internal void OnCookieCollectionChange()
{

    this.Request.ResetCookies();
}

And as if this were necessary, System.Web.HttpRequest.ResetCookies():

internal void ResetCookies()

{
    if (this._cookies != null)
    {

        this._cookies.Reset();
        this.FillInCookiesCollection(this._cookies, true);

    }
    if (this._params != null)
    {

        this._params.MakeReadWrite();
        this._params.Reset();
        this.FillInParamsCollection();

        this._params.MakeReadOnly();
    }
}

Digging through the Analyzer, the cookies in the HttpRequest are reset by the following seemingly innocuous methods:

  • System.Web.HttpCookieCollection.Remove(String)
  • System.Web.HttpCookieCollection.Set(HttpCookie)
  • System.Web.HttpResponse.SetCookie(HttpCookie)

So if you ever try and overwrite a cookie in the HttpRequest, you had better not call any of those three methods, otherwise the cookies will get reloaded by parsing the original values from the raw request.

Final thoughts:

- You can use reflection to set HttpCookieCollection._response to null (from HttpResponse.Cookies), which then avoids the OnCookieCollectionChange call, but if you do, it will break other things, like automatic adding of cookies on accessing them. Like in System.Web.HttpCookieCollection.Get(string) (called by HttpCookieCollection this[string]):

public HttpCookie Get(string name)
{
    HttpCookie cookie = (HttpCookie) base.BaseGet(name);

    if ((cookie == null) && (this._response != null))

    {
        cookie = new HttpCookie(name);
        this.AddCookie(cookie, true);

        this._response.OnCookieAdd(cookie);
    }
    return cookie;

}

- I could only find one other person on the Internet who experience this problem.

- There's some other weirdness where adding a Response cookie resets the Request.Cookies collection, and adds the Response.Cookies to the Request.Cookies collection. You might be able to benefit from that; add a cookie to the Response.Cookies collection, call one of the methods that triggers resetting the Request cookies, and now your Response cookie will be one of the Request cookies. That didn't work in our case due to later cookie manipulation by the Session provider.

Tuesday, December 01, 2009

How to debug and step through Framework code

http://dotnetslackers.com/Visual_Studio/re-78109_Configuring_Visual_Studio_to_Debug_NET_Framework_Source_Code.aspx

Wednesday, November 25, 2009

Troubleshooting a Custom Resource Provider in ASP.NET

My current project is a large multi-lingual eCommerce engagement. Due to business requirements (on-the-fly updates), we externalized resources into a database (following this MSDN article). Furthermore due to business requirements (uptime for a very high revenue site with regular mid-day content updates), they need to be able to publish markup (aspx & ascx) on the fly without restarting IIS.

We were seeing a sporadic issue where resources would disappear on the page. For example, there was custom control that looked like so:

<custom:CustomHyperLink ID="TL" runat="server" ImageUrl="[Header Image]" SiteMapNodeId="Basket" ToolTip="[Header]" meta:resourcekey="HeaderImage" />

When everything was working (which was 99% of the time), the ImageUrl would be looked up at runtime (via the control's HeaderImage.ImageUrl resource) and substituted in as ~/images/en/header_en.gif. But when it didn't work, we would see an <img src="[Header Image]" />, which obviously is a problem.

Adding to the confusion was that only some of the resources showed this problem. Also, it was seemingly random. Everything would be working one minute, broken the next, in the middle of the day. Putting together steps to reproduce was nearly impossible. It had something to do with loading resources and/or compiling the site and/or restarting iis and/or the planets aligning.

Here's what we didn't understand: Resources in ASP.NET can be declared either explicitly or implicitly. Explicit means code, GetGlobalResourceObject("keyName") or GetLocalResourceObject("keyName"). Implicit means markup, meta:resourcekey="keyName".

Explicit calls are evaluated at runtime, every time, because it is regular code that gets executed in the regular way.

Implicit calls are evaluated once at compile time, and the compiler (essentially) hooks up a binding to between the appropriate property and the explicit / GetLocalResourceObject()* call. To walk through the above control sample:

  • At ASP.NET compile time, that line is parsed. The compiler looks at what’s specified in meta:resourcekey.
  • That key is passed into IImplicitResourceProvider.GetImplicitResourceKeys. This method queries the resource provider for all valid keys starting with HeaderImage, and returns all of those keys in an ICollection. Our example thus returns {"HeaderImage.ImageUrl", "HeaderImage.ToolTip"}.
  • The compiler inspects all of the keys, parses them, and performs databinding. Our example matches HeaderImage.ImageUrl from our resource provider and hooks up a binding between the property and IImplicitResourceProvider.GetObject("HeaderImage.ImageUrl") ... *which I believe calls GetLocalResourceObject() to complete the circle.

If the resource datastore, whatever it may be, is unavailable (or empty!) at ASP.NET compile time, the call to GetImplicitResourceKeys will return nothing and no databinding will occur.

That's what was happening to our resources. We would push new markup and immediately afterwards import new resources. But our import process was naïve; it deleted all of the resources from the database, scanned the filesystem for .resx files, loaded them into memory, and then inserted them into the database. And because it was a live site, many of these controls would be hit by the ASP.NET compiler while the database was empty. This meant the compiler thought it had nothing to do because GetImplicitResourceKeys returned nothing and so would let the resources fall back to their default text, in our case, [Header Image].

The resources that never exhibited a problem were of course retrieved explicitly.

I want to give credit to Rick Strahl, whose blogged frustrations about this topic helped point me in the right direction. Unlike him, I did not have to implement IImplicitResourceProvider (which agrees with MSDN), I just had to trace down a race condition where it was being called at an inopportune time.

In summary, pushing new markup and then immediately emptying the resource datastore on a live site will break implicit (meta:resourcekey) resources due to how the ASP.NET compiler resolves implicit bindings.

Thursday, December 21, 2006

Hello World

Check out how convoluted this Hello World is using an anonymous method in C# 2.0:

using System;
using System.Collections.Generic;
using System.Text;

namespace HelloWorld
{
    /// 
    /// Declare a delegate that will do something with a string.
    /// 
    public delegate void AcceptString(string s);

    public class Program
    {
        static void Main(string[] args)
        {
            //create the delegate using an anonymous method
            //in other words, this object is really a method
            AcceptString writeConsole = delegate(string s)
            {
                Console.WriteLine(s);
            };

            //call the object/method
            writeConsole("Hello World!");
        }
    }
}

Saturday, August 27, 2005

Connections

On a coworkers recommendation, I downloaded and used XsdObjectGen from Microsoft's web site. I opened up the documentation and saw that one of the principal authors of the tool was Colin Cole. I worked with Colin on a project a not too long ago...shook his hand, had a beer with him even. I feel so special.

Monday, June 14, 2004

No Private Methods

Jaybaz writes about a programming concept that intrigued me: no private methods. If you ever need to encapsulate something into a private method, you should make it an object instead with a public interface. He describes it as performing Extract Class until there are only public methods left. Private fields are okay, but methods must be public.

It's intriguing.... It would be a little bit of overhead, extra work, sure, but it leads to some cool ideas. It pushes the idea of design encapsulation. It should lead to better code reuse. And better reuse means less bugs over time: you fix it in one spot and everything that uses that object is fixed, too.

Of course if you define your object boundaries poorly, refactoring might become a nightmare. But if they're defined well, refactoring might become a breeze.

I haven't made up my mind on this yet. I want to try it and see if I like it. Will I stick with it? Will the overhead and extra work be outweighed by the encapsulation and reusability prospects in that code? Will it be an end to or a cause for refactoring?

Sunday, April 18, 2004

Ignorance Isn't Bliss

In my never ending quest to browse the entire Internet, I came across a message thread in a board for a really cool app. Some misinformed kid was bashing .NET. I decided to set the kid straight. To save you the trouble if clicking, I'll reproduce the conversation here.

ProfessorCRX: Can you tell me why .net has to be installed to make this work? I've got major problems with M$ .net.

In my eyes, Security > convience [sic]. Ms seems to see it the other way around. Is there ANY way possible to use this program without it? Or will there be? It looks pretty ill, but I just don't know about the.net BS. I think that needs to be rethought.

Travis: .NET is all about security. In fact, it makes security extremely convenient. Microsoft is making a huge security push internally and with all of its developers. Every attendee to the PDC last October got a copy of Writing Secure Code, 2nd edition. Managed code (.NET) makes things like buffer overflows almost impossible. The app throws an exception if you go out of bounds in an array instead of writing into memory that it's not supposed to be able to write to. How many security exploits have you seen in IIS 6, one of their first releases since the security push?

Basically, your prejudices are unfounded and result from you being ill-informed. .NET is a great platform both to develop on and from a security-minded user perspective. Looking towards the future, MS Longhorn (the next version of Windows) will be largely written in .NET. Get used to it, buddy, .NET is the future. IMO, that's a good thing. Install the .NET runtime, try out the app, and enjoy the wealth of apps that can easily be written by using .NET.

I can't speak for the author, but I wouldn't hold your breath for a native version of this app. He would have to scrap everything he's written and start over in unmanaged C++. Not gonna happen.

It's funny to me that I didn't know anything about .NET a year ago. I thought C# was just created because of the Microsoft/Sun Java lawsuit (not entirely untrue). But now I think .NET is an amazing platform. It's so easy to get quality apps out the door. And the Visual Studio IDE makes life so easy. It's possibly Microsoft's best product. Either Studio or Office...I can't decide. But I like .NET enough to stick up for it when the masses bash it.