# DependencyInjectionHelperLib **Repository Path**: Richard_ji/dependency-injection-helper-lib ## Basic Information - **Project Name**: DependencyInjectionHelperLib - **Description**: 依赖Microsoft.Extensions.DependencyInjection,在使用DI容器的时候觉得手动注册很麻烦,所以写入一个特性用来实现注册的自动化。简单实现了一下用于切换viewmodel导航接口INavigationObjectProvider。DI容器直接使用单例模式,便于在任何需要使用的地方注册和解析服务。 - **Primary Language**: C# - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2024-06-23 - **Last Updated**: 2024-11-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # DependencyInjectionHelperLib #### 介绍 依赖 Microsoft.Extensions.DependencyInjection,在 WPF 设计 MVVM 模式的时候,使用 DI 容器的时候觉得手动注册很麻烦,所以写入一个特性用来实现注册的自动化。简单实现了一下用于切换 viewmodel 导航接口INavigationObjectProvider 。DI容器直接使用单例模式,便于在任何需要使用的地方注册和解析服务。 #### 软件架构 使用 .net 6.0 C# 类库,Visual Studio IDE 。 #### 安装教程 使用 .net 6.0 以上,引入类库就可以了。依赖 Microsoft.Extensions.DependencyInjection 。 #### 使用说明 1. DIRegistrationAttribute :类的特性,不可重复使用。属性分为生命周期、导航key、接口数组 ~~~C# [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class DIRegistrationAttribute : Attribute { public Lifetimes Lifetime { get; set; } public string PageKey { get; set; } public Type[] InterfaceTypes { get; set; } /// /// 将服务类注册到 IServiceCollection 容器中的特性 /// /// 注册的生命周期,默认值为单例模式 /// 用于导航的key值 /// 注册的服务接口 public DIRegistrationAttribute( Lifetimes lifetime = Lifetimes.Singleton, string pageKey = "", params Type[] interfaceTypes ) { Lifetime = lifetime; PageKey = pageKey; InterfaceTypes = interfaceTypes; } ~~~ 2. IServiceCollectionExtension :扩展方法 AutoRegisterServices() 实现 将特性标记的类自动注册到 ServiceCollection 中。 4. INavigationObjectProvider : 暴露接口用于ViewModel作为导航的参数类型。 定义以下方法: ~~~C# public interface INavigationObjectProvider { public T? GetNavigationObject(string key) where T : class; } ~~~ 5. NavigationObjectProvider :继承了接口 INavigationObjectProvider 的**内部类**,这个类不向外部暴露,这个类用于存储 DIRegistrationAttribute 中定义的导航对象的类型,并实现获取实例的方法。 6. 提供一个DI容器单例 DIContainer : - RegisterAndBuildServices(Action = null) 方法,实现自动或自定义的注册,并创建 ServiceProvider。这个方法中使用了 IServiceCollectionExtension 将标记了 DIRegistrationAttribute 特性的类自动注册到依赖容器中。同时在方法中使用 。 ~~~ c# // 注册接口 用户导航 private DIContainer() { _servicesCollection = new ServiceCollection(); _servicesCollection .AddSingleton(serviceProder => new NavigationObjectProvider(_servicesCollection, serviceProder)) .AutoRegisterServices(); } ~~~ - 提供 GetServiceProvider() 方法,获取容器的 ServiceProvider 用于解析,但前提是首先要使用 RegisterAndBuildServices() 进行注册。 ~~~c# /// /// 注册服务并构建服务提供者,所有的服务只能在同一处进行注册。 /// /// 可选的委托,用于注册额外的服务。 public void RegisterAndBuildServices(Action? Register = null) { Register?.Invoke(_servicesCollection); if (_serviceProvider == null) { _serviceProvider = _servicesCollection.BuildServiceProvider(); } } /// /// 获取服务提供者实例。 /// /// 服务提供者实例。 /// 如果服务提供者尚未构建,则引发此异常。 public IServiceProvider GetServiceProvider() { if (_serviceProvider == null) { throw new InvalidOperationException("Service provider has not been built yet. Call BuildServiceProvider first."); } return _serviceProvider; } } ~~~ #### 使用建议 - 建议使用 DIContainer 这个单例。可以在wpf的app.xaml.cs中使用: ~~~C# // 注册服务 DIContainer.Default.RegisterAndBuildServices( (s) => { s.AddSingleton(); // 其他 } ); ~~~ - 也可以在 ViewModelLocator 中直接使用: ~~~C# public ViewModelLocator() { DIContainer.Default.RegisterAndBuildServices(); } ~~~ - 获取 DIContainer 的 ServiceProvider 用于解析数据: ~~~C# IServiceProvider? services = DIContainer.Default.GetServiceProvider(); ~~~ - 使用 DIRegistrationAttribute 特性 ~~~C# [DIRegistration] //注册为Singleton。 [DIRegistration(lifetime:Lifetimes.Scoped] //注册为Scoped [DIRegistration(pageKey: "XXXX")] //注册为单例,并且这个类被存储在导航集合中。 ~~~ - 使用导航接口 ~~~C# [DIRegistration] public partial class MainWindowViewModel : ObservableRecipient, IRecipient { private INavigationObjectProvider? _navigationObjectProvider; private IDataService? _dataService; public MainWindowViewModel() { } public MainWindowViewModel(INavigationObjectProvider navigationObjectProvider, IDataService dataService) { _navigationObjectProvider = navigationObjectProvider; _dataService = dataService; IsActive = true; NavigationObject = _navigationObjectProvider.GetNavigationObject("key"); } public void Receive(NavigateRequestMessage message) => NavigationObject = message.ViewModel; [ObservableProperty] private object? _navigationObject; [RelayCommand] private void StopApp() => _dataService!.StopPeriodicRead(); } ~~~ #### 参与贡献