I was hoping someone could help clarify my options regarding refactoring methods from code-behinds from ASP.NET webforms pages.
As background, we have spent some time recently implementing the repository pattern in both a generic and non generic sense, which has enabled us to move a lot of the DAL methods out of the codebehinds, which is great.
What I’m struggling to finalise, is a sensible approach to moving application logic methods out of the codebehinds which specific focus on the repository/DAL and how best to structure the BL classes.
Here are the two options I am considering at present:
1.Create a Business Logic class per codebehind and from this, expose
methods like getProject(int id) which would behind the scenes,
access a repository instance of repo.GetById(int id)
The benefit of this as far as I can see would be the following:
- seperate app logic from the codebehinds, allowing them to be simple
- allowing testable methods at the BLL (with some tweaking), kind of synonymous with controller classes in MVC (this is still webforms though)
- Doesn’t expose the repository directly
The downside would be:
- A lot of wrapper methods in the BLL which don’t really do anything
besides hide the repository methods
2.Write extension methods on my entity types, e.g. Project.getUsers() which would access a repository instance method allowing BL to be stored without the need for a specific BLL class, thereby reducing the duplication of the wrapper methods in each BL class.
The benefit of this would be:
- No need to have a BL as such, storing methods with their entity type
- Less wrapper methods, as there wouldn’t be a need for
ProjectBL.getUsers(projectid)andUserBL.getUsers(projectid)which both callrepo.getProjectUsers(projectid)behind the scenes, simpleProject.getUsers()from both codebehinds
The downside of this as far as I can tell:
- If I introduce new types in the future, e.g. ‘SubProject’
getUsers()needs to be re-implimented - I’m not too keen on extension methods in general and not sure if this is the right place to use them!
I’m a little unsure which is ‘better’ practice, or if I’ve missed a better option all together. It may be worth knowing that initially the repository was being instantiated in the codebehind and accessed directly, but as I understand things, this is not ideal as we risk returning things like IQueryable from the repository and making DAL methods which can be manipulated in codebehind to produce inconsistent results.
The model I have found to be most effective with ASP.NET Webforms is the bind/unbind pattern. In this pattern, the only things you implement in the codebehind itself are event handlers (which will call back to more abstracted, logic-heavy methods in a BLL of some sort) and one method each to transfer data from (Bind) and to (Unbind) an instance of a domain object or DTO.
By structuring the codebehind in this way, the codebehind class becomes concerned only with the interop between logic and presentation, and so becomes quite thin in most cases. The data it will deal with will be primarily primitives and the DTO, and it will not require any knowledge of the DAL (at least, individual page codebehinds won’t; you may set up your master page or a base class for your codebehinds to have DAL-touching methods common to wide swaths of your site, basically making this base class your Controller layer in code).
One other thing to keep in mind is that, depending on structure, it can be very simple to unit-test your codebehind classes. You can even TDD them, to a point; the declaration of basic GUI elements in the markup (and their object representations in the codebehind) is still best left to the IDE, but a public codebehind class with publicly-accessible members can be easily instantiated in a unit test, and the public methods exercised.