Is it right to instantiate active classes outside of Page_Load? - asp.net

a quick question for an ASP.NET expert. It is an arguable moment for us in the company at the moment...
We have built a nice (no bugs in there) CMS framework that we use for our sites...
It goes something like this:
MyCms.Content.Channels channels = new MyCms.Content.Channels();
where at the moment of instantiating the Channels class, it loads a bunch of XML files and converts them to a List<MyCms.Content.Channels.Channel> that is held within the Channels class, and cached using System.Web.HttpRuntime.Cache (until there are any changes to the folder holding the XML files)
The Channels class is basically a hierarchical structure for web pages...
We normally use it like this in our ASP.NET pages (code behind):
public partial class Default : System.Web.UI.Page
{
public MyCms.Content.Channels channels;
public MyCms.Content.Images images;
public MyCms.Content.Channels.Channel CurrentChannel;
public List<MyCms.Content.Channels.Channel> latestItems;
public MyCms.Content.GameVotes votes;
public MyCms.Content.GameVotes.Vote vote;
protected void Page_Load(object sender, EventArgs e)
{
channels = new MyCms.Content.Channels();
images = new MyCms.Content.Images();
..
}
as you can see, the public variable 'channels' is instantiated at Page_Load()... where at the moment it has loaded a bunch of XML files either from a file system, or from cache...
Our colleague though, is sometimes instantiating this class outside of Page_Load() - right next to the public declaration of the 'channels' variable like this:
public partial class Default : System.Web.UI.Page
{
public MyCms.Content.Channels channels = new MyCms.Content.Channels();
protected void Page_Load(object sender, EventArgs e)
{
... he does the same in various User Controls...
Now thing is.. I need your opinion on whether it's ok to instantiate a very active class like this - outside of Page_Load() event... ? The site that was built by our colleague was hanging the entire IIS from time to time, and I just suspect that this could be one reason... - what do you think, please ? :)
The same CMS Framework is being used on other sites, on other servers with no issues at all... So the only difference I could find between the good working sites and the one that is hanging - is this .. instantiation of 'channels' class outside the scope of Page_Load()...

It shouldn't make a difference. That's not to say it doesn't.
All that's happening is you're changing the point at which you create the object from load event, which happens about half way through the lifecycle to the constructor, right at the very start. At both points the cache should be available as it's part of the context, although you really ought to check that.
I would say though, instantiating such an important class should happen at a specific point, like page initialise or load, rather than at constructor.
Simon

The only difference I'm aware of is that if you initialize the objects outside of the Page_Load they will be created as soon as your page's class is created (i.e. before all the Page_XXX events), and if you initialize them inside the Page_Load they will be created only when the event is called.
That means if your application crashes, redirects or for whatever reason does not enter Page_Load, you have created the object uselessly.

Related

Multiple Page_Load methods, which is called?

In an existing ASP.NET application, I have a base class containing a Page_Load method:
public class PageBaseClass : System.Web.UI.Page {
protected virtual void Page_Load(object sender, EventArgs e) {
// do stuff...
}
}
I have an actual page which inherits from this base class. However, it doesn't override the existing Page_Load method, but declares a new one like this:
public class ActualPage : PageBaseClass {
protected void Page_Load(object sender, EventArgs e) {
// do other stuff...
}
}
The compiler gives me a warning that the Page_Load method in the actual page is hiding the existing Page_Load method. So effectively, there are two seperate Page_Load methods, since the old one wasn't overridden, but hidden.
Now my question is, what does the ASP.NET architecture do in it's lifecycle in such a situation? Which one is being called? Or are they both being called?
Note: I know this is bad design, I'm not sure what the original author had in mind, I'm just trying to understand what's happening and how this will affect the logic of the system.
After some digging around, I've found out what's happening.
Short answer: only the top-most method is called!
At first I put down some breakpoints like MelanciaUK suggested in a comment. This showed me that only the top-most method was being called.
Digging deeper, I looked at what volpav suggested. It was true that AutoEventWireup was set to true, which was automatically hooking up the method to the event handler (since this indeed wasn't done manually). However, unlike he claimed, only the top Page_Load method was being called.
Reflecting over the type gave me a bit of a clue what was going on:
var pageloads = this.GetType().GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).Where(m => m.Name == "Page_Load");
var pageload = this.GetType().GetMethod("Page_Load", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
The pageloads value ended up containing two results: the two Page_Load methods, one with declaring type ActualPage and one with declaring type PageBaseClass.
I though that would cause problems for the second call, since having two results, I expected it to throw an AmbiguousMatchException. However, it did not. It contained the MethodInfo for the method in the ActualPage.
Digging deeper, I stumbled upon an article by K. Scott Allen: Inside AutoEventWireup
http://odetocode.com/blogs/scott/archive/2006/02/16/inside-autoeventwireup.aspx
According to his article, wiring up events is happening as follows:
Delegate.CreateDelegate(typeof(EventHandler), this, "Page_Load", true, false);
Executing this myself, I found that this call creates a delegate pointing at the Page_Load method for the ActualPage, the same way the GetMethod call returned that method.
So it seems that in case an event-method is being wired up automatically, it will not wire up any methods that are being hidden.
The code in both methods will be called since these are essentially an event handlers (one which is attached by the base class, another one - by your "ActualPage" class). This is due to "AutoEventWireup" property set to "true" (it's set by default in your markup).
Related question on "AutoEventWireup": What does AutoEventWireUp page property mean?
UPDATE
Turned out I was wrong stating that both methods will be called and in fact, only the one declared on the "ActualPage" gets called. See Rene's answer below.

How to use Ninject.Web.PageBase alongside another, custom .NET PageBase

I am trying to get Ninject working with a WebForms application that already has a custom PageBase object. But, I don't know for sure if I can use Ninject's PageBase object alongside another, custom PageBase. I've been searching for a while now to see if I could find an answer to this problem, or to learn how to do it, but all I've found is this:
I've hacked together an alternative using a shared base class that
derives from Page. It looks roughly like this
public abstract class PageBase : Page
{
public IKernel Kernel { get; private set; }
public PageBase() { Kernel = ...; }
public void Page_Init() { Kernel.Inject(this); }
}
This will allow you to property and method injection on any pages that
inherit from PageBase. Note that the constructor is incomplete --
you'll have to access the kernel in some static fashion. You should
be able to read it from the HttpApplication somehow.
(source: http://groups.google.com/group/ninject/browse_thread/thread/317fc48387399aa6, linked from Ninject with ASP.Net webforms and MVC):
This looks like it might work for me because it appears that I could apply this code to the existing, custom PageBase. But, I am hung up on the part in which the author says, "... the constructor is incomplete -- you'll have to access the kernel in some static fashion."
Does anyone have any idea what that sentence means, and how one might go about accessing the Ninject kernel in a static fashion?
You do not need to derive from a Ninject page base. You can alternatively use the NinjectHttpModule.
https://github.com/ninject/ninject.web/blob/master/src/Ninject.Web/NinjectHttpModule.cs

Entity Framework ObjectContext re-usage

I'm learning EF now and have a question regarding the ObjectContext:
Should I create instance of ObjectContext for every query (function) when I access the database?
Or it's better to create it once (singleton) and reuse it?
Before EF I was using enterprise library data access block and created instance of dataacess for DataAccess function...
I think the most common way is to use it per request. Create it at the beginning, do what you need (most of the time these are operation that require common ObjectContext), dispose at the end. Most of DI frameworks support this scenario, but you can also use HttpModule to create context and place it in HttpContext.Current.Items. That is simple example:
public class MyEntitiesHttpModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.BeginRequest += ApplicationBeginRequest;
application.EndRequest += ApplicationEndRequest;
}
private void ApplicationEndRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Items[#"MyEntities"] != null)
((MyEntities)HttpContext.Current.Items[#"MyEntities"]).Dispose();
}
private static void ApplicationBeginRequest(Object source, EventArgs e)
{
var context = new MyEntities();
HttpContext.Current.Items[#"MyEntities"] = context;
}
}
Definitely for every query. It's a lightweight object so there's not much cost incurred creating one each time you need it.
Besides, the longer you keep an ObjectContext alive, the more cached objects it will contain as you run queries against it. This may cause memory problems. Therefore, having the ObjectContext as a singleton is a particularly bad idea. As your application is being used you load more and more entities in the singleton ObjectContext until finally you have the entire database in memory (unless you detach entities when you no longer need them).
And then there's a maintainability issue. One day you try to track down a bug but can't figure out where the data was loaded that caused it.
Don't use a singleton.. everyone using your app will share that and all sorts of crazy things will happen when that object context is tracking entities.
I would add it as a private member
Like Luke says this question has been asked numerous times on SO.
For a web application, per request cycle seems to work best. Singleton is definitely a bad idea.
Per request works well because one web page has a User, maybe some Projects belonging to that user, maybe some Messages for that user. You want the same ObjectContext so you can go User.Messages to get them, maybe mark some messages as read, maybe add a Project and then either commit or abandon the whole object graph at the completion of the page cycle.
Late post here by 7 months. I am currently tackling this question in my app and I'm leaning towards the #LukLed solution by creating a singleton ObjectContext for the duration of my HttpRequest. For my architecture, I have several controls that go into building a page and these controls all have their own data concerns that pull read-only data from the EF layer. It seems wasteful for them to each create and use their own ObjectContext's. Besides, there are a few situations where one control may pull data into the Context that could be reused by other controls. For instance, in my masterpage, my header at the top of the page has user information that can be reused by the other controls on the page.
My only worry is that I may pull entities into the context that will affect the queries of other controls. I haven't seen that yet but don't know if I'm asking for trouble. I guess we'll see!
public class DBModel {
private const string _PREFIX = "ObjectContext";
// DBModel.GetInstance<EntityObject>();
public static ObjectContext GetInstance<T>() {
var key = CreateKey<T>();
HttpContext.Current.Items[key] = HttpContext.Current.Items[key] ?? Activator.CreateInstance<T>();
return HttpContext.Current.Items[key] as ObjectContext;
}
private static string CreateKey<T>() {
return string.Format("{0}_{1}", _PREFIX, typeof(T).Name);
}
}

Silverlight VirtualizingPanel recycling containers display wrong content

I recently wrote an implementation of a VirtualizingWrapPanel that recycles containers as they scroll into and out of view.
On occasion I've noticed that the content rendered by the control is actually the previously contained data, not the current data. Performing any action on the control that forces a new render call updates the control such that it displays the correct data.
Could this a bug in the ItemContainerGenerator recycling or is it more likely in my recycling code? Is there a way I can force all my bindings to update (after updating the control with new content) without explicitly writing each binding expression in code behind?
I've seen problems very like this in the past when using virtualization when we were using custom controls that really weren't expecting their DataContexts to be changed once they were displayed.
If your panel is correctly (as it sounds) handing new DataContexts to the reused objects then it does sound like the reused objects aren't processing that DataContext change correctly. (This 'render' call you talk about would then pick up the new DataContext and display that.)
If you're using plain data binding in your control then I'm slightly stumped. (Is your panel re-Measure/Arranging the controls after they've got their new DataContext?)
The fix for us was to have our controls listen out for when their DataContext changed. (This is also useful for debugging virtualizing panels to test that the DataContext is coming in correctly.)
Sadly the OnDataContextChanged method isn't public in Silverlight but you can still find out about DC changes by binding to them.
public MyClass()
{
InitializeComponent();
SetBinding(MyDataContextProperty, new Binding());
}
private static readonly DependencyProperty MyDataContextProperty =
DependencyProperty.Register("MyDataContext",
typeof(object),
typeof(MyClass),
new PropertyMetadata(DataContextChanged));
private static void DataContextChanged(
object sender,
DependencyPropertyChangedEventArgs e)
{
MyClass source = (MyClass)sender;
source.OnDataContextChanged();
}
private void OnDataContextChanged()
{
// My DataContext has changed; do whatever is needed.
// re 'render' in your case?
}

What is the best way to reuse pages from one website in another?

I'm developing a new ASP .NET website which is effectively a subset of the pages in another site we've just released. Two or three of the pages will need minor tweaks but nothing significant.
The obvious answer is to simply copy all of the code and markup files into the new project, make the aforementioned tweaks, and consider the job done. However I'm not keen on this at all due to the amount of duplicated code it will create.
My next idea was to move the code for the pages (i.e. the code-behind file) into a separate assembly which can then be referenced from both sites. This is a little awkward however as if you don't take the designer file with it, you get a lot of build errors relating to missing controls. I don't think moving the designer file is a good idea though as this will need to be regenerated each time the markup is altered.
Does anyone have any suggestions for a clean solution to this problem?
You might want to take a look at the MVP pattern. Since you are probably using WebForms it would be hard to migrate to ASP.Net MVC, but you could implement MVP pretty easily into existing apps.
On a basic level you would move all the business logic into a Presenter class that has a View that represents some sort of interface:
public class SomePresenter
{
public ISomeView View{get; set;}
public void InitializeView()
{
//Setup all the stuff on the view the first time
View.Name = //Load from database
View.Orders = //Load from database
}
public void LoadView()
{
//Handle all the stuff that happens each time the view loads
}
public Int32 AddOrder(Order newOrder)
{
//Code to update orders and then update the view
}
}
You would define your interface to hold the atomic types you want to display:
public interface ISomeView
{
String Name {get; set;}
IList<Order> Orders{get; set;}
}
Once those are defined you can now simply implement the interface in your form:
public partial class SomeConcreteView : System.Web.UI.Page, ISomeView
{
public SomePresenter Presenter{get; set;}
public SomeConcreteView()
{
Presenter = new SomePresenter();
//Use the current page as the view instance
Presenter.View = this;
}
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
Presenter.InitializeView();
}
Presenter.LoadView();
}
//Implement your members to bind to actual UI elements
public String Name
{
get{ return lblName.Text; }
set{ lblName.Text = value; }
}
public IList<Order> Orders
{
get{ return (IList<Order>)ordersGrid.DataSource; }
set
{
ordersGrid.DataSource = value;
ordersGrid.DataBind();
}
}
//Respond to UI events and forward them to the presenter
protected virtual void addOrderButton_OnClick(object sender, EventArgs e)
{
Order newOrder = //Get order from UI
Presenter.AddOrder(newOrder);
}
}
As you can see, your code behind is now extremely simple so code duplication is not a big deal. Since the core business logic is all wrapped up in a DLL somewhere, you don't have to worry about functionality getting out of sync. Presenters can be used in multiple views, so you have high reuse, and you are free to change the UI without affecting the business logic as long as you adhere to the contract.
This same pattern can apply to user controls as well, so you can get as modular as you need to. This pattern also opens up the possibility for you to unit test your logic without having to run a browser :)
The patterns and practices group has a nice implementation of this: WCSF
However, you don't have to use their framework to implement this pattern. I know this may look a little daunting at first, but it will solve many of the problems (In my opinion) you are running into.
Create user controls (widgets) or templates to tweak what you want to achieve.
It might also be possible to achieve the same with CSS styles or JavaScript.
Why not create user controls (or custom controls) from the pages which you wish to share? You can then re-use these across both sites.
What we use in our project (JSP, not ASP, but when it comes to building and files it surely isn't an issue?) is to have a base folder of common files, and then another ("instance") folder of additional files and overwrites, and our build script (in ANT, Maven should be fine too) will first copy the base folders, and then based upon a parameter supplied select which instance's files to copy across as well.
Thus we can change a file in the base, and have it apply across all instances.
An issue is that changing a base file will not update any instance file that overwrites it but at least you can make a process for these updates. Presumably you could also use the SVN (etc) revision to flag a build error is an instance file is older than a base file, but we haven't implemented anything that clever yet.
In addition your back-end code (Struts actions in our case) will end up handling all cases rather than any particular instance's cases only. But at least all the code is in one place, and the logic should be clear ("if (instance == FooInstance) { doFooInstanceStuff(...); }").

Resources