Scott Hanselman

Advanced ASP.NET Caching and AddValidationCallBack

March 09, 2005 Comment on this post [2] Posted in ASP.NET
Sponsored By

ASP.NET (today 1.1, and more so with 2.0) has a fantastic capability for caching.

At it's most basic, there's

<%OutputCache Duration="30" VaryByParam="id"%>

When this is added to an ASPX page, it would automatically cache versions of a page for every received value of id= that appears in the QueryString.

That means that when your application starts up, there's nothing in the ASP.NET output cache. If someone hits foo.aspx?id=4, your code-behind executes and the page renders the first time. Subsequent hits to foo.aspx?id=4 will retrieve a cached version. Since Duration="30", that means that your code for foo.aspx will not run until the cached item expires in 30 seconds.

As new visitors hit foo.aspx with different values for id=, there will be a new version cached. You want to be aware of how many possible values for id= there are, as your web servers memory will be affected. If foo.aspx is hit with a few dozen values for id=, you're likely OK. But if there are thousands or millions of potential values and you have a long value for Duration, you may end up holding a lot more versions of cached pages in memory than is reasonable or performant.

In addition to VaryByParam, there's a few others, with the most powerful being VaryByCustom where you can set a custom string:

<%OutputCache Duration="30" VaryByCustom="mycustomthing"%>

Then you override HttpApplication.GetVaryByCustomString in your Global.asax. GetVaryByCustomString returns a string. That string is built by you and used as a key to store and retrieve a cached version of your page. The key can be anything and build from anything. You can create a composite key from other pieces of information available to you like cookies, user-languages, browser capabilities, whatever.

This gives the developer a lot of flexibility as to the name that the developer wants to base caching on. However, what if I want to cache pages for every value of id= except id=5?

That's where the little-used, little-known, Response.Cache.AddValidationCallback comes in.

On your page you hook up a callback that will be called when it's time to decide whether to return a cached version of your page.

<%@ OutputCache VaryByParam="none" Duration=600 %>

<Script Language="C#" runat="server">

   public void Page_Load()

   {

      Response.Cache.AddValidationCallback(new HttpCacheValidateHandler(Validate), "somecustomdata");

   }

 

   public void Validate(HttpContext context, Object data, ref HttpValidationStatus status)

   {

      //I can check 'data' if I want to here as well...

 

      if (context.Request.QueryString["id"] == "5")

      {

        status = HttpValidationStatus.IgnoreThisRequest;

      }

      else

      {

        status = HttpValidationStatus.Valid;

      }

   }

</Script>

There are three values for HttpValidationStatus. In this example, if id=5, HttpValidationStatus.IgnoreThisRequest indicates that this should be treated as a Cache Miss and the page will run and render as usual. If not, HttpValidationStatus.Valid indicates that everything is cool. The third value, not shown here, is HttpValidationStatus.Invalid that indicates not only that this request should be treated as a Cache Miss, but also that any cached value should be invalidated and evicted from the Output Cache.

Note: You don't want to do ANYTHING "heavy" in the callback method. Remember that your callback is being called to ask your advice. ASP.NET is asking, "should I return the cached item?" If it takes you longer to answer that question then it would to just return the cached item, then you need to rethink what are your goals. Remember also that you can store some small objects (context) when you setup the callback that may be used later to make your decision.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Storing things on Threads

March 09, 2005 Comment on this post [1] Posted in Web Services | ASP.NET
Sponsored By

There's so many places to put stuff. I think one of the most difficult things for new .NET developers is deciding where to store objects and bits of data.

There's certainly the obvious starting points:

  • Local variables: Variables exist for a short period of time, have "scope" and may live only for the life of a method call. No threading issues.
  • Instance class fields: Variables exist for the life of the class. Threading issues can come up if multiple threads go poking around.
  • Static local variables: Variables are stored in a single location and are shared between instances. Threading issues galore as you are responsible for serializing access to folks messing with these variables.
  • Variables marked with [ThreadStatic]: These should NEVER be used from within ASP.NET. I've blogged about its evil before. Details From MSDN - A static (Shared in Visual Basic) field marked with ThreadStaticAttribute is not shared between threads. Each executing thread has a separate instance of the field, and independently sets and gets values for that field. If the field is accessed on a different thread, it will contain a different value.
  • CallContext: These are a set of properties that are carried along within the execution code path. You can add variables to the CallContext as it flows through execution. You can add objects into the CallContext as if it were a Hashtable, using .SetData() and .GetData(). As it moves over/between application domains, it is cloned. Objects that implement ILogicalThreadAffinative will go along for the ride.
  • ThreadLocalStorage: This is something I don't see used a lot, as it's pretty specialized. Dino Chiesa had this cool example. He wanted to provide a factory that could be used by multiple threads to retrieve an object instance, but he wanted each thread to get their own reusable copy. He uses a LocalDataStoreSlot to store/cache objects on a thread-by-thread basis. This way he can always call GetProxy from his code, and ensure that only one copy will exist per thread.
    • public static System.LocalDataStoreSlot Slot= System.Threading.Thread.AllocateNamedDataSlot("webutil.proxy");

      public static System.Net.WebProxy GetProxy()

      {

          object PutativeProxy = System.Threading.Thread.GetData(Slot);

          if (PutativeProxy==null)

          {

              string ProxyString =     System.Configuration.ConfigurationSettings.AppSettings[GetConfigKey("proxy")];

              if ((ProxyString == null) || (ProxyString == "")) return null;

              PutativeProxy = new System.Net.WebProxy(ProxyString, true);

              System.Threading.Thread.SetData(Slot, PutativeProxy); 

          }

          return (System.Net.WebProxy) PutativeProxy;

      }

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

DasBlog 1.7 and Free Text Box

March 09, 2005 Comment on this post [1] Posted in ASP.NET | DasBlog
Sponsored By

Clemens mentioned to me that after upgrading in-place to DasBlog they are seeing a BLANK page when visiting the Administration "Edit Entry" page.

This appears to be some left over schmutz somewhere in a Temporary ASP.NET Files folder as it relates to the upgraded version of FreeTextBox that DasBlog 1.7 included. Somewhere in the temp world the FTB versions aren't lining up.

I had this problem myself, and I fixed it by doing a fresh deploy of my bin folder. I backed it up, delete all of bin, and redeployed all the application assemblies and resource assemblies. Also confirm that you've got the latest versions of all ASPX and ASCX files.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Rotating the Screen on the Toshiba m205 TabletPC

March 08, 2005 Comment on this post [2] Posted in Musings
Sponsored By

A fellow emailed me yesterday saying:

Anyway I have an M205 that I have practically worn out the keyboard on (an indication of the relative non-use of the stylus) and for this reason: Toshiba, for some reason or lack of reason, I have no way to fathom either, forgot to put a 180-degree landscape view in. Now first off, I would be happy to be informed – no you push this and voila! (But that isn’t going to happen – is it?)

so I said:

No, you push this and voila!

The hardware orientation button has to be configured to allow different views. Go to “Rotation Utility” under Start Menu|All Programs|TOSHIBA|TabletPC|Rotation Utility. There you can set the orientation.

Additionally, the m200 and m205 also support gyroscopic orientation. If you turn the Tablet to the orientation you want, then press and hold the hardware rotate button, you’re set. You don’t need or want a screen rotation util, the TabletPC (OS) and Toshiba support all 4 orientations. I promise.

And he was happy.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Stop Complaining

March 08, 2005 Comment on this post [11] Posted in ASP.NET | Learning .NET | Ruby
Sponsored By

It's great that Scott and Dan took the time to respond to the bizarre rantings of Richard Grimes' final column.

Personally, I'm not going to write a big essay in retort. I think Richard's essay stands on its own, and proves only that he's out of touch. It sure seems odd that a fellow who's written books on .NET and a column for three years would leave on that kind of note. It was kind of sad.

My thoughts on his thoughts:

  • The Size of the Framework - Sure, it's big. So was Win32, and so is sun.java.*. Programming isn't all Ruby on Rails, you know. :) The redist is 25 Meg? For what you get that's pretty cheap. That'll fit on any pen-drive and can be downloaded in a few minutes via broadband.
  • The Framework is a Thin Wrapper on Win32 - Um, duh?
  • VB and VB.NET are too different - Again, it's common knowledge that VB.NET isn't VB and vice versa. VB.NET exists to make former Visual Basic programmers comfortable, and to provide another, arguably simpler interface to IL.

Yes, he's cynical.  All I know is that .NET has paid my mortage (and possibly yours) for a few years now, and I'm not too interested in complaining about a good thing.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.