Can I access virtual directory name in global.asax.cs?
Asked Answered
U

5

7

The property HttpContext.Current.Request.ApplicationPath represents the virtual directory in IIS or WebDev.WebServer.

 HttpContext.Current.Request.ApplicationPath evaluates to "/virtualdirectory"

This can be used in conjunction with VirtualPathUtility to make a path root relative :

 VirtualPathUtility.ToAbsolute("~/images/cat.jpg",
                               HttpContext.Current.Request.ApplicationPath)

 // (this evaluates to "/virtualdirectory/images/cat.jpg")

In IIS6 and WebDev.WebServer the Request object is available in global.asax.cs, but IIS7 complains that it is 'not available in current context'. Therefore the second line of code above works but not in IIS7.

The problem is I need to access the virtual directroy name within global.asax.cs. I need it to construct some paths that are used in dynamically created CSS. Is there an alternative way to access this value?

Edit: This is the error you get in IIS 7 for calling HttpContext.Current.Request in global.asax.cs under Application_Start:

 HttpException (0x80004005): Request is not available in this context]
    System.Web.HttpContext.get_Request() +8789264
Unpleasant answered 28/4, 2009 at 20:42 Comment(2)
I don't understand the question, HttpContext.Current is available in global.asax , are you asking what event?Deepdyed
@deviant - HttpContext.Current is available, but HttpContext.Current.Request isn't. I've edited the post to include the errorUnpleasant
U
14

Finally found the simple answer!

 HttpRuntime.AppDomainAppVirtualPath

Available immediately during Application_Start

This is of the form /myapplication including the / prefix.

Unpleasant answered 3/1, 2010 at 5:2 Comment(3)
How to get the full directory name?Gershom
Got it! HttpRuntime.AppDomainAppPathGershom
You sir, Mister Simon Weaver, you got it goin' on.Inodorous
S
0

Can you use ResolveUrl("~/images/cat.jpg") to build your path?

Edit: ResolveUrl is a method of Control, not just the Page class, so you can do it this way instead (bit ugly maybe):

System.Web.UI.Control c = new Control();
String s = c.ResolveUrl(@"~/images/cat.jpg");
Saar answered 28/4, 2009 at 20:48 Comment(0)
C
0

Hmmm... I wasn't aware of the IIS7 change. I wonder if it wouldn't be simpler to defer this operation until you have got a page. For example, you could try putting something "once only" in Application_BeginRequest or Session_Start?

Or (completely untested) for a self-unsubscribing hook:

    public override void Init() {
        base.Init();
        EventHandler handler = null;
        handler = delegate {
            // do stuff, once only
            this.BeginRequest -= handler;
        };
        this.BeginRequest += handler;
    }

The trick is doing it once only (if multiple requests arrive at once); perhaps a static ctor? For example, I think this fires once only, and only when there is a page available in context:

    static class DelayedLoader {
        static DelayedLoader() {
            string s = VirtualPathUtility.ToAbsolute("~/images/cat.jpg",
                           HttpContext.Current.Request.ApplicationPath);
        }
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static void Init() { }
    }
    public override void Init() {
        base.Init();
        EventHandler handler = null;
        handler = delegate {
            DelayedLoader.Init();
            this.BeginRequest -= handler;
        };
        this.BeginRequest += handler;
    }
Chong answered 29/4, 2009 at 8:29 Comment(1)
Application_BeginRequest is probably safest. I'm not sure about the lifecyle of Session_Start, but when I tried to use it the page output was corrupted - I think it is conflicting with my compression - which is very odd but I'll stick with Begin_Request for nowUnpleasant
U
0

This is the best I came up with : Application_BeginRequest (via mark)

I use asax so rarely that I had temporarily forgotten you get different events with it. Until now I'd been creating the CSS sprites in Application_Start. Moving it to BeginRequest was the best I could come up with.

One boolean check for every request is negligible, but would be nice if there is a different way.

  protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
    }

    protected void Application_BeginRequest()
    {
        if (!_initialized)
        {
            lock (thisLock)
            {
                _initialized = true;
                GenerateCSSSprites();  
            }
        }
    }
Unpleasant answered 29/4, 2009 at 9:2 Comment(3)
Note that it seems to be theoretically possible to run the GenerateCSSSprites twice if two requests come in in close enough. Unlikely, but... you might want use double-checked locking (i.e. check _initialized inside the lock as well), or another approach (such as the static ctor trick).Chong
oops. thanks. i was trying to avoid locking on every request and managed to miss that. its important since running GenerateCSSSprites twice will actually cause an exception becasue it adds items to a global dictionary and complains if this is done twice. thanksUnpleasant
it actually DID run twice when i originally tried : GenerateCSSSprites(); _initialized=true. this is a little wierd since I'm the only person hitting the page and even though i'm accessing several resource on that host the browser cant ask for them until the first request is rendered - so IIS7 must be making more than one 'pseudo' request for my one real request. wierdUnpleasant
D
0

I had this problem too when switching to IIS7 but I was able to refactor out the need for Request. Which is what this guy also suggests and provides a workaround if you can't.

http://mvolo.com/blogs/serverside/archive/2007/11/10/Integrated-mode-Request-is-not-available-in-this-context-in-Application_5F00_Start.aspx

Deepdyed answered 29/4, 2009 at 9:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.