C# 如何在MVC项目外部重构数据库访问代码,但将viewmodels保留在内部?

C# 如何在MVC项目外部重构数据库访问代码,但将viewmodels保留在内部?,c#,asp.net-mvc,model-view-controller,refactoring,asp.net-mvc-viewmodel,C#,Asp.net Mvc,Model View Controller,Refactoring,Asp.net Mvc Viewmodel,我有一个asp.net-mvc网站,其中包含以下文件夹: 控制器 剧本 观点 视图模型 模型 域模型 我现在想在另一个.net应用程序(一个完全不是web的windows控制台应用程序)中访问大量的业务逻辑和数据库访问代码和数据,因此我正在重构,以尽可能多地删除MVC项目之外的内容,并将其放入解决方案中的其他项目中,以便与其他解决方案共享代码 我有两个主要问题 我的主要问题是,我正在努力找到一个地方来放置生成ViewModel的代码,因为在控制台应用程序发送电子邮件时,我希望在控制台应用程序

我有一个asp.net-mvc网站,其中包含以下文件夹:

  • 控制器
  • 剧本
  • 观点
  • 视图模型
  • 模型
  • 域模型
我现在想在另一个.net应用程序(一个完全不是web的windows控制台应用程序)中访问大量的业务逻辑和数据库访问代码和数据,因此我正在重构,以尽可能多地删除MVC项目之外的内容,并将其放入解决方案中的其他项目中,以便与其他解决方案共享代码

我有两个主要问题

  • 我的主要问题是,我正在努力找到一个地方来放置生成ViewModel的代码,因为在控制台应用程序发送电子邮件时,我希望在控制台应用程序中重用许多代码,因为控制台应用程序需要与视图中相同的数据

  • 另一个主要问题是,当我的许多实例化ViewModel的函数都是从一堆数据库访问代码开始时,我很难看到如何将数据库访问代码移出MVC项目,同时仍然将ViewModels放在里面

  • 以下是我到目前为止的一些细节和过程:

    步骤1-将DomainModel移动到另一个项目中-成功 因此,移动DomainModel项目很简单(因为这是许多原始对象,上面有一些业务逻辑,没有任何web内容)

    步骤2-精简控制器-成功 我已经尽可能精简了我的控制器,并将任何业务逻辑或复杂的数据访问逻辑移到Models文件夹中。当我试图将models文件夹移到MVC项目之外时,出现了一些问题:

    步骤3-尝试将模型文件夹移到MVC项目外部-挣扎 在细化控制器时,我有许多不同的控制器动作,这些动作转到模型类并返回我传递回视图的ViewModel。类似这样的内容(在我的控制器类中):

    因此,“模型”文件夹中的文件依赖于ViewModel类。我确实希望集中化GenerateAppDetailViewModel()函数,因为它在多个不同的控制器中使用。此外,在我的控制台应用程序(发送电子邮件)中,我通常希望获取某个视图上的所有数据,因此我的代码“希望”利用viewmodel。如果我将其移出MVC项目,则可以重用,但我认为存在依赖性问题(很明显,我的控制台应用程序中不需要SelectListItem,但在其他情况下,它们只是生成视图所需的不同数据的容器对象,我确实希望重用)

    或者另一件打破的事情是对以下方面的依赖:

    System.Web.Mvc
    
    因为我有很多代码:

  • 查询数据库中的表
  • 将其转换为对象集合(我使用的是nhibernate)
  • 将其转换为某些DTO对象(位于ViewModels文件夹中)或SelectListItem对象列表(用于填充视图中的下拉列表),这是System.web.mvc的一部分
  • 我想寻找关于打破这种依赖性的最佳方法的建议,这样我就可以将尽可能多的代码移出MVC项目,以便重用

    问题是,如果我试图将ViewModel代码吸入Model文件夹和另一个项目中,那么我会再次陷入困境,因为ViewModel类对

    System.Web.Mvc

    由于SelectListItem之类的原因

    我是否应该有两个视图模型文件夹(一个在MVC项目中,有特定的system.web.MVC引用,另一个在不同的项目中?)。似乎对SelectListItem的依赖性是导致争用的原因

    在我看到的大多数示例中,ViewModels确实依赖于System.Web.Mvc

    我看到了这些问题:


    它们有点相关,但不确定它们是否回答了我提出的具体整体重构问题。

    您可以使用扩展方法在controller中创建viewmodels:

    控制器:

     public ActionResult ApplicationDetail(int id)
     {
          var model = _serviceLayer.GetSomeModel(id); 
          var viewModel = model.CreateInstance(model);      
          return View(viewModel);
     }
    
    在mvc项目中创建此
    SomeModelExtensions

    public class SomeModelExtensions {
          public AppDetailViewModel CreateInstance(this SomeModel model) {
               var viewModel = new AppDetailViewModel();
               // here you create viewmodel object from model with logic
               return viewModel;
          }
    }
    

    视图模型是特定于特定应用程序的。我猜web应用程序和控制台应用程序之间的视图模型会有所不同。因此,请让每个应用程序定义自己的视图模型以及域模型和视图模型之间的对应映射。不要让域模型拥有将em用于查看模型,因为这样做会将域层完全绑定到UI层,这是最糟糕的情况。使用映射层(特定于每种应用程序类型)。这是映射层的一个很好的示例

    甚至不要尝试在控制台应用程序中重用ASP.NET MVC视图模型。正如您已经发现的那样,它们将包含对System.Web.MVC的引用,因为例如ASP.NET MVC中的dropDownList用
    IEnumerable
    类表示,而在控制台应用程序中,天知道,可能是
    IEnumerable


    结论:视图模型以及域和视图模型之间的来回映射属于UI层(也称为ASP.NET MVC、Console、WPF等)。

    我假设MVC web将使用与Console应用程序+额外字段相同的数据,对吗

    那么,如何从模型继承ViewModel呢?这样您就可以重用模型并根据需要在ViewModel上获取自定义字段

    public class AppDetailModel
        {
            public int ID { get; set; }
            public string Name { get; set; }
        }
    
    
        public class AppDetailViewModel : AppDetailModel
        {
            public string ViewProperty { get; set; }
        }
    

    通常,我在设计MVC应用程序时使用以下设置/架构,其中可能需要重用模型:

    MVC项目:所有与web相关的内容。我在这里定义ViewModels并将它们映射到域模型

    模型项目:包含所有域逻辑的类库

    存储库项目:这是一个类库,用于访问数据库和域模型

    它的工作方式是MVC项目将使用(希望是注入的)存储库库
    public class AppDetailModel
        {
            public int ID { get; set; }
            public string Name { get; set; }
        }
    
    
        public class AppDetailViewModel : AppDetailModel
        {
            public string ViewProperty { get; set; }
        }
    
        MVC App                      Console App
           |                            |
           |                            |
       MVC Specific Mapper         Console Specific Mapper
                     \               /  
                      \             /
                       \           /   
                       GenericMapper <- EmailMapper and EmailViewModel can be implemented here
                         |       |      
                         |       |
                    Repository   |
                         |       |
                         |       |
                        DomainModels