Best method for a generic web applications 'features' / global properties - asp.net

I'm creating a generic flexible site that I can use over and over again but with different features activated or deactivated. I'm looking for the best method to approach my solution.
Specific areas will need to be closed off in certain circumstances, for instance, the application will contain an event management page, but it will not always be required. The application will pull out the active and deactivated features from a data source.
They're going to be like Application wide settings, that will be required on each page, hiding away those settings that are turned off from the menu and not allowing users to access the deactivated feature pages.
I have thought of a number of ways to achieve this :
Store the feature statuses in the database, then on each time the page / menu is accessed / displayed, call the database requesting whether to hide the page / menu item.
Store the feature statuses in the database and access them on the application startup, store them application wide then they can be accessed as and when.
Put the feature statuses in the web config, this way we don't need to query the database every single time or have globally accessible properties.
I would like you advice on which method would be best, or if a better method is available I would be grateful. I don't want to hit the database too many times, or would a simple check like this not be too performance expensive? I'm also not sure if the web config is secure enough for managing active site features.
Regards,

I think putting configuration in configuration file(web.config) would be better option. Because while displaying page/loading menu going to database every time to see whether it should be de/active, required database trip which is overhead.
And if the configuration is stored in web.config it is easily accessible by admin and also easy to modify without compiling or changing anything.
So, in my view best option is to store configuration in web.config. In addition to that you can also make administration page which will change configuration settings and should be reflected in configuration file.

I suggest 2nd approach - store the settings in the database and then retrieve them at startup and store in application scoped containers.
The advantage of such approach over the web.config is that you can easily take client database and immediately run it in your development environment for testing/debugging. If, on the other hand, some settings are stored outside of the database, cloning the site means that you not only have to clone the database but also all the settings from various other resources (like the web.config).

The answer depends on how often you will be changing the status of the features.
If you are going to only set the statuses once when you clone the site and will never touch it again, go with option #2 (load on application start).
If there is any possibility that you will need to change the status of the features in the future, go with option #1 (get statuses on each page load). A simple datareader read to the db will not affect the speed of your site. The db is your friend, remember that's what it is there for. Also, if you ever need to change the statuses while the site is up and running, this method allows you to do so without restarting the entire application.
Whatever method you finally decide to implement, make sure the "application wide" location you store the settings is multi-threaded ready. Remember, each page request will be run on a separate thread and they will all access the same resource.
My suggestion taken from MS (multi-thread safe Singleton Pattern):
using System;
public sealed class Singleton
{
private static volatile Singleton instance;
private static object syncRoot = new Object();
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}

Related

Application level variables in web api c#

I am in a situation where requirement is to keep an application level object in web api which can be accessed by all requests. I know one can use HttpContext.Current but that is not required since HttpContext is only for the liftime of request. I need a solution where i can keep an object that all requests can access and update as required.
Use a static class to hold your application level objects. static classes and static data members are created once for the application lifetime and all ASP.NET requests can access them.
I learnt it the hard way. Some time back, I mistakenly created a static field to hold customer-specific database connection string, in a ASP.NET Web API project and it became a mess. On each customer's login it was being set (overridden) in the code and the requests from the previously logged customers were using this newly set static SQL connection string for their queries. It was an embarrassing situation when customer's inadvertently saw each other's data.
You could use SessionState (per session).
I.e.
Session["YourDataKey"] = ApplicationLevelObject;
And then check the session state variable on each request that requires it.
However if you require the object for longer, I.e. every single user session, then I would suggest persisting your object to a database. You could use an ORM such as Entity Framework.
Cheers

static initialization of a class used by asp.net-- how long will the initialized values last?

We're writing a class we'll use in our asp.net site. This class will pull down some json using HttpClients and such, and use it to provide information to other clients.
Some of this information will change very infrequently and it doesn't make sense to query for it on each client request.
For that reason I'm thinking of making a static constructor in this new class for the slow-changing information and stashing the results in a few static member variables. That'll save us a few HttpRequests down the line-- I think.
My question is, how long can I expect that information to be there before the class is recycled by ASP.Net and a new one comes into play, with the static constructor called once more? Is what I'm trying to do worth it? Are there better ways in ASP.Net to go about this?
I'm no expert on ASP.Net thread pooling or how it works and what objects get recycled and when.
Typical use of the new class (MyComponent, let's call it) would be as below, if that helps any.
//from mywebpage.aspx.cs:
var myComponent = new MyComponent();
myComponent.doStuff(); //etc etc.
//Method calls like the above may rely on some
//of the data we stored from the static constructor call.
Static fields last as long as the AppDomain. It is a good strategy that you have in mind but consider that the asp runtime may recycle the app pool or someone may restart the web site/server.
As an extension to your idea, save the data locally (via a separate service dedicated to this or simply to the hard drive) and refresh this at specific intervals as required.
You will still use a static field in asp.net for storing the value, but you will aquire it from the above local service or disk ... here I recommend a System.Lazy with instantiation and publication options on thrread safe (see the constructor documentation).

How to lock database table in ASP.NET

Our project is running on ASP.NET, we are using Entity Framework with LINQ (lambda syntax) and we need to prevent from inserting into table at same time. I tried to use ReaderWriterLock class, but it works only in one session (when opened more tabs in browser), but not in more different browsers. I also read about creating table with timestamps (not sure if it can solve our problem) or use transactions, but do not now exactly how to use it in web application with LINQ.
Can you tell me please how to handle this exclusive write access in ASP.NET?
The ReaderWriterLockSlim could be a good choice, but if you want that ANY thread/process may share the same lock, the whole ReaderWriterLockSlim must be a static member.
That is, your class should look like this:
public class Class1
{
private readonly static ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
}
Important note
Using an application layer lock you'll be able to lock your own application threads in order to limit one thread to access the database at once. But other applications (not the ASP.NET one, or another application in another application pool also on IIS) may be able to access the database in parallel either doing reads and writes.
If you want a 100% effective solution, you must use database transactions. If SQL Server is the RDBMS, you can go for a transaction with Serializable isolation level:
Volatile data can be read but not modified, and no new data can be
added during the transaction.
Learn more here.

global.asax scope and lifetime clarification

I need to implement several application-level behavior in a project I'm currently working on.
There are several things I need to get my head around:
1. Where and how do I define application level variables?
2. What is the lifetime of these variables? or more accuratly, in what scenarios are they discarded? (Application pool recycle? App binaries dropped from memory and recompiled on the next request? etc.)
3. Is the global.asax file a good place to put a session counter, or maybe storing the value to a DB / file is a better way of persisting this kind of data?
Any comments or ideas are welcome.
Thank you!
-Elad
Application-level variables have an application life-time. It means that it the application pool is recycled, they're discarded.
The application pool can be recycled for different reasons. IIS 6/7 can be configures so that the app pool is recycled after a certain amount of time, after a certain number of request or at specified intervals.
You set an application variable this way:
Application["DbConfig"] = "my value";
but you have to be aware of the problems you might encounter if you try to set/access in different place. You have to adopt a way to lock the variables when they're updated.
I us the web.config for all the configuration parameters and then I've created my own class which I use to store application fields:
namespace Web.My
{
public class Application
{
public static string ApplicationStorageFolder
{
get
{
return (System.IO.Path.Combine(HttpContext.Current.Server.MapPath("~"), "_AppStorage"));
}
}
}
}
If I need set some fields I do it at the application startup Application_Start
If you need to persist infos you can create your own config file (xml or simple text) to store and read values at the application startup and shutdown. You can serialize your class in a XML file so you can ready it, repopulating your properties easily.
A db would be fine as well.
I would do the same with the session counter.

How to access Session values from layers beneath the web application layer

We have many instances in our application where we would like to be able to access things like the currently logged in user id in our business domain and data access layer. On log we push this information to the session, so all of our front end code has access to it fairly easily of course. However, we are having huge issues getting at the data in lower layers of our application. We just can't seem to find a way to store a value in the business domain that has global scope just for the user (static classes and properties are of course shared by the application domain, which means all users in the session share just one copy of the object). We have considered passing in the session to our business classes, but then our domain is very tightly coupled to our web application. We want to keep the prospect of a winforms version of the application possible going forward.
I find it hard to believe we are the first people to have this sort of issue. How are you handling this problem in your applications?
I don't think having your business classes rely on a global object is that great of an idea, and would avoid it if possible. You should be injecting the necessary information into them - this makes them much more testable and scalable.
So rather than passing a Session object directly to them, you should wrap up the information access methods that you need into a repository class. Your business layer can use the repository class as a data source (call GetUser() on it, for example), and the repository for your web app can use session to retrieve the requested information (return _session.User.Identity).
When porting it to winforms, simply implement the repository interface with a new winform-centric class (i.e. GetUser() returns the windows version of the user principal).
In theory people will tell you it's a bad business practice.
In practice, we just needed the data from the session level available in the business layers all the time. :-(
We ended up having different storage engines united under a small interface.
public interface ISessionStorage
{
SomeSessionData Data {get;set;}
...
.. and most of the data we need stored at "session" level
}
//and a singleton to access it
public static ISessionStorage ISessionStorage;
this interface is available from almost anywhere in our code.
Then we have both a Session and/or a singleton implementation
public WebSessionStorage
{
public SomeSessionData Data
{
get { return HttpContext.Current.Session["somekey"] as SomeSessionData;}
set { HttpContext.Current.Session["somekey"] = value;}
}
public WebFormsSessionStorage
{
private static SomeSessionData _SomeSessionData; //this was before automatic get;set;
public SomeSessionData
{
get{ return _SomeSessionData;}
set{ _SomeSessionData=value; }
}
}
On initing the application, the website will do a
Framework.Storage.SessionStorage = new WebSessionStorage();
in Global.asax, and the FormsApp will do
Framework.Storage.SessionStorage = new WebFormsSessionStorage();
I agree with Womp completely - inject the data down from your front-end into your lower tiers.
If you want to do a half-way cheat (but not too much of a cheat), what you can do is create a very small assembly with just a couple POCO classes to store all of this information you want to share across all of your tiers (currently logged-in username, time logged in, etc.) and just pass this object from your front-end into your biz/data tiers. Now if you do this, you MUST avoid the temptation to turn this POCO assembly into a general utility assembly - it MUST stay small or you WILL have problems in the future (trust me or learn the hard way or ask somebody else to elaborate on this one). However, if you have this POCO assembly, injecting this data through the various tiers becomes very easy and since it's POCO, it serializes very well and works nicely with web services, WCF, etc.

Resources