MVVM Light中能否在app.config注册服务?WPF应用编译痛点求助
在MVVM Light中通过app.config注册服务的解决方案
好问题!MVVM Light的SimpleIoc本身确实没有直接支持从app.config注册服务的内置功能,但我们可以自己动手实现这个逻辑,这样以后修改服务注册就不需要重新编译应用了。下面是具体的实现步骤:
1. 在app.config中添加自定义服务注册配置
首先,我们需要在配置文件中定义专门的节点来存储服务与实现类的映射关系。先添加配置节声明,再添加具体的服务注册项:
<configuration> <!-- 声明自定义配置节 --> <configSections> <section name="serviceRegistrations" type="YourAppNamespace.ServiceRegistrationSection, YourAppAssembly" /> </configSections> <!-- 服务注册配置 --> <serviceRegistrations> <services> <!-- 格式:serviceType是接口/抽象类的完整类型名(含程序集),implementationType是实现类的完整类型名 --> <add serviceType="YourAppNamespace.IMyDataService, YourApp" implementationType="YourAppNamespace.MyDataServiceImpl, YourApp" /> <add serviceType="YourAppNamespace.ILoggerService, YourApp" implementationType="YourAppNamespace.FileLoggerServiceImpl, YourApp" /> </services> </serviceRegistrations> </configuration>
2. 创建配置节解析类
接下来需要编写C#类来解析上面的自定义配置节点,让.NET能正确读取配置内容:
using System.Configuration; namespace YourAppNamespace { // 对应serviceRegistrations根节点 public class ServiceRegistrationSection : ConfigurationSection { [ConfigurationProperty("services", IsDefaultCollection = false)] [ConfigurationCollection(typeof(ServiceElementCollection), AddItemName = "add")] public ServiceElementCollection Services { get => (ServiceElementCollection)base["services"]; set => base["services"] = value; } } // 对应services节点下的add集合 public class ServiceElementCollection : ConfigurationElementCollection { protected override ConfigurationElement CreateNewElement() { return new ServiceElement(); } protected override object GetElementKey(ConfigurationElement element) { return ((ServiceElement)element).ServiceType; } } // 对应单个add节点 public class ServiceElement : ConfigurationElement { [ConfigurationProperty("serviceType", IsRequired = true)] public string ServiceType { get => (string)base["serviceType"]; set => base["serviceType"] = value; } [ConfigurationProperty("implementationType", IsRequired = true)] public string ImplementationType { get => (string)base["implementationType"]; set => base["implementationType"] = value; } // 可选:添加singleton属性控制是否单例注册 [ConfigurationProperty("singleton", DefaultValue = false, IsRequired = false)] public bool IsSingleton { get => (bool)base["singleton"]; set => base["singleton"] = value; } } }
3. 修改ViewModelLocator读取配置并注册服务
最后,我们需要在ViewModelLocator中添加逻辑,读取配置文件中的服务注册信息,通过反射获取类型后注册到SimpleIoc中:
using GalaSoft.MvvmLight.Ioc; using System.Configuration; using System; namespace YourAppNamespace { public class ViewModelLocator { static ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); // 从app.config加载服务注册 LoadServicesFromConfig(); // 注册你的ViewModels SimpleIoc.Default.Register<MainViewModel>(); } private static void LoadServicesFromConfig() { var configSection = ConfigurationManager.GetSection("serviceRegistrations") as ServiceRegistrationSection; if (configSection == null) { // 如果配置节不存在,可以输出警告或者直接返回 return; } foreach (ServiceElement serviceElement in configSection.Services) { // 解析服务类型和实现类型 var serviceType = Type.GetType(serviceElement.ServiceType); var implementationType = Type.GetType(serviceElement.ImplementationType); if (serviceType == null || implementationType == null) { // 类型解析失败,建议记录日志 continue; } // 根据singleton属性决定注册方式 if (serviceElement.IsSingleton) { SimpleIoc.Default.RegisterAsSingleton(serviceType, implementationType); } else { SimpleIoc.Default.Register(serviceType, implementationType); } } } public MainViewModel Main => ServiceLocator.Current.GetInstance<MainViewModel>(); } }
关键注意事项
- 确保类型名称是完整的程序集限定名:格式为
命名空间.类型名, 程序集名称,比如YourAppNamespace.IMyService, YourApp,这样.NET才能正确找到对应的类型。 - 修改app.config后不需要重新编译,只要重启应用就能生效,完美解决你遇到的每次改代码都要重新编译的问题。
- 如果需要支持更多配置项(比如构造函数参数),可以扩展ServiceElement类添加对应的属性,然后在注册时通过反射处理构造函数注入。
内容的提问来源于stack exchange,提问作者Rajon Tanducar
相关产品推荐
相关产品推荐

