views:

1085

answers:

10

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

+3  A: 

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

Robert
+1, I find that designing a stateless view layer with a stateful presentation layer promotes the separation of _business logic_ from _presentation logic_. The latter of which should be the only logic that is aware of session.
Michael Meadows
that's one way of doing it, Michael.
gnomixa
actually that's what I had in mind initially.
gnomixa
I wanted to clarify my comment: View logic is responsible for rendering a view (drawing a screen or page). Presentation logic is logic that is responsible for presenting data to the user and coordinating unsubmitted transactions. Business logic is responsible for modeling the business behavior (transactional behavior). Data Access Logic is responsible for persisting data (as a result of transactions).
Michael Meadows
+1  A: 

My feeling is, is that the business layer is the only place to put the session data access. Becuase 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 the change is more difficult.

What I would do, Is for all the data that is is session state, 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, but this is semantic, and depends on what you consider the data layer.

aquillin
I've always thought of the business layer as a set of functionality to solve the 'actual user-facing problem.' For example, let's say you create an application to convert .doc files to .pdf. You want to provide this as a command line app (1 user at a time) and a web app (many users at a time). Good encapsulation would allow you to completely just drop the same business logic layer into both. I don't see how this would work with a Session object inside, since it is not applicable to the command line implementation.
tehblanx
tehblanx, see my comment to the question body. my app will never be run from anywhere but a web page.
gnomixa
That is implementation detail.....not design....
CSharpAtl
@aquillin, you have two problems if you consume session state in the business logic layer: First, you'll couple your business logic to a technology. You can build adapters to protect you from this, but that's essentially a layer. Second, you are muddying up your types of state. Transient state (session) and persistent state (database) are now connected by a single layer. If you want to add more indirection later, you will have more code to write.
Michael Meadows
I would think this through more if you want a well designed application...separation of responsibility/concerns.
CSharpAtl
I may still write a session management object to encapsulate it. Depends how much time I am given. If we all had unlimited time we would produce 100% pure apps that Knuth would be proud of:)
gnomixa
Michael, what if being able to access the session IS part of your business logic? just playing the devils advocate.
gnomixa
@Michael Meadows. I agree that it does bind your business logic to the technology, but if you do it correctly, you can make your core "business logic" independent from this. And that is to break your business logic into sub layers. Part of the problme, is that people want to view their application in a defines 3-tier architecture, but this is rarely possible. I like to add a data controller tier that manages cache (which includes session) to sit between BL and DAL layers. This allows you seperate it well, and still reuse the BL elsewhere.
aquillin
A: 

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.

tehblanx
+3  A: 

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

CSharpAtl
+3  A: 

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.

MatthewMartin
+4  A: 

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.

GreenieMeanie
A: 

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;
}
WaldenL
A: 

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.

Bryan Rowe
see my comment - switching is not a concern, but I get the point. it's a purity vs reality argument.
gnomixa
A: 

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?

chris
+1  A: 

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.

Rob