Question

Say you have 3 layers: UI, Business, Data.

Is that a sign of poor design if Business layer needs to access Sessions? Something about it doesn't feel right. Are there any guidelines to follow specifically tailored to web app?

I use c# 2.0 .net

Was it helpful?

Solution

My feeling is that the business layer is the only place to put the session data access because it really is part of your logic. If you bake it into the presentation layer, then if you change where that data is stored (lets says, you no longer want to use session state), then making a change is more difficult.

What I would do is for all the data that is is session state, I'd create a class to encapsulate the retrieval of that data. This will allow for future changes.

Edit: The UI should only be used to do the following: 1. Call to the business layer. 2. Interact with the user (messages and events). 3. Manipulate visual object on the screen.

I have heard people consider the session data access as part of the data layer, and this is semantic, and depends on what you consider the data layer.

OTHER TIPS

No. If you had a "Controller" layer, you should access it there. Get what you need from the Session and hand it off to your business layer.

Sigh.

The broad consensus is going to be no; the business layer and the controller/web layer ought to be maintained differently, because they are separate concerns.

The fact is, you seem to label this as a "purity vs. reality" question which is incredibly short-sighted and slightly obnoxious. It also defies the point of asking the question; if you're not going to consider the opinions being presented, then why solicit them?

It's true that separating things out a little more carefully up front requires more up-front effort, more time, and ultimately may cost a little more. It's also true that you may not be able to perceive any immediate benefit from doing so. However, a wealth of sob stories shared among a huge number of programmers for several decades suggests that, where possible, your so-called "purity" reduces the pain when, five years down the line; gosh; you really have to knuckle down and do a bit of refactoring, and it's not remotely pleasant because of all the cracks through which your responsibilities are seeping.

A slightly better way of envisioning the layers for a web application might be to consider presentation, interaction, business rules and data; from top to bottom. Your data is the database, data access, etc. and the business rules enforce any additional constraints on that data, handle valiation, calculation, etc. Interaction then branches between the presentation layer (which is basically your user interface) and the business logic, performing the use cases that drive your application.

Up to this point, the user interface is all immaterial; it doesn't matter if the user's entering, say, customer data in a command-line application, or navigating some multi-page web form with data stored in the session. Let's say you pick the latter; stick a web front-end on it. Now what you're concerned with is writing relatively simple code to handle retrieving the requested data and presenting it to the user. The point is, your web application; the front-end, that is your entire user interface; sessions and all. Only at the point where you're ready to say, "hey, let's stick that customer data into the database" do you go and invoke those oh-so-lovingly-crafted service layers, passing each bit of information that your web application's got stashed; the user input, the name of the user making the change; all that crap. And your service layer deals with it. Or, alternatively, bitches 'cause you forgot a required field.

Because you've cleanly separated things out, the guts of your application can, as others have suggested, be remodelled (or "borrowed") to use in any other application, and the service layer remains, stateless, clean, and ready to handle things. And it does your validation, and so your validation is consistent everywhere. But it doesn't know who's logged into the web frontend, or the console application, or the fancy rich client application running on a terminal, and it doesn't care, because that detail is important only to those applications.

Need to add a new validation rule? No problem; make the service layer do the validation, and handle the user interface concerns as necessary higher up in the chain. Need to change the way something's calculated? Change that at the business layer. Nothing else needs to be affected.

Smells funny to me. Maybe you need a presentation layer to manage the session and any other stateful information?

I think the Business logic should not be tied to a presentation choice, and if Session lives in that tier it will be tied.

I consider unnecessary usage of Session to be a code smell in general, often querystrings, cookies and viewstate are lighterweight and have better 'scope'

As to Sessions role in a business tier, it depends on what architectural guru you're reading at the moment. If the business logic tier is a place for code independent of UI, then Session isn't a thing to introduce into the business tier.

For example, in a Console app, an ASP.NET web App, a Windows Service, and a Windows Forms app--only ASP.NET has Session.

That said, being able to support mutliple UIs is a highly overrated feature and it doesn't take perfect foresight to estimate if you will ever port your app to a different user interface. If you're highly confident that your logic will only run in an ASP.NET app from now and forever, then it is okay.

An exception would be unit testing. nUnit test runners constitute a different UI and it is hard to simulate Request, Response, Session, Application, etc.

If you keep the three layers you listed, the 'Business' layer would likely be the most suited to dealing with Session objects.

Since a session has more to do with the actual framework tying the application together than with any actual business logic, you may want to create a control layer that translates data from the Session object to business data inputs to the business layer.

I think it depends on the usage, but yes, we access session from our business layer all the time. There's a "purity vs. reality" argument here too.

For example, in our application we have a database per client, but one code base. So we have the client info in the session for each user. Sure, we could then pull that data out of session in the web layer and then pass it down to the business layer. Of course, the business layer doesn't even care about it, but it's needed by the data layer to connect to the correct database. So then the business layer would need to pass it down to the data layer. Seems like lots of parameter passing for no good business reason. In our case our data layer checks the session object for the connection string and runs from there. We coded around the issue of not having session if it's not a web app (and we have windows services and .exe helper apps) as follows:

protected virtual string GetConnectionString()
{
string connectionString;
string connectionStringSource;

//In app.config?
if (ConfigurationManager.AppSettings[_ConnectionStringName] != null &&
   ConfigurationManager.AppSettings[_ConnectionStringName] != "")
{
   connectionString = ConfigurationManager.AppSettings[_ConnectionStringName];
   connectionStringSource = "Config settings";
}
//Nope? Check Session
else if (null != HttpContext.Current && null != HttpContext.Current.Session &&
   null != HttpContext.Current.Session[_ConnectionStringName])
{
  connectionString = (string)HttpContext.Current.Session[_ConnectionStringName];
  connectionStringSource = "Session";
}
//Nope? Check Thread
else if (null != System.Threading.Thread.GetData(
      System.Threading.Thread.GetNamedDataSlot(_ConnectionStringName)))
{
   connectionString = (string)System.Threading.Thread.GetData(
          System.Threading.Thread.GetNamedDataSlot(_ConnectionStringName));
   connectionStringSource = "ThreadLocal";
}
else
{
   throw new ApplicationException("Can't find a connection string");
}

if (debugLogging)
   log.DebugFormat("Connection String '{0}' found in {1}", connectionString, 
          connectionStringSource);

return connectionString;
}

Accessing the session from the business layer is definitely a code smell.

If you need to 'switch' the business layer as stated, your presentation layer or controller is all that need to worry about what the session variable is.

For example, say you want to use one set of objects for one session variable and another set for another variable. Your controller could call a service layer and pass in the variable. The service layer would then return the appropriate business object.

Your business layer has no business knowing anything about the session in the same sense that your presentation layer has no business knowing about how you are connecting to the DB.

The session object is tied to a specific UI implementation, so having your business layer died to your session is a smell.

Plus, you probably should be able to unit-test your business layer - how are you going to do that if there are dependencies on a session?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top