# 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();
}
~~~
#### 参与贡献