Response.Redirect
在坚持正确的层分离的同时,在 Model-View-Presenter 模式中调用 a 的最佳方法是什么?
4 回答
Succeeded
我处理此问题的一种方法是让演示者引发视图将订阅的事件(如或其他)。当 Presenter 完成它的处理时,它会引发事件,该事件将由 View 处理。在该处理程序中,视图将重定向到下一页。
这样,演示者不需要知道任何关于页面或 URL 或任何东西的信息。它只知道它何时完成了任务并通过引发事件让视图知道。如果演示者成功或失败,您可以引发不同的事件,以防您需要重定向到不同的地方。
从概念上讲,我不知道这是否是最正确的方法。但是我在上一个 MVP 应用程序中所做的是创建一个包装器HttpContext.Current
,我将其称为 HttpRedirector。我还为测试目的创建了一个虚拟重定向器。两者都跟踪最后一个重定向的 url,以便我可以在单元测试中检查当我在控制器/演示器上调用方法时重定向实际上发生了。使用 IOC 容器,我可以IRedirector
根据环境(生产/测试)切换实现。
一旦奠定了基础工作,我们的工作方式就会很好地工作。我敢肯定有几种方法可以给猫剥皮。(反正谁给猫剥皮。猫很可爱!)
首先,这仅适用于 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 版本的问题。您可能需要考虑查询字符串/路径加密/等。
最后,您的任何演示者(应该引用特定于页面的接口)都可以获取所需页面上的静态 BuildUrl() 以进行查看,然后使用返回的路径调用 LoadView()。
这取决于您的演示者的通用性。如果您的演示者完全与 UI 无关(可以在 WinForms 和 WebForms 之间重用),那么您将不得不抽象重定向操作。在 WebForms 中,重定向操作将通过 Response.Redirect 在视图中实现。在 WinForms 中,(我否认有很多使用 WinForms 的经验)我的猜测是它将由 SomeForm.Show 实现。
一个简单的、令人难以置信的选项是在视图的界面中包含一个 ShowViewX() 方法。您可以为视图可以逻辑重定向到的每个表单设置一个。或者,视图可以实现类似 Show(ConnectedViews) 的接口方法,其中 ConnectedViews 是一个枚举,其中包含每个视图的值,这些视图可以从特定视图“重定向”到。此枚举将存在于演示者级别。
上述方法特定于视图-呈现器对。您可以改为将其实现为系统范围的事物。逻辑与上面类似,在基本视图和演示器中实现。每个表单都有一个 ShowView__(),或者一个 Show(Views) 方法,其中 Views 是所有表单的枚举。
这是封装和干燥之间的折腾。