Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Most Correct way to redirect page with Model-View-Presenter Pattern

What is the best way to call a Response.Redirect in the Model-View-Presenter pattern while adhering to correct tier separation?

like image 340
Chris Marisic Avatar asked Jan 15 '10 19:01

Chris Marisic


4 Answers

One way I handled this is for the presenter to raise an event (like Succeeded or something) that the view would subscribe to. When the presenter finished it's processing, it would raise the event, which would get handled by the View. In that handler, the view would redirect to the next page.

This way, the presenter doesn't need to know anything about pages or URLs or anything. It just knows when it has completed its task and lets the view know by raising an event. You can raise different events if the presenter succeeded or failed, in case you need to redirect to different places.

like image 178
KevnRoberts Avatar answered Nov 15 '22 09:11

KevnRoberts


I do not know whether it is the most correct way, conceptually. But what I did in my last MVP-applications, is create a wrapper around HttpContext.Current which I called HttpRedirector. I also created a dummy redirector for testing purposes. Both keep track of the last redirected url, so that I can check in my unit tests that the redirect actually happened when I call a method on my controller/presenter. With an IOC-container I am able to switch the implementation of IRedirector based on the environment (production/test).

like image 44
Ruben Avatar answered Nov 15 '22 10:11

Ruben


The way we do it works nicely once some ground work is laid. I'm sure there are several ways to skin a cat though. (Who skins cats anyway. Cats are cute and cuddly!)

First, this will only work on the ASP.Net compiled Web Projects, not Websites.

Each page should inherit from a custom abstract base class which looks something like this:

public abstract class PageBase : Page
{
  private static string _baseUrl = "/";

  public static string BaseUrl
  {
    get { return _baseUrl; }
    set { _baseUrl = value; }
  }

  protected static string BuildUrl(string basePath)
  {
    if( !string.IsNullOrEmpty(basePath) && basePath.StartsWith("~/"))
    {
      basePath = basePath.replace("~/", BaseUrl);
    }
    return basePath;
  }

  protected static string LoadView(string path)
  {
    Response.Redirect(path);
  }
}

Each page also implements a page-specific interface. Each page-specific interface also inherits from a base interface:

public interface IPageBase()
{
  void LoadView(string path);
}

Then it's a matter of each page defining it's own version of BaseUrl. You might want to account for querystrings/path encryption/etc.

Finally, any of your presenters (which should be referencing the page-specific interfaces) can grab the static BuildUrl() on a desired page to view and then call LoadView() with the returned path.

like image 42
ddc0660 Avatar answered Nov 15 '22 10:11

ddc0660


It depends how generic your presenters are. If your presenters are totally UI agnostic (can be reused between WinForms and WebForms) then you'll have to abstract the redirection operation. In WebForms, the redirection operation would be implemented in the view by a Response.Redirect. In WinForms, (I disclaim lots of experience with WinForms) my guess is that it would be implemented by SomeForm.Show.

One simple, off-the-top-of-my-head option would be to include in the view's interface a ShowViewX() method. You can have one for each form the view could logically redirect to. Alternatively, the view can implement an interface method like Show(ConnectedViews) where ConnectedViews is an enum that includes a value for each of the views that can be "redirected" to from a particular view. This enum would live at the presenter level.

The above approaches are specific to view-presenter pairs. You could instead implement it as a system-wide thing. The logic would be similar to above, implemented in the base view and presenter. There would be a ShowView__() for each form, or a Show(Views) method where Views is an enum of all forms.

It's a toss-up between encapsulation and DRY-ness.

like image 27
G-Wiz Avatar answered Nov 15 '22 11:11

G-Wiz