Image of a spark (static).Dozens of variations on the title of this post are some of the most common searches that bring people here to Encosia. Unfortunately, the search engines all point to a post that doesn’t answer the question. It’s also a frequent question raised on the ASP.NET message boards, typically without a satisfactory answer provided.

However, it is an important question, the answer to which is important to understand. So, in an attempt to fill in this gap for the searchers and perhaps preemptively help others, I want to proceed to answer it as thoroughly as possible without overly complicating the whole business.

In order to do this, we’ll have to take a brief tour of WebForms, including:

  • Understanding what the Page class is, and why we have it.
  • One specific thing that the Page class does for us.
  • How this is accomplished, behind the scenes.
  • What the static keyword entails, when used with a method.
  • Finally, why page methods must be static.

Note: Please bear in mind that I have taken great liberties in simplifying these concepts down to only what is necessary to answer the central question. What I will show you is conceptually accurate, but some of the implementation details are much more complex than what you will see here.

Understanding what the Page class is, and why we have it

Contorting the stateless HTTP protocol to accommodate ASP.NET’s WebForm paradigm was a considerable task for the ASP.NET team to accomplish. On top of that, going from the inline execution model of ASP classic to the event-driven model of ASP.NET also required major changes.

As such, the ubiquitous WebForms Page class was created to solve these various problems. Take this snippet, for example:

public partial class _Default : System.Web.UI.Page 
{
  protected void Page_Load(object sender, EventArgs e) 
  { 
    // Hello World.
  }
}

I’m sure you’re familiar with the Page_Load event. The very first ASP.NET code example you were exposed to probably involved the Page_Load event. How about this portion of it though?

public partial class _Default : System.Web.UI.Page

To get you started quickly, those examples may not have explained that part very well (if at all). Later, after you get up and running, it can be easy to simply gloss over this line as cruft that comes with writing an ASP.NET page.

What this declaration means is that your code extends the Page class. Because of this, your code will include the functionality of the entire ASP.NET Page class, instead of standing on its own and requiring you to implement the mundane details.

If you’re more familiar with something like ASP classic or PHP, you can think of this Page inheritance as being functionally similar to a powerful include file that you use site-wide.

One of the Page’s most powerful features: Persistence

The Page brings a lot to the table. However, to answer the question of why page methods must be static, we need to focus on persistence.

Consider this example:

<asp:Label runat="server" id="Label1" />
<asp:Button runat="server" id="Button1" OnClick="Button1_Click" />
protected void Button1_Click(object sender, EventArgs e)
{
  Label1.Text += DateTime.Now.ToString();
}

Each time the button is clicked, the label will have the current time and date appended to its current contents. Even this elementary example illustrates how the WebForms Page automatically provides persistence for us.

We take for granted that the Page will provide us this Label1 object after an HTTP POST from the browser. We also assume that it will automatically have a Text property with that Label’s current value.

However, this data would not normally be included in the POST data sent to the server. Only form elements are sent from the browser. The Label renders as a span element, which means that its state is not POSTed by the browser.

So, how does the Page provide us with this data anyway? Persistence.

Understanding how the Page does this

To implement this encompassing layer of persistence, the ViewState was created.

Each time a page is rendered to the browser, the Page serializes the state of its controls and then includes that information in the returned HTML, via a hidden form field named __ViewState. When a postback occurs, this hidden field can then be de-serialized to create an instance of the Page in the same state that it was at the end of the last request.

Oversimplifying, you can envision this constructor being used to re-instantiate the Page, at the beginning of every postback:

Page _Default = new Page(Request["__ViewState"]);

In our example above, the Page created through that process would look something like this after one postback:

This re-instantiation of the Page from the ViewState is what keeps the entire WebForms machine rolling, postback after postback.

What does it mean that a method is static?

A static method is simply one that is disassociated from any instance of its containing class. The more common alternative is an instance method, which is a method whose result is dependent on the state of a particular instance of the class it belongs to.

For example, both of these statements would return precisely the same string, but accomplish it through different types of methods:

// ToString() is an instance method of the DateTime class.
//  Its result depends on the value of each DateTime instance.
return DateTime.Now.ToString();
 
// String.Format is a static method of the String class.
//  Its result is not related to any instance of the String.
return String.Format("{0}", DateTime.Now);

The key difference to understand is that a static method can be called without setting up a proper instance of the class it belongs to.

In a sense, it is a stateless method.

So, why do page method calls have to be static?

If you’re implementing page methods, you’re probably well aware of their excellent performance. They are especially performant compared to the UpdatePanel’s partial postbacks.

They are efficient largely because they do not require the ViewState to be POSTed and they do not create an instance of the Page, while partial postbacks do both of these things. As we now know, a page method couldn’t create an instance of the page even if desired, since the ViewState isn’t provided in the request.

This is exactly why they must be marked as static. They cannot interact with the instance properties and methods of your Page class, because a page method call creates no instance of the Page or any of its controls.

Page methods are roughly equivalent to shorthand for standalone web services. In fact, the ScriptManager even calls them exactly as it would a regular web service.

Conclusion

While forcing the page method to be static is primarily due to technical reasons, I would suggest that it’s actually a good thing. If page methods transmitted the ViewState along with their request, in order to instantiate the Page, they would immediately lose a majority of their benefit.

Forcing the method to be static is necessary to confer most of the benefits of using page methods. Sure, it would be nice to be able to access control properties directly from within page methods, but not at the expense of transmitting volumes of extraneous data about every other control on the page.

Instead of fighting against this limitation, I say embrace efficiency.