MVC3控制器和视图可重用性

时间:2011-08-04 13:34:19

标签: asp.net-mvc-3 reusability

我目前正在开发一组MVC3 Web应用程序,这些应用程序有许多共同点,但是作为单独的程序包部署。一个例外是为每个安装部署的管理应用程序。他们还共享一个数据库和一组共同实体。

最近增加的内容包括身份验证(自定义表单身份验证),自动菜单构建(使用控制器操作属性)和其他一些屏幕。我遇到的问题是我必须创建重复的控制器和视图。

最好的例子是身份验证位。每个应用程序现在都有一个帐户控制器和身份验证视图,它们是彼此的副本。您可以看到,由于添加了更多应用程序,这很快就会成为维护噩梦。另一个例子是每个呈现菜单的应用程序中的共享视图(通常通过Html.Action调用)。这还需要一个在每个应用程序中看起来完全相同的控制器。

我设法将身份验证和菜单构建的实现细节抽象为一个名为XXX.Core.Mvc的共享项目,该项目还具有常见的htmlHelper扩展和Mvc web特有的任何内容。所以现在应用程序中所有重复的视图和控制器都充当代理。

我正在寻找一个关于如何摆脱这些的好模式,因此常见的视图和控制器将驻留在可以引用/调用它们的共享项目中。有没有人做过这样的事情?你能推荐一些好的文章或例子吗?

例如,如何指定将View ActionResult返回到不同项目或共享路径中的视图的控制器操作?如何将例如/ Account / Authenticate路由到另一个项目中的控制器?方法的部署含义是什么?

1 个答案:

答案 0 :(得分:0)

我尝试了两件事。在每种情况下,公共控制器和视图都位于单独的组件中。为了概念验证,我实现了常见的应用程序错误处理所以在我的终点Mvc3应用程序中,global.asax实现:

protected void Application_Error()
{
    ApplicationErrorHandler.Get().Handle(Server, new HttpResponseWrapper(Response), new HttpContextWrapper(Context));
}

在单独的程序集中实现Application错误处理程序:

public class ApplicationErrorHandler
{
    public static ApplicationErrorHandler Get()
    {
        return new ApplicationErrorHandler();
    }

    public void Handle(HttpServerUtility server, HttpResponseBase response, HttpContextBase context)
    {
        var exception = server.GetLastError();
        var httpException = exception as HttpException;
        response.Clear();
        server.ClearError();
        var routeData = new RouteData();
        routeData.Values["controller"] = "Errors";
        routeData.Values["action"] = "Http500";
        routeData.Values["exception"] = exception;
        response.StatusCode = 500;
        if (httpException != null)
        {
            response.StatusCode = httpException.GetHttpCode();
            switch (response.StatusCode)
            {
                case 403:
                    routeData.Values["action"] = "Http403";
                    break;
                case 404:
                    routeData.Values["action"] = "Http404";
                    break;
            }
        }
        IController errorsController = new ErrorsController();
        var rc = new RequestContext(context, routeData);
        errorsController.Execute(rc);
    }
}

在Controllers文件夹中的同一个程序集中,ErrorsController和Views \ Errors保存了所需的3个视图; Http403.cshtml,Http404.cshtml和Http405.cshtml。所以结构与普通的Mvc3项目相同。但是,为了使@model支持和intelisense工作,您还需要web.config - 来自常规项目中Views的文件的副本,并放置在此单独程序集中的视图下。

当我们的应用程序中发生应用程序错误(http状态500 - 内部服务器错误)时,执行ErrorsController,在这种情况下使用的视图将是Http500.cshtml。调查的路径将是:

  • 〜\视图\错误\ Http500.cshtml
  • 〜\视图\共享\ Http500.cshtml

为了从程序集中提供文件,我尝试了两件事:

方法一:实现VirtualPathProvider。我不会详细介绍,但目标是将cshtml视图作为资源嵌入,并使用VirtualPathProvider和VirtualFile为它们提供服务。这种方法的问题是我发现没有可行的方法来从Views文件夹中为web.config提供服务,以便让Razor评估视图。我可以让它检索文件并流式传输但不执行它。要解释问题所在,请考虑Http500.cshtml:

@model Exception
<h3>@MvcHtmlString.Create(Model.Message.Replace(Environment.NewLine, "<br />").Replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;"))</h3>
<p>@MvcHtmlString.Create(Model.StackTrace.Replace(Environment.NewLine, "<br />").Replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;"))</p>
<input type="hidden" name="serverError" value="true"/>

返回的是文件的内容而不是评估的Exception。原因是需要提供View文件夹中的web.config以便使用Razor。默认情况下,视图引擎是Web表单(.aspx)。

方法二:在IIS中创建虚拟目录。这种方法效果更好,因为视图不必编译为资源,不需要虚拟化。所需的只是在我的最终应用程序中的Views文件夹下创建虚拟目录错误,并将其指向部署Views / Errors from common assembly的位置。

当然,它不像一个正确的插件,因为常见的文件需要与.dll分开部署,但我并不是太烦恼。

然而,如果有人知道如何让虚拟文件为Razor工作,我会全力以赴。嗯 - 所有人的眼睛真的。