Do all instances of the same ASPX page share the same static field? - asp.net

Let's consider this page's code-behind:
public partial class Products : Page
{
private static SomeClass SharedField;
public Product()
{
// ... Some logic
}
}
Do all Products pages instances share the same SharedField, I know this is a basic concept of static fields. But in this case, really? all users can have access (and can't have their own instance of) to the same static field on the website-level?
If so, in what aspects this would used by the web developer? or is this non-recommended practice?

Yes, there will be a single instance of that static field for all users, but only within a single worker process. If you have web farms/web gardens, they will each have their own static instance. If the worker process restarts, you'll get a new static instance.
You'll have to use locking around that shared field to ensure thread safety.
As for why to use that, I'm not sure, I never do it. The best example I can give you is the built-in static HttpContext.Current, which gives you access to the Request, Response, etc.

SharedField will be available in one instance for the entire life-cycle of the web site.
To read a bit more about it, see this answer.

A better practice would be to store your object in the Application state.
Application["MyObject"] = new SomeClass();

Related

C#/ASP.NET MVC 4 Instantiate Object Derived From Interface In Factory Method

Currently have a Factory class that features a GetSelector function, which returns a concrete implementation of ISelector. I have several different classes that implement ISelector and based on a setting I would like to receive the appropriate ISelector back.
public interface ISelector
{
string GetValue(string Params);
}
public class XmlSelector : ISelector
{
public string GetValue(string Params)
{
// open XML file and get value
}
}
public static class SelectorFactory
{
public static ISelector GetSelector()
{
return new XmlSelector(); // Needs changing to look at settings
}
}
My question is what is the best way to store the setting? I am aware of using AppSettings etc. but I'm not sure whether I want to have to store strings in the web.config and perform a switch on it - just seems to be really tightly coupled in that if a new implementation of ISelector is made, then the Factory would need to be changed. Is there any way of perhaps storing an assembly name and instantiating based on that?
Thanks,
Chris
It is hard to say, because I don't know the architecture of your particular project, but at a first glance what I would do is if the objects associated with ISelector can be decoupled from your web application, I would put these objects in a class library along with the factory. Your factory will need to be changed if you implement a new ISelector, but if you can decouple the whole ISelector family from your actual web application the depth of the refactoring you will have to do will be minimal compared to a monolithic architecture.
Personally, I tend to avoid AppSettings, web.config settings and the like for mission-critical design questions. Using the web.config as an example, I have seen applications where architectural data is stored for ease of configurability. The problem is that after compilation your web.config can be changed (that is the purpose of it after all) and if the implementation of your classes depends on very specific values being chosen, you are running a risk of a crash when someone inadvertently modifies the wrong value.
Like I said all this depends entirely on your application architecture, but my reflex would be to split out the components that could be subject to future modification into a class library. Loose coupling is your friend ;).
Instead of doing it in AppSettings, I think a better approach will be to create a separate XML file, which will only hold the mappings and from that file you can iterate through the mappings and return correct instance in GetSelector().

Unique way to identify page instance within HttpContext

You can get the name of a page within HttpContext via Request.Path.
Is there a way to distinguish between different requests from the same page?
That is when two different instances of yourpage.aspx make a request, how can you distinguish between the two using HttpContext?
you probably want to do this in a base Page class, but here's what i would do
public partial class Default : System.Web.UI.Page
{
private Guid _instanceID;
public Guid InstanceID
{
get { return _instanceID; }
}
/// <summary>
/// Constructor
/// </summary>
public Default()
{
this._instanceID = Guid.NewGuid();
}
}
then using the HttpContext somewhere else in your code...
if (HttpContext.Current.CurrentHandler is Default)
{
((Default)HttpContext.Current.CurrentHandler).InstanceID;
}
Nothing built into ASP.NET will allow you to differentiate different "page instances" or requests from them.
However, you can easily add a Guid to your view state to uniquely identify each page. This mechanism works fine when you are in the Page class itself. If you need to identify requests before you reach the page handler, you need to use a different mechanism (since view state is not yet restored).
The Page.LoadComplete event is a reasonable place to check if a Guid is associated with the page, and if not, create one.
If you're using authentication, would it work for you to distinguish which user submitted the page?
You could use System.Web.Httpcontext.Current.User.Identity.Name.
just throwing this out there: NInject (and other DI containers) use a scoping mechanism based on the HttpContext.Current object itself, so depending on what you're trying to do, you could attempt to retrieve a state object from the DI container and go from there.

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);
}
}

Most Correct way to redirect page with Model-View-Presenter Pattern

What is the best way to call a Response.Redirect in the Model-View-Presenter pattern while adhering to correct tier separation?
One way I handled this is for the presenter to raise an event (like Succeeded or something) that the view would subscribe to. When the presenter finished it's processing, it would raise the event, which would get handled by the View. In that handler, the view would redirect to the next page.
This way, the presenter doesn't need to know anything about pages or URLs or anything. It just knows when it has completed its task and lets the view know by raising an event. You can raise different events if the presenter succeeded or failed, in case you need to redirect to different places.
I do not know whether it is the most correct way, conceptually.
But what I did in my last MVP-applications, is create a wrapper around HttpContext.Current which I called HttpRedirector.
I also created a dummy redirector for testing purposes. Both keep track of the last redirected url, so that I can check in my unit tests that the redirect actually happened when I call a method on my controller/presenter. With an IOC-container I am able to switch the implementation of IRedirector based on the environment (production/test).
The way we do it works nicely once some ground work is laid. I'm sure there are several ways to skin a cat though. (Who skins cats anyway. Cats are cute and cuddly!)
First, this will only work on the ASP.Net compiled Web Projects, not Websites.
Each page should inherit from a custom abstract base class which looks something like this:
public abstract class PageBase : Page
{
private static string _baseUrl = "/";
public static string BaseUrl
{
get { return _baseUrl; }
set { _baseUrl = value; }
}
protected static string BuildUrl(string basePath)
{
if( !string.IsNullOrEmpty(basePath) && basePath.StartsWith("~/"))
{
basePath = basePath.replace("~/", BaseUrl);
}
return basePath;
}
protected static string LoadView(string path)
{
Response.Redirect(path);
}
}
Each page also implements a page-specific interface. Each page-specific interface also inherits from a base interface:
public interface IPageBase()
{
void LoadView(string path);
}
Then it's a matter of each page defining it's own version of BaseUrl. You might want to account for querystrings/path encryption/etc.
Finally, any of your presenters (which should be referencing the page-specific interfaces) can grab the static BuildUrl() on a desired page to view and then call LoadView() with the returned path.
It depends how generic your presenters are. If your presenters are totally UI agnostic (can be reused between WinForms and WebForms) then you'll have to abstract the redirection operation. In WebForms, the redirection operation would be implemented in the view by a Response.Redirect. In WinForms, (I disclaim lots of experience with WinForms) my guess is that it would be implemented by SomeForm.Show.
One simple, off-the-top-of-my-head option would be to include in the view's interface a ShowViewX() method. You can have one for each form the view could logically redirect to. Alternatively, the view can implement an interface method like Show(ConnectedViews) where ConnectedViews is an enum that includes a value for each of the views that can be "redirected" to from a particular view. This enum would live at the presenter level.
The above approaches are specific to view-presenter pairs. You could instead implement it as a system-wide thing. The logic would be similar to above, implemented in the base view and presenter. There would be a ShowView__() for each form, or a Show(Views) method where Views is an enum of all forms.
It's a toss-up between encapsulation and DRY-ness.

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