开发者

asp.net mvc - reusing pages/controllers in workflow

I have 2 workflows:

1) the user signs up for the first time. They see 3 different screens, their basic user information, their credit card, and some additional profile information. They complete these 3 steps in a wizard like fashion, where each time they hit "submit" they leave the current screen and move on to the next.

2) the user already is signed up. He has links in the na开发者_Go百科vigation to these 3 seperate pages. He can update them in any order. When he hits save, he doesn't leave the page he's on, it just shows something at the top that says "Credit Card Info saved..." or whatever. Possibly using ajax or maybe a full page refresh.

I would like to reuse the code not only the view but also in the controller for these 3 screens between the two workflows, but without a ton of if...then logic to determine where to go next depending on whether its a first signup in the wizard or updating individual parts of a profile.

Any ideas?

Here is the type of code i'm trying to reuse:

    public ActionResult Index()
    {
        var model = this.GetModel();
        return this.View(Views.Index, model);
    }

    public ActionResult Save()
    {
        var model = this.GetModel();
        this.TryUpdateModel(model);
        this.UserAccountRepository.Save(model.CurrentUser);
        return this.RedirectToAction<EditCreditCardController>(c => c.Index());
    }

    private EditCreditCardModel GetModel()
    {
        var model = new EditCreditCardModel();
        model.CCTypes = ModelHelper.PopulateDropDownWithModel(this.CardTypeRepository, this.CurrentUser.CreditCard.CardType);
        model.States = ModelHelper.PopulateDropDownWithModel(this.StateRepository, this.CurrentUser.BillingAddress.State);
        model.CurrentUser = this.CurrentUser;
        return model;
    }


Essentially the solution is very simple and involves creating a new abstract class of Controller called "CommonController" (or XController, or whateverController you like) and placing the code in there instead of your actual controller. When you create a controller normally, this is the code you use:

public class HomeController : Controller

Create a new controller, and use this instead:

public abstract class CommonController : Controller

Notice the "abstract" keyword in there, that's the only difference. Now, in your actual Controllers, you need them to inherit this CommonController instead of the normal Controller, so instead of using:

public class HomeController : Controller

You need to use:

public class HomeController : CommonController

Now, in this class instead of the usual ActionResult methods, you'll have a void method set up like so:

public void CommonController() { 
ViewData["MyVariable"] = value; 
}

Now that you've done that, all of the ViewData variables set in CommonController will be available to the Views returned from your Controller.

In summary: Set up a new controller called "CommonController" like this:

public abstract class CommonController : Controller {
    public void CommonController() {
        // PUT ALL OF YOUR COMMON VARIABLES AND STUFF
        // IN HERE!
        ViewData["MyVariable"] = "BOB THE BUILDER!";
        if(isLoggedIn) {
            ViewData["User"] = "BOB";
        }else{
            ViewData["User"[ = "Unknown User";
        }
        // Etc, etc, etc.
    }
}

Then make your existing controllers use the CommonController as their base Controller class:

public class HomeController : CommonController {
    public ActionResult Index() {
       return View();
    }
}

In your View, you should be able to write <%=ViewData["MyVariable"]%> and "BOB THE BUILDER!" will appear! }


As a general rule of thumb, controller methods should be very slim, similar to:

public ActionResult SomeAction(int foo, string bar)
{
    MyViewModel model = repository.GetData(foo, bar);
    return View("SomeView", model);
}

So when you talk about controller reuse, you shouldn't really have any need or use for it. If it seems difficult to reuse controller logic then it probably means that your controllers are too fat, they're doing too much.

As for reusing views, you just need to make judicious use of partial views. I'd be more specific, but that's difficult to do without knowing the details of what's in these views. Something like a set number of user profile fields would be very easy to place in a partial view.


After looking at your edit, the best I can say is that the GetModel() method shouldn't be part of your controller, it should be part of your model (i.e. a repository or service somewhere), so you wouldn't have to keep rewriting those 5 lines of code.

As for the rest, though... I don't really see what you'd stand to gain from any further abstraction. The Index method is just two lines of code which could technically be reduced to one, and the Save method is three lines (the fourth is a redirect which is likely to be different for each controller).

I'm all in favour of abstraction and code reuse, but for just 2 distinct controllers, trying to do more than what you appear to already have (based on the updated code examples) is probably overkill (aside from the GetModel piece, which could be moved). If you had 5 or 20 controllers all repeating this code, then I might implement either a CreditCardController base class or a CreditCardHelper utility class. But not yet, at this point it would just be further obscuring the controller logic.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜