Hack: Faking HttpContext under EPiServer CMS5
In my previous posts, I showed how one can "fake" a web request by creating a HttpContext and then assign it to the writeable property HttpContext.Current.
Now, there is a problem using this approach under the original release of EPiServer CMS5, where you get an error message like this:
"Cannot access EPiServerProfile. ProfileManager must be enabled, HttpContext must be valid and HttpContext.Current.Profile must be of a type derived from EPiServerProfile"
The error originates from the fact that HttpContext.Current.Profile isn't assigned and always returns null. A little investigation using Reflector reveals that the HttpContext instance gets it's _Profile field set by some internal Asp.Net code runned as an IHttpModule (ProfileManager), and as our "faked" web request isn't runned through the normal web request pipeline, this will never be assigned.
Furthermore, as the HttpContext.Current.Profile hasn’t got a “setter”, and the underlying field _Profile is marked “internal”, we really have no options but to resort to some reflection hacks to set the profile. Or more precisely, we specify the field _ProfileDelayLoad = true so the profile gets loaded the next time we access HttpContext.Current.Profile.
This can be done by adding the below line of code before calling the httphandler's ProcessRequest()-method:
1: typeof(HttpContext).InvokeMember("_ProfileDelayLoad", 2: BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.SetField,
3: null,
4: HttpContext.Current,
5: new object[] { true });
The solution isn't ideal, resorting to reflection to touch internal data fields rareley are, but in this case it might be justified.
If the code runned in the http handler accesses the profile through calls to ProfileBase.Create() rather than HttpContext.Current.Profile, this reflection stunt can be completely avoided.
Regards,
Johan Olofsson
23 June 2008