如何避免在使用MVVM的.NET中使用大量dbcontexts?

时间:2018-05-23 16:56:49

标签: c# mvvm asp.net-core razor-pages

我尝试使用MVVM模式学习在.NET中构建Web应用程序。我看过一些教程,有一件事我不明白。

每个ViewModel都包含:

public class IndexModel : PageModel
{
    private readonly ApplicationDbContext _dbContext;

    public IndexModel(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    ..
}

当你有几页(最多10个)时,复制粘贴这个很好,但我的应用程序开始增长,并且使用这种方法开始感觉非常多余。

我无法找到另一篇回答我的问题的帖子,但我想知道是否还有其他方法可以在每个ViewModel上使用_dbContext而无需使用此冗余?我对设计模式不太熟悉,但是我的启动中的单例模式是一个选项吗?

2 个答案:

答案 0 :(得分:2)

添加从PageModel继承的自定义基类。然后从您的自定义基类继承您的所有模型。

public abstract class MyBasePageModel : PageModel
{
   protected readonly ApplicationDbContext _dbContext;
   public MyBaseModel(ApplicationDbContext dbContext)
   {
      _dbContext = dbContext;
   }
}


public class IndexModel : MyBasePageModel 
{
    public IndexModel(ApplicationDbContext dbContext):base(dbContext)
    {
      // 
    }
}

答案 1 :(得分:2)

这不是声音设计模式。您可以做的是使用依赖注入(Unity示例)将业务接口作为注入依赖项传递给您的viewmodel。然后,注入的业务服务可以向其中注入一个数据服务接口,在该接口中可以找到数据上下文。

在您的表示层中使用数据层被认为是不好的做法。以下是如何分离代码层的示例方法。

下面是IDataService的简单示例(注意我只处理接口,数据上下文保留在数据服务中):

public class DataService : ServiceBase, IDataService
{
    public DataService(IMapper mapper) : base(mapper) { }

    public IList<UserDto> GetUsers(bool runSafeMode = true)
    {
        Func<IList<UserDto>> action = () =>
        {
            return GetUsers(_ => true);
        };

        return ExecutorHandler(action, runSafeMode);
    }

    ...

    private IList<UserDto> GetUsers(Expression<Func<User, bool>> predicate, bool runSafeMode = true)
    {
        Func<IList<UserDto>> action = () =>
        {
            using (var ymse = YMSEntities.Create())
            {
                var users = ymse.User
                    .Include(u => u.UserUserProfile)
                    .Include(m => m.UserUserProfile.Select(uup => uup.UserProfile))
                    .Include(m => m.UserUserProfile.Select(uup => uup.User))
                    .Include(m => m.UserUserProfile.Select(uup => uup.UserProfile.UserProfileModule))
                    .Where(predicate).OrderBy(u => u.UserName).ToList();

                return MappingEngine.Map<IList<UserDto>>(users);
            }
        };

        return ExecutorHandler(action, runSafeMode);
    }
}

它被注入到业务服务中,而业务服务又注入到我的VM中:

public class DocksViewModel : ViewModelBase
{
    public DocksViewModel(IConfigService configService, IEventService eventService, INotificationService notificationService)
    {
        ...
    }
}

关注点和一切事物的简单分离是可独立测试的。在这种情况下我的IDataService可以在BaseViewModel中找到,因为我的应用程序是否具有Internet连接,我在sql server和本地json文件之间切换实现以获得数据持久性。以下是使用Unity连接依赖关系的方法,例如:

        var unityContainer = new UnityContainer();

        ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(unityContainer));

        unityContainer.RegisterType<IServiceLocator, UnityServiceLocator>(new ContainerControlledLifetimeManager());

        // automapper
        var config = new MapperConfiguration(cfg =>
           cfg.AddProfile(new AutoMapperBootstrap())
       );

        unityContainer.RegisterType<IMapper>(new InjectionFactory(_ => config.CreateMapper()));

        // factories
        unityContainer.RegisterType<IWelcomeGateViewFactory, WelcomeGateViewFactory>();
        unityContainer.RegisterType<ITrailerPictureViewFactory, TrailerPictureViewFactory>();

        // services
        unityContainer.RegisterType<IDataService, OfflineDataService>("OfflineDataService", new ContainerControlledLifetimeManager(), new InjectionConstructor(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), ServiceLocator.Current.GetInstance<IMapper>()));
        unityContainer.RegisterType<IDataService, DataService>(new ContainerControlledLifetimeManager());
        unityContainer.RegisterType<ITestDataService, TestDataService>(new ContainerControlledLifetimeManager()); 

        ...