views:

435

answers:

4

I've inherited an ASP.NET application built on top of webforms, and the application suffers from having all of its business logic embedded in the codebehind. As a result, this application can't be unit tested.

I want to break out the functionality of every form into an MVC style, but I've found that ASP.NET resists every effort on my part to refactor it. In general, I like to seperate my MVC classes as follows:


public class LoginModel
{
    public string Username, Password;
    public bool IsAuthenticated;
}

public interface ILoginView
{
    event Action UserLoggedIn;
    void SetMode(bool isAuthenticated);
}

public class LoginController
{
    ILoginView View;
    LoginModel Model;

    public LoginController(ILoginView view, LoginModel model)
    {
        this.View = view;
        this.Model = model;

        // hook onto view events
    }
}

Once I've got my classes set up and nicely unit tested, I can implement the ILoginView interface on my usercontrol or page:


public class LoginView : UserControl, ILoginView
{
    public LoginView() : base()
    {
        new LoginController(this); // registers view with the controller
    }
}

If this were a winform application, it would work beautifullly. But the ASP.NET lifecycle causes this style to break down.

  • ASP.NET creates and destroys the view on every page load. Since my Controller is held by the View, the Model is held by the Controller, every postback causes my page to lose its state.

  • I can remedy the problem above by holding my Controller in the users session, but that introduces a world of problems. In particular, putting Controllers in the session causes memory issues because Models and Controllersaren't reclaimed by garbage collection until the session expires. Navigating from page to page creates dozens of controllers, but the controllers don't dispose of themselves when the user navigates away from a page.

  • Since a view is destroyed/recreated on every postback, then I have to re-register the view with the controller on every postback. This is harder to do than it sounds, because the state of the Model needs to be copied back to the View on every postback, but simultaneously we don't want to overwrite a users changes to the View which were made in the previous postback. You have no idea what kind of additional nightmare this turns into when dealing with dynamically created or AJAXed controls using this MVC style.

I know I'm overthinking this and there is an easier way to get the results I want, but how do I implement an MVC style properly using webforms?

+1  A: 

Is it not easier to re-write this using asp.net mvc?

redsquare
No, the project is based on DotNetNuke, so its incompatible with ASP.NET MVC.
Juliet
+1  A: 

As it seems you'll have to re-write. Either completely to MVC (and stop using DNN), or to a better WebForms implementation (meaning, separate logic from display and take into account the page life-cycle issues). There's a third option - combining MVC and ASP.NET WebForms, but you should look at it carefully taking into account all the variables in your platform.

synhershko
A: 

Well the nature of the POSTback is dictating your state changes, so you should react on that. Any framework you use would work pretty much the same way, it'll rebuild/bind the state with each request. You should look into savind the state (read data) into your user's session.

A: 

ViewState should be used to store all the loaded data in WebForms, so the Controller would be instancied only when the page is created, eliminating the need to store any object in the user session.

Arborend