【问题标题】:Passing and persisting a connection string in WPF using MVVM pattern?使用 MVVM 模式在 WPF 中传递和持久化连接字符串?
【发布时间】:2023-03-31 00:14:01
【问题描述】:

我的应用程序需要能够存储来自登录模块的连接字符串,以供应用程序中的所有其他模块使用,其中大约有 50 个。我最初打算通过广播和订阅新的/更改的连接字符串事件来使连接字符串可用,但是由于 50 个模块中的大多数/全部是按需加载的,因此它们在登录过程中无法订阅该事件,因为它们是登录过程后加载。根据我的理解,我需要一种不同的方法来使连接字符串可用。

然后我考虑将连接字符串放在 shell 中并尝试将其公开给任何已加载的模块,但我找不到在不破坏 MVVM 模式和引入不需要的依赖项的情况下做到这一点的方法。

如果有人知道实现上述两个选项中的任何一个的方法,我很想知道它是否可以在遵循 MVVM 模式的同时完成。

我现在在想,最好的方法是将连接字符串的单例变体用作共享服务。我希望 Unity Container 能够存储连接字符串,并且我可以使用服务定位器在任何模块中访问它,但我不知道该怎么做。 MEF 和/或 Silverlight 中有任何性质相似的示例。 有没有人在 WPF 中做过这个,或者有一个如何编写连接字符串单例并将其添加到 Unity 容器的示例?指南、教程或一些代码 sn-ps 将不胜感激!

注意:我在后端使用 Prism 和 Unity、Oracle,应用程序将部署在 Citrix 服务器上(以安全的名义,他们阻止开发人员写入应用程序。 config) 这就是为什么我不能使用这种方法的原因。 当多个用户从 Citrix 运行应用程序时,使用 Singleton 作为连接字符串也会导致问题吗?每个用户都有自己的单例连接字符串吗?如果没有,那么我的整个问题就会改变,有没有一种好方法可以用来在我的所有模块之间传递/保持连接字符串?

【问题讨论】:

  • 有几种方法,但要看事件的先后顺序如何。你的依赖模块是和登录模块同时加载的,还是先加载登录模块,然后登录完成后再加载其他模块?
  • @Backlash 登录完成后加载依赖模块。首先是登录模块,然后是菜单模块,然后是任意数量的模块,具体取决于菜单选择。
  • 如果你采取这条路线,它开始变得有点“健谈”,但一种选择是让模块在加载时发送连接字符串的请求,然后登录模块将回复

标签: .net wpf mvvm connection-string unity-container


【解决方案1】:

要回答有关如何在 Unity 容器中注册连接字符串的问题,您应该能够使用以下 sn-ps 实现所需的结果。

存储连接字符串:

Container.RegisterInstance<string>("ConnectionString", theConnectionString);

检索连接字符串:

var connectionString = Container.Resolve<string>("ConnectionString");

正如我在上面的评论中提到的,另一种选择可能是创建一个请求和一个响应类型,您可以使用 EventAggregator 来回发送,让每个模块请求连接字符串并让登录模块回复。

var MyToken = Guid.NewGuid();

EventAggregator.GetEvent<ConnectionStringResponse>().Subscribe(r => {
    if(r.Token != MyToken)  // Make sure we're only handling responses to our request.
        return;

    ConnectionString = r.ConnectionString;
    // Kick off whatever other stuff you need to do once
    // you've gotten the connection string
    // Might also want to unsubscribe at this point unless you want
    // to go even further and handle changing connection strings.
});

EventAggregator.GetEvent<ConnectionStringRequest>().Publish(MyToken);

【讨论】:

  • 谢谢,您注册字符串的解决方案非常完美。我同意下面的答案,最干净的方法是为连接字符串构建一个接口和类,并将其注册到 Unity Container。但是现在你的方法是完美的。另外,您建议的事件方法在我听到时听起来很明显,我认为我需要在更改/设置连接字符串时广播事件,但是在加载需要连接字符串的新模块时广播事件效果更好.
  • 我同意在这里创建一个Type 来解决(类似于ConnectionStringProvider,甚至是一个接口)如果您想继续使用容器方法,将是更好的选择。或者至少通过使其成为所有模块都可用的字符串常量来使​​名称在某种程度上具有重构性。 (很像 RegionNames 的处理方式)
【解决方案2】:

如果您使用的是 Prism,我强烈建议 Unity Container 注册连接字符串并将 ctor-dependency 注入您拥有的各种 VM。

类似于,定义其他程序集/VM 可以使用它的合同,以及 LoginModule 中的实现:

class ConnectionInfo : IConnectionInfo 
{
    public GetConnectionString()
    {
      // you get the drift...!  
      // you should probably cache the result into a Lazy<T> impl. and just return
      // that value on future calls, to save the lookup of the config.
    }
}

在登录模块中注册:

container.RegisterType<IConnectionInfo, ConnectionInfo>(
  new ContainerControlledLifetimeManager());

然后在你的虚拟机的 ctor 中进行 DI 操作——此时它是无忧无虑的:

public MyViewModel(IConnectionInfo connectionInfo_)
{
  var connectionString = connectionInfo_.GetConnectionString();
}

如果我可以选择的话,我想我对这些情况的首选方法是更喜欢 IEventAggregator 之上的接口。它只是更容易处理诸如由于事件信号发生得太早而导致迟创建的 VM 没有接收 IEA 信号的情况。这将导致一些真正痛苦的技术债务积累。

【讨论】:

  • 这似乎是应用 MVVM、构建要注入每个视图模型的接口和连接字符串类的最干净的解决方案。而不是像上面的答案中建议的那样简单地注册字符串实例“连接字符串”。我将在未来转换为这个进行生产。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多