3

I find it weird to use context.Server.MapPath every time just to determine physical location of some known directory/file under app_data folder. I have an understanding that once an application is running, it must not be possible to have its physical location be changed without first shutting it down. If this is true, then I can cache physical path of app_data on application_start and use the cache value for its execution lifetime!

I need experts opinion on this matter. Is my assumption right? there's no possibility of changing the physical path of an application without restarting it, right?

If this is true, It will save me tons of time from having to include context as a parameter in every odd method!

Clarity of the method interface is most important to me, and <context> just doesn't fit into that.

BTW, I'm using shared hosting so I have no control on application physical placement. Does this matter?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Varun K
  • 3,593
  • 2
  • 25
  • 26
  • 1
    Why do you want to cache it? Do you believe that it's an expensive operation? – Maxim May 31 '11 at 18:06
  • @maxim, not just because it is more expensive than the cache option, but most importantly because I have to pass context in every method/object that needs to do IO. And of course I just don't want to go with HttpContext.Current approach chiefly it's too expensive. – Varun K May 31 '11 at 18:30
  • Why do you pass it to every method/object? The *HttpContext* is a static class. Are you sure that getting the context is too expensive? Did you check it? – Maxim May 31 '11 at 18:36
  • 1
    http://forums.asp.net/p/1328274/3351710.aspx – Varun K May 31 '11 at 18:43

3 Answers3

1

The path is relative to the current request, so MapPath("foo") might have a different result on requests at different urls. However, if your path is relative to the app-root ("~/foo") or relative to the site-root ("/foo") you can pretty much cache to your heart's content.

There is perhaps an edge-case scenario of people adding virtual directories inside IIS during execution, but that is vanishingly unlikely, and is pretty-much going to cause pain anyway.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
0

I don't think you have to pass the context as a parameter. There is always the possibilty to use

 HttpContext.Current.Server.MapPath("~/...");

That's easier than to store the variable in the cache.

Edit: If you really think a call like this would be costly, create a Singleton class Application with a property where you can store the root path, e.g. like this:

public class Application
{
  private static string _rootPath = HttpContext.Current.Server.MapPath("~");
  public static string RootPath
  {
      get { return _rootPath; }
  }
}

and you can access your Root from everywhere. You can put this code in global.asax as well.

slfan
  • 8,950
  • 115
  • 65
  • 78
  • arguably less testable, though – Marc Gravell May 31 '11 at 18:15
  • Nopes! HttpCOntext.Current is more costly than anything else, and I've just got rid of most of its usage in my app – Varun K May 31 '11 at 18:15
  • Did you measure how costly it is? I think in comparison to streaming HTML to a network or accessing a database it is close to nothing. – slfan May 31 '11 at 19:28
  • I agree with you slfan, these milliseconds don't count – Maziar Taheri May 31 '11 at 19:57
  • @slfan, this doesn't look much expensive on first shot and that's exactly where you start ignoring things. You start using it wherever you need context, and once you are done with most of your application and it begun to get many hits constantly, you suddenly realize that you have some performance bottleneck and that is because you have HttpContext.Current being called tens of times during a request. That said, I'm not entirely against using it. In fact, I have left its usage in some of the places (like global logger) where I've found that there's no other viable design solution. – Varun K Jun 01 '11 at 05:48
  • @Varun K, I still believe your file I/O is a thousand times slower. I had a look at the code with Reflector: it can't be that bad. When I find the time I will measure it. But I think your problem accessing a constant physical path should be solved with my suggestion. This should be absolutely no problem on a shared server. – slfan Jun 01 '11 at 06:04
  • @slfan, I was actually not looking for a code that demonstrates how to cache application route, instead, I wanted to know if I do it, does it have any unknown consequence? Specifically, can physical path of an application be changed while it's running? If it can then the cached path will get invalid and all requests involving IO will fail. Anyway, thanks for your solution, but I'd plans to go with global.asax approach and initialize such static things on app start event. – Varun K Jun 01 '11 at 06:17
  • the disadvantage of global.asax is, you can't reuse your code. You have to add it to every project. That's why I generally prefer business classes in libraries which have some context, compared to all kind of global stuff in global.asax. In the old days I learned you should try to avoid globals, that's why I try to avoid global.asax as well (Î'm not saying that I don't use it from time to time) – slfan Jun 01 '11 at 06:35
  • @slfan, I agree, me too not making static variables in global.asax. The design is like this: business/common libraries (those who need such static stuff) individually have some class with a public static method called Init(). this method is responsible to initialize the static stuff of that library. I can make Init accept HttpContext as an argument if it is required. What I'm doing in global.asax is only calling these Init methods of different libraries – Varun K Jun 01 '11 at 06:47
  • @Varun K, a call to Init in global.asax is an option until the day you forget to call it. That's why I prefere lazy initialization for this kind of requirements. It's initialized when you need it the first time. If nobody uses it, it doesn't use memory – slfan Jun 01 '11 at 07:03
0

If I were you, I wouldn't cache anything, because I don't believe that caching will make anything faster. or if it was faster, that was about some nano seconds.

about your problem of passing the context, this is because of your design.

I would refactor my code and create a single point which would do IO operation, i.e. an IOHelper class, and I would cache the context there.

Maziar Taheri
  • 2,288
  • 22
  • 27
  • And how do you think you can get reference to that IO helper class? Making it a static doesn't work since you need to resolve httpContext in such case, which is, more expensive, than anything else. ANd if you create an object of that class and passing it around during a request execution, then it is more or less the same as passing context. – Varun K May 31 '11 at 18:48
  • yes make helper classes static, and you have to call HttpContext.Current just once! (in the static constructor) and then save it in a field. – Maziar Taheri May 31 '11 at 18:52
  • @Maziar, this sounds more weird to me. As I understand, Context is not something to cache, it exists and must only be used during a request being service, and there might be many at a time. – Varun K May 31 '11 at 18:59
  • I think you are right and I made a funny mistake. anyway where have you read that getting HttpContext.Current is an "expensive" operation? – Maziar Taheri May 31 '11 at 19:04
  • @Maziar, Well there are many, just google for it. One of them is: http://forums.asp.net/p/1328274/3351710.asp. I've recently refactorx a large code base just to get rid of .current. And now I touch it only when there is no viable design solution. – Varun K May 31 '11 at 19:12
  • your link was broken, but I did google it, and there was an argument about that, not an issue which everybody agreed upon. If you are sure about that, just cache the physical address somewhere, i.e. that blessed IOHelper class ;) – Maziar Taheri May 31 '11 at 19:22
  • Actually link got messed up while pasting it, posted the corrected version above. – Varun K May 31 '11 at 19:25
  • 300 microseconds in October 2008 without any reference to the hardware where it has been executed. Because you only want to store the application root path, which is normally constant during the lifetime of an application, you can even store it in a static variable, it will be the same after every call. – slfan May 31 '11 at 19:39
  • I just want to be assured about this constant factor. Because if it gets changed, request will fail – Varun K Jun 01 '11 at 06:00