“无法解析服务的所有参数:(?)”当我尝试在 Angular 10 中使用库中的服务时
Posted
技术标签:
【中文标题】“无法解析服务的所有参数:(?)”当我尝试在 Angular 10 中使用库中的服务时【英文标题】:"Can't resolve all parameters for service: (?)" when I try to use service from library in Angular 10 【发布时间】:2021-01-31 02:32:34 【问题描述】:在我的图书馆中,我有一个使用此代码的服务:
import Inject, Injectable from '@angular/core';
import HttpClient from '@angular/common/http';
import DataInjectorModule from '../../data-injector.module';
// @dynamic
@Injectable()
export class RemoteDataService<T>
@Inject('env') private environment: any = ;
public type: new () => T;
constructor(
model: T,
)
this.http = DataInjectorModule.InjectorInstance.get(HttpClient);
// ...
data-injector.module
(存在的原因只是避免循环依赖):
import NgModule, Injector from '@angular/core';
// @dynamic
@NgModule(
declarations: [],
imports: [],
providers: [],
exports: [],
)
export class DataInjectorModule
static InjectorInstance: Injector;
constructor(injector: Injector)
DataInjectorModule.InjectorInstance = injector;
在我的库的主模块文件中:
import ModuleWithProviders from '@angular/compiler/src/core';
import NgModule, Injector from '@angular/core';
import DataInjectorModule from './data-injector.module';
import RemoteDataService from './services/remote-data/remote-data.service';
// @dynamic
@NgModule(
declarations: [],
imports: [
DataInjectorModule,
],
providers: [],
exports: [],
)
export class DataCoreModule
static InjectorInstance: Injector;
constructor(injector: Injector)
DataCoreModule.InjectorInstance = injector;
public static forRoot(environment: any): ModuleWithProviders
return
ngModule: DataCoreModule,
providers: [
RemoteDataService,
provide: 'env', useValue: environment
]
;
终于在我的应用程序的app.module.ts
:
import BrowserModule from '@angular/platform-browser';
import NgModule from '@angular/core';
import DataCoreModule from 'data-core';
import AppRoutingModule from './app-routing.module';
import environment from 'src/environments/environment';
import AppComponent from './app.component';
@NgModule(
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
DdataCoreModule.forRoot(environment),
],
providers: [],
bootstrap: [AppComponent]
)
export class AppModule
构建顺利,但在浏览器中出现此错误:
Error: Can't resolve all parameters for RemoteDataService: (?).
at getUndecoratedInjectableFactory (core.js:11338)
at injectableDefOrInjectorDefFactory (core.js:11328)
at providerToFactory (core.js:11371)
at providerToRecord (core.js:11358)
at R3Injector.processProvider (core.js:11256)
at core.js:11230
at core.js:1146
at Array.forEach (<anonymous>)
at deepForEach (core.js:1146)
at R3Injector.processInjectorType (core.js:11230)
我在 *** 中检查了有关此主题的几个问题,例如 this,但几乎所有地方都缺少 @Injectable()
,但在这种情况下,我使用了这个装饰器。
知道如何解决这个问题吗?
【问题讨论】:
这看起来太复杂了,我相信你可以简单地使用导入的environment
变量而不必注入它。将providedIn
属性添加到@Injectable
装饰器也比添加提供程序数组更容易。如果环境变量来自远程源,那么只需将其保存为 observable 就足够了
“使用导入的环境变量而不必注入它”部分我认为它在库中不起作用。或者它是?该库可从 npm 安装。
库中的 model: T
构造函数参数 RemoteDataService
有什么作用?
@Akash 在这个例子中它什么都不做,好点。但我仍然认为这是一个重要的细节,因为一些建议的解决方案将获取环境值作为构造函数参数,我不想这样做。
我猜问题出在你的构造函数参数上。 Angular DI 需要知道您要在服务的构造函数中注入的实例。
【参考方案1】:
错误:无法解析 RemoteDataService 的所有参数:(?)
错误说明了一切。 Angular 无法解析 RemoteDataService 中的所有构造函数参数。实例化此服务时,它需要所需的参数。
您可以通过InjectionToken提供所需的依赖项,详情请参阅this答案。
但是您的服务使用generics
,并且您没有提及如何在组件中使用此服务,因此我建议您在组件中声明提供程序(或模块也可以)并使用@Inject()
在您的组件中注入此服务的不同版本,如下所示(结帐this StackBlitz 并查看控制台以获取来自服务构造函数的日志)-
import Component, Inject from "@angular/core";
import RemoteDataService from "./custom/remote-data.service";
export class A
export class B
@Component(
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
providers: [
provide: "env", useValue: ,
provide: "ARemoteDataService",
useFactory: () => new RemoteDataService<A>(new A())
,
provide: "BRemoteDataService",
useFactory: () => new RemoteDataService<B>(new B())
]
)
export class AppComponent
constructor(
@Inject("ARemoteDataService")
private aRemoteDataService: RemoteDataService<A>,
@Inject("BRemoteDataService")
private bRemoteDataService: RemoteDataService<B>
)
另外,不确定您是否可以在构造函数之外使用@Inject()
。但是您始终可以使用注入器来获取其他依赖项(在您的情况下为env
)-
// @Inject('env') private environment: any = ;
constructor(model: T)
this.environment = DataInjectorModule.InjectorInstance.get("env");
【讨论】:
【参考方案2】:我找到了解决方案(实际上是一种解决方法)。我认为这不是一种优雅的方式,但它很有效。
我创建了一个EnvService
类,它可以从模块中获取environment
参数,并且对构造函数属性没有副作用:
import Inject, Injectable from '@angular/core';
@Injectable(
providedIn: 'root',
)
export class EnvService
public environment: any = ;
constructor(@Inject('env') private env?: any)
this.environment = env ?? ;
然后在我的库的主模块文件中设置EnvService
而不是RemoteDataService
:
import ModuleWithProviders from '@angular/compiler/src/core';
import NgModule, Injector from '@angular/core';
import DataInjectorModule from './data-injector.module';
import EnvService from './services/env/env.service';
// @dynamic
@NgModule(
declarations: [],
imports: [
DataInjectorModule,
],
providers: [],
exports: [],
)
export class DataCoreModule
static InjectorInstance: Injector;
constructor(injector: Injector)
DataCoreModule.InjectorInstance = injector;
public static forRoot(environment: any): ModuleWithProviders
return
ngModule: DataCoreModule,
providers: [
EnvService,
provide: 'env', useValue: environment
]
;
最后在我的RemoteDataService
中将@Inject
解决方案更改为InjectorInstance.get(EnvService)
解决方案:
import Injectable from '@angular/core';
import HttpClient from '@angular/common/http';
import DataInjectorModule from '../../data-injector.module';
import EnvService from '../env/env.service';
// @dynamic
@Injectable()
export class RemoteDataService<T>
private env = DdataInjectorModule.InjectorInstance.get(EnvService);
public type: new () => T;
constructor(
model: T,
)
this.http = DataInjectorModule.InjectorInstance.get(HttpClient);
// ...
所以RemoteDataService
的constructor
属性保持不变,但服务可以通过EnvService
访问环境变量。
【讨论】:
【参考方案3】:在大多数情况下,Angular DI 是在 constructor
中完成的。正如你已经编写了这样的构造函数
constructor(
model: T,
)
Angular 认为您正在尝试注入 T
。你应该在构造函数中注入你想要的所有东西
constructor( @Inject('env') private environment)
但请确保正确提供了 env。出于这个原因,甚至更好地使用InjectionToken
s
【讨论】:
model
变量用于RemoteDataSerivce
的函数中。它不能从构造函数属性中删除。而另一方面RemoteDataService在其他服务中使用,在其他服务中使用什么等等......所以我不想添加另一个构造函数属性,因为它涉及到使用该库的整个应用程序的升级。
服务实例应该通过角度依赖注入创建,而不是自定义代码以上是关于“无法解析服务的所有参数:(?)”当我尝试在 Angular 10 中使用库中的服务时的主要内容,如果未能解决你的问题,请参考以下文章
当我尝试在 ace.js 中创建 Range 对象时,抛出“Illegal Constructor”错误
kotlin.NotImplementedError: An operation is not implemented: not implemented AlertDialog
android项目它得到一些与ANDROID_SDK_HOME相关的错误
MemoryError: Unable to allocate 115. GiB for an array with shape (1122, 1122, 12288) and data type f