2009-09-23 97 views
1

在我的应用程序有不同的网页:联系我们,关于我们,首页ASP.NET MVC:填充派生的强类型视图与基强类型查看

他们都需要填充的观点相同的基本要素:

  • 页面标题
  • meta描述
  • 用户信息

但是在每一页上,他们有一些元素是不同的:

联系我们

  • 联系信息模型
  • 联系表型号

关于我们

  • 扩展用户信息模型

首页

  • 首页文本属性

他们都路由到同一个控制器的操作方法,因为大多数的功能比填充“额外”的信息类似的其他依赖页面类型。

到目前为止,我已经做了一些,其中:

PageDetailViewData pageDetailViewData = new PageDetailViewData {Title = title, Desc = desc....} 

并且在这之后,我有:

   switch ((PageType)page.PageType) 
      { 
       case (PageType.Contact): 
        return View("ContactUsDetails", pageDetailViewData); 
       default: 
        return View(pageDetailViewData); 
      } 

的问题是,我该如何填写“额外”的信息?我不确定我是否正在以正确的方式做这件事。任何洞察,以更好地构建逻辑流程将不胜感激。

回答

3

使用接口暗示您的视图模型之间有一些共同点的答案肯定会有助于回答您的问题中的一些观点。

然而,我会问,“重构”你的行动是多么明智,以支持不同数据结构的多个视图。

MVC控制器操作通常代表收集生成预期视图所需的特定数据所需的最少代码量。单个动作返回同一模型数据的不同视图(例如Html视图或Mobile视图)并不罕见,但通过改变数据结构和视图会产生一些问题。

特别是,您违反了常见的最佳实践,如Single Responsibility Principle,并使您的代码更加复杂以进行测试 - 无痛测试和TDD是ASP.Net MVC的重大胜利的一部分。

就我个人而言,我会有一个单独的行动。

就你的视图模型而言,如果这是一个数据库,你会怎么做? 你会分开查询单独的数据权利?

用户的个人资料信息将与页面元数据信息分开查询。这可能是由于许多原因造成的,这些原因可能包括高速缓存数据的某些部分而不是其他数据。

因此,与上述建议,你的代码可能是这样的(注意:此代码不能在Visual Studio编写,是完全可能的语法问题):

public interface IMetaDataViewModel 
{ 
    PageMetaData MetaData{get; set;} 
} 
public class HomeViewModel : IMetaDataViewModel 
{ 
    public PageMetaData MetaData{get; set;} 
    public string HomePageText{get; set;} 
} 
//other view models go here.... 

public class CommonPagesController : Controller 
{ 
    private MetaDataProvider _metaProvider = new MetaDataProvider(); 
    private PageDataProvider _pageDataProvider = new PageDataProvider(); 
    private ContactDataProvider _contactDataProvider = new ContactDataProvider(); 

    public ActionResult Home() 
    { 
     var viewModel = new HomeViewModel 
     { 
      MetaData = _metaProvider.GetPageMeta(); 
      HomePageText = _pageDataProvider.GetPageData(); 
     }; 
     return View(viewModel); 
    } 
    public ActionResult Contact() 
    { 
     var viewModel = new ContactViewModel 
     { 
      MetaData = _metaProvider.GetPageMeta(); 
      ContactFormData = _contactDataProvider.GetData(); 
     }; 
     return View(viewModel); 
    } 
    //you get the picture... 
} 

有几种方法,你也可以重构视图模型代码的生成,但这是一种可能的模式。

我明白,这个答案确实有一定的意见,但我会考虑分开行动是最好的做法。

希望有所帮助。

+0

感谢您的详细回复。所有路由到同一个Action Handler的原因是因为传入的“Action”是动态的,并且只有在查询数据库时才确定页面类型。例如:site.com/ABC site.com/contact-ABC ...我只知道依赖于域之后的密钥取决于哪个视图。 – TimLeung 2009-09-24 03:24:18

+0

也许您需要的抽象不在控制器级别,但可能在Controller Factory级别? 如果你想坚持强类型的视图路线(通常是一件好事),那么你将不得不编写自定义代码来填充每个视图模型。 听起来你正在编写一个CMS风格的应用程序。这可能是我一次积极辩论强类型观点的优点的时候。我还没有看到......但值得考虑。 – 2009-09-24 08:37:28

1

问题的标题几乎给你答案。你可以使用某种形式的多态来实现这一点。可以定义一个基类与所述共享属性,或者可替换地是这样的接口:

public interface ICommonPage 
{ 
    string Title { get; } 
    string MetaDescription { get; } 
    string UserInformation { get; } 
} 

然后定义三个强类型视图模型类,所有实现这个接口(或从基类派生):

  • ContactUsViewModel:ICommonPage
  • AboutUsViewModel:ICommonPage
  • HomeViewModel:ICommonPage

在这些ViewModel类的每一个上,都添加了这些视图所需的额外属性。

在您的Controller Action中,您需要打开PageType以选择正确的ViewModel并使用数据填充它。

您还需要为每个ViewModel类创建三个不同的视图(.aspx)。

如果您已经共享通用数据的渲染,那么可以将其提取到键入ICommonPage的强类型UserControl(.ascx)中。

+0

实例化派生视图模型的最佳方法是什么?填充基本信息的最佳方式是什么?我应该将人口抽象为一种方法吗? – TimLeung 2009-09-23 13:03:05

+0

一般来说,如果您可以保持ViewModel被动,并使其成为Controller(或另一个类)填充数据的责任,那么最好。这也是您需要选择正确的ViewModel类型的地方。 – 2009-09-23 13:30:37