使用Model-View-Presenter模式重定向页面的最正确方法

5

在遵循正确的层次结构分离的同时,在Model-View-Presenter模式中调用Response.Redirect的最佳方法是什么?

4个回答

6
一种我处理这个问题的方法是让主持人引发一个事件(比如 Succeeded 或其他),让视图进行订阅。当主持人完成处理后,它会引发该事件,由视图进行处理。在处理程序中,视图会重定向到下一个页面。
这样,主持人不需要知道任何关于页面或URL的信息。它只知道完成任务并通过引发事件让视图知道。如果需要重定向到不同的位置,您可以引发不同的事件,以表示主持人成功或失败。

1
我最近又在思考这个问题,使用事件相对于方法真的有明显的优势吗? - Chris Marisic

4

在概念上,我不知道是否是最正确的方式。但在我的最后一个MVP应用程序中,我创建了一个称为HttpRedirector的HttpContext.Current包装器。我还创建了一个虚拟的重定向测试程序。这两个都跟踪上次重定向的URL,以便在调用控制器/Presenter上的方法时,我可以检查我的单元测试是否实际发生了重定向。通过IOC容器,我能够基于环境(生产/测试)切换IRedirector的实现。


抽象化HttpContext,我也非常喜欢。 - Chris Marisic

1

在一些基础工作完成后,我们所采用的方式非常有效。虽然我相信有很多种方法可以达到同样的效果。(不过谁会去剥猫皮呢?猫咪可爱又惹人喜爱!)

首先,这个方法只适用于ASP.Net编译的Web项目,而不是网站。

每个页面都应该继承自一个自定义的抽象基类,它看起来像这样:

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);
  }
}

每个页面还实现了一个特定于页面的接口。每个特定于页面的接口也继承自一个基础接口:
public interface IPageBase()
{
  void LoadView(string path);
}

然后,每个页面定义自己的BaseUrl就成为了一个问题。您可能需要考虑查询字符串/路径加密等因素。

最后,任何引用特定页面接口的Presenter都可以获取所需页面上的静态BuildUrl()以查看并使用返回的路径调用LoadView()。


1

这取决于你的Presenter是否是通用的。如果你的Presenter完全与UI无关(可以在WinForms和WebForms之间重复使用),那么你就需要对重定向操作进行抽象。在WebForms中,重定向操作将由视图通过Response.Redirect实现。在WinForms中(我对WinForms的经验不多),我猜想它可能是通过SomeForm.Show来实现的。

一个简单的、即兴的选择是,在视图的接口中包含一个ShowViewX()方法。你可以为视图可以逻辑上重定向到的每个窗体都有一个方法。或者,视图可以实现一个类似于Show(ConnectedViews)的接口方法,其中ConnectedViews是一个枚举,其中包含从特定视图可以“重定向”到的每个视图的值。这个枚举将存在于Presenter级别。

上述方法针对视图-Presenter对是具体的。你也可以将其实现为系统范围的。逻辑与上述相似,实现在基础视图和Presenter中。将会有一个ShowView__()方法,用于每个窗体,或者一个Show(Views)方法,其中Views是所有窗体的一个枚举。

这是封装和DRY原则之间的权衡。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接