搬运自OpenMod官网,经过翻译,可能有些不足,欢迎指正!原文链接
服务和依赖注入
OpenMod与其他基于.NET的现代框架一样,使用依赖注入模式。本指南旨在简化它,并解释它对使用OpenMod的插件开发人员意味着什么。
插件、命令、事件监听器和服务可以自动获取对插件或OpenMod提供的任何其他服务的引用,只需将它们的接口添加到构造函数中。请参见下面的示例。
依赖注入示例
让我们看看这个活动:
这就是你的插件通常的样子:
public class MyPlugin(IServiceProvider serviceProvider) : base(serviceProvider) { }
如果您想访问IStringLocalizer服务,您可以这样做:
public class MyPlugin(IStringLocalizer stringLocalizer, IServiceProvider serviceProvider) : base(serviceProvider) { // 用stringLocalizer做些什么 }
假设您希望通过命令访问插件实例和配置。以下是您的方法:
private readonly IConfiguration m_Configuration; private readonly MyPlugin m_MyPlugin; public EchoCommand( IServiceProvider serviceProvider, MyPlugin myPlugin, IConfiguration configuration) : base(serviceProvider) m_MyPlugin = myPlugin; m_Configuration = configuration; }
注册您自己的服务
注册服务有两种方法:
使用接口的[Service]属性和具体类的[PluginServiceImplementation]进行注册。
通过实现IServiceConfigurator或IContainerConfigurator接口手动注册。当配置IoC容器时,实现这些接口的类将自动实例化,并可用于直接配置容器。
您可以实现IDisposable或IAsyncDisposable接口,以便在OpenMod或插件卸载时清理资源。
以下是清理车辆的示例服务:
[Service] public interface IVehicleClearingService { Task ClearVehiclesAsync(); } [PluginServiceImplementation(Lifetime = ServiceLifetime.Transient)] public class VehicleClearingService : IVehicleClearingService, IAsyncDisposable { private readonly IStringLocalizer m_StringLocalizer; private readonly ILogger<VehicleClearingService> m_Logger; public VehicleClearingService( ILogger<VehicleClearingService> logger, IPluginAccessor<VehicleClearerPlugin> pluginAccessor) { VehicleClearerPlugin plugin = pluginAccessor.Instance; // 服务位于全局OpenMod作用域中,该作用域不提供IStringLocalizer。 // 因为IStringLocalizer不在这个范围内,所以我们必须使用plugins范围。 m_StringLocalizer = plugin.Lifetime.Resolve<IStringLocalizer>(); m_Logger = logger; } public async Task ClearVehiclesAsync() { m_Logger.LogInformation(m_StringLocalizer["messages:clearing_vehicles"]); // 翻译是从plugins translation中读取的 // 调用游戏API清除车辆... } // 在OpenMod重载或服务器关闭时调用服务dispose方法 public async ValueTask DisposeAsync() { await ClearVehiclesAsync(); // 确保车辆在重新装载或关闭时被清除 } }
现在,您可以通过在命令、事件侦听器、插件类或其他服务中注入IVehicleClearingService来访问此服务。
服务期限
您可能已经注意到,VehicleClearningService的生存期设置为Lifetime = ServiceLifetime.Transient。
以下生存期可用:
Transient-每次解析时都会重新创建服务。此服务的每个解析和注入都将有一个唯一的实例。这是默认的生存期。
Scoped-服务将在同一命令或事件中共享同一实例。
Singleton-服务将只有一个实例的生存期与OpenMod IoC容器的生命周期相同(直到OpenMod重新加载或服务器关闭)。
避免使用单例服务。如果您的服务具有暂时的或作用域的依赖关系,这可能会导致问题。
服务范围
服务可以有两个作用域:插件作用域和全局作用域。
插件作用域服务仅在定义插件本身中使用,其他插件无法访问。它们也不能覆盖OpenMod本身或其他插件的全局范围服务。插件作用域服务是使用[PluginServiceImplementation]属性实现的。插件作用域服务是在加载插件时构造的,在关闭插件时释放。
全局作用域服务用于所有插件和OpenMod本身。全局作用域服务是使用[ServiceImplementation]属性实现的。如果您想为每个人替换例如IStringLocalizer,您需要在全局范围内实现它。全局作用域服务在OpenMod重新加载或服务器关闭时被释放。全局作用域服务是在OpenMod加载并被释放和OpenMod关闭时构建的。
在实现全局范围服务时避免依赖于插件。仅创建对其他全局范围服务的依赖关系。由于全局范围服务的生存期与插件不同,因此不能注入插件实例。一种解决方法是注入Lazy<IPluginAccessor<YourPlugin>>并稍后解析。请记住,即使您的插件无法加载或卸载,您的全局范围服务仍将保持活动状态。
内置的OpenMod服务
服务 | 说明 |
---|---|
IConfiguration | 提供配置文件中的值 |
ICommandContextBuilder | 生成命令上下文 |
ICommandExecutor | 执行命令 |
ICommandStore | 提供命令注册 |
ICommandPermissionBuilder | 定义命令的权限 |
ICommandParameterResolver | 从字符串分析命令参数 |
ICurrentCommandContextAccessor | 访问当前命令上下文 |
IDataStore | 序列化和反序列化持久数据 |
IDataStoreFactory | 创建数据存储 |
IEventBus | 订阅事件并发出它们 |
IJobSchgeduler | 任务和管理作业 |
ILogger<T> | 为T类提供日志记录 |
ILoggerFactory | 创建者记录器 |
IOpenModStringLocalizer | 本地化来自OpenMod自己的翻译文件的消息 |
IOpenModDataStoreAccessor | 访问OpenMod自己的数据存储 |
IOpenModHost | OpenMod主机平台抽象 |
IPermissionChecker | 检查权限 |
IPermissionRoleStore | 存储权限角色 |
IPermissionRegistry | 注册和存储权限 |
IPluginAccessor<TPlugin> | 访问插件实例 |
IPluginActivator | 加载并激活插件 |
IRuntime | 创建并托管OpenMod运行时 |
IStringLocalizer | 本地化来自插件翻译文件的消息 |
IUserDataSeeder | 在第一次连接时种子用户数据 |
IUserDataStore | 存储和管理用户数据 |
IUserManager | 保姆用户 |