使用不同的 InjectionConstructor 参数在注入的依赖项中注入依赖项
Inject dependency in injected dependency with different InjectionConstructor parameters
我正在使用一个有用的 RestClient,它处理对其他 Web 服务的 Rest 调用。这个 RestClient 是更大的服务客户端的一部分,它通过提供业务逻辑等使用的便利方法来处理不同的 Web 服务。
我正在使用 UnityContainers 进行依赖注入。
我有某种 RestClient:
public interface IRestClient
{
T PostSomething<T>();
}
public class RestClient : IRestClient
{
public RestClient(string baseUrl) { }
public T PostSomething<T>() { /* post something */ }
}
我在多个 ServiceClient 中使用:
public interface IServiceClient1
{
void Work1();
}
public class ServiceClient1 : IServiceClient1
{
private RestClient client;
private string myRestUrl = "ServiceUrl1";
public ServiceClient1(IRestClient client)
{
this.client = client;
client.SetUrl(myRestUrl); // i don't want to do this here. This should be done by unity when RestClient is instantiated
}
public void Work1()
{
/* do something */
client.PostSomething<string>();
}
}
public interface IServiceClient2
{
void Work2();
}
public class ServiceClient2 : IServiceClient2
{
private RestClient client;
private string myRestUrl = "ServiceUrl2";
public ServiceClient2(IRestClient client)
{
this.client = client;
client.SetUrl(myRestUrl); // i don't want to do this here. This should be done by unity when RestClient is instantiated
}
public void Work2()
{
/* do something */
client.PostSomething<string>();
}
}
现在我想用 UnityContainers 注入那些 类:
container.RegisterType<IServiceClient1, ServiceClient1 >();
container.RegisterType<IServiceClient2, ServiceClient2 >();
// And here comes the problem:
container.RegisterType<IRestClient, RestClient>(new InjectionConstructor("ThisParameterShouldBeSetByServiceClient"));
两者 ServiceClients
如本例所示有更多不同。此示例可能仅显示问题。
我想注册类型 RestClient
并且我希望 ServiceClientX
为 RestClient
的构造函数选择字符串参数。而且我不想在 ServiceClient
.
的构造函数中设置 Url
如何使用 UnityContainers
实现此目的?
你必须为此使用工厂。如果 ServiceClient 决定如何创建 RestClient:
public class ServiceClient1 : IServiceClient1
{
private RestClient client;
private string myRestUrl = "ServiceUrl1";
public ServiceClient1(IRestClientFactory clientFactory)
{
this.client = clientFactory.CreateClient(myRestUrl);
}
public void Work1()
{
/* do something */
}
}
Unity 注入工厂而不是 RestClient。
如果应模拟 RestClient,则应将工厂切换为模拟工厂。
除了你自己想出来的,还有一个办法就是在解析的时候用ParameterOverride
container.RegisterType<IRestClient, RestClient>(url1, new ParameterOverride(url1));
IRestClient restClient1 = container.Resolve<IRestClient>(url1);
container.RegisterType<IServiceClient1, ServiceClient1>();
IServiceClient1 svcClient = container.Resolve<IServiceClient1>(
new ParameterOverride("client", restClient1)
);
恕我直言,您将 "inject dependencies" 与 "inject parameters" 混合在一起。如果您的代码是新的,那么这是一个不太理想的设计。
对于新代码,您应该(恕我直言)注入依赖项。
..
现在,你是如何处理你的需求的?
有办法。
将 IConfigurationRetriever 注入您的 ServiceClient1 和 ServiceClient2。
public ServiceClient1 (IRestClient client, IConfigurationRetriever icr)
现在您可以创建一个简单的实现
public interface IConfigurationRetriever()
{
string GetSomeMagicValueOne();
}
public InMemoryConfigurationRetriever : IConfigurationRetriever
{
public string GetSomeMagicValueOne(){ return "HardCodedUrl"; }
}
您不应该将 URL 硬编码到对象中。但至少在上述情况下,您完成硬编码的方式仍然使您的 ServiceClient1 和 ServiceClient2 在未来保持灵活性。
以及如何,当您想创建一种不同的方式来读取配置时,您可以编写 "FromAppOrWebConfigConfigurationRetriever : IConfigurationRetriever" 或 "FromDotNetCoreJsonFileConfigurationRetriever : IConfigurationRetriever" 或 "FromTheDatabaseConfigurationRetriever : IConfigurationRetriever"
恕我直言,InjectionConstructor 用于处理 "old code" 在构造函数中具有参数的变通方法。并且 InjectionConstructor 不应该被设计成新的代码。再次,恕我直言。
我正在使用一个有用的 RestClient,它处理对其他 Web 服务的 Rest 调用。这个 RestClient 是更大的服务客户端的一部分,它通过提供业务逻辑等使用的便利方法来处理不同的 Web 服务。 我正在使用 UnityContainers 进行依赖注入。
我有某种 RestClient:
public interface IRestClient
{
T PostSomething<T>();
}
public class RestClient : IRestClient
{
public RestClient(string baseUrl) { }
public T PostSomething<T>() { /* post something */ }
}
我在多个 ServiceClient 中使用:
public interface IServiceClient1
{
void Work1();
}
public class ServiceClient1 : IServiceClient1
{
private RestClient client;
private string myRestUrl = "ServiceUrl1";
public ServiceClient1(IRestClient client)
{
this.client = client;
client.SetUrl(myRestUrl); // i don't want to do this here. This should be done by unity when RestClient is instantiated
}
public void Work1()
{
/* do something */
client.PostSomething<string>();
}
}
public interface IServiceClient2
{
void Work2();
}
public class ServiceClient2 : IServiceClient2
{
private RestClient client;
private string myRestUrl = "ServiceUrl2";
public ServiceClient2(IRestClient client)
{
this.client = client;
client.SetUrl(myRestUrl); // i don't want to do this here. This should be done by unity when RestClient is instantiated
}
public void Work2()
{
/* do something */
client.PostSomething<string>();
}
}
现在我想用 UnityContainers 注入那些 类:
container.RegisterType<IServiceClient1, ServiceClient1 >();
container.RegisterType<IServiceClient2, ServiceClient2 >();
// And here comes the problem:
container.RegisterType<IRestClient, RestClient>(new InjectionConstructor("ThisParameterShouldBeSetByServiceClient"));
两者 ServiceClients
如本例所示有更多不同。此示例可能仅显示问题。
我想注册类型 RestClient
并且我希望 ServiceClientX
为 RestClient
的构造函数选择字符串参数。而且我不想在 ServiceClient
.
如何使用 UnityContainers
实现此目的?
你必须为此使用工厂。如果 ServiceClient 决定如何创建 RestClient:
public class ServiceClient1 : IServiceClient1
{
private RestClient client;
private string myRestUrl = "ServiceUrl1";
public ServiceClient1(IRestClientFactory clientFactory)
{
this.client = clientFactory.CreateClient(myRestUrl);
}
public void Work1()
{
/* do something */
}
}
Unity 注入工厂而不是 RestClient。
如果应模拟 RestClient,则应将工厂切换为模拟工厂。
除了你自己想出来的,还有一个办法就是在解析的时候用ParameterOverride
container.RegisterType<IRestClient, RestClient>(url1, new ParameterOverride(url1));
IRestClient restClient1 = container.Resolve<IRestClient>(url1);
container.RegisterType<IServiceClient1, ServiceClient1>();
IServiceClient1 svcClient = container.Resolve<IServiceClient1>(
new ParameterOverride("client", restClient1)
);
恕我直言,您将 "inject dependencies" 与 "inject parameters" 混合在一起。如果您的代码是新的,那么这是一个不太理想的设计。
对于新代码,您应该(恕我直言)注入依赖项。
..
现在,你是如何处理你的需求的?
有办法。
将 IConfigurationRetriever 注入您的 ServiceClient1 和 ServiceClient2。
public ServiceClient1 (IRestClient client, IConfigurationRetriever icr)
现在您可以创建一个简单的实现
public interface IConfigurationRetriever()
{
string GetSomeMagicValueOne();
}
public InMemoryConfigurationRetriever : IConfigurationRetriever
{
public string GetSomeMagicValueOne(){ return "HardCodedUrl"; }
}
您不应该将 URL 硬编码到对象中。但至少在上述情况下,您完成硬编码的方式仍然使您的 ServiceClient1 和 ServiceClient2 在未来保持灵活性。
以及如何,当您想创建一种不同的方式来读取配置时,您可以编写 "FromAppOrWebConfigConfigurationRetriever : IConfigurationRetriever" 或 "FromDotNetCoreJsonFileConfigurationRetriever : IConfigurationRetriever" 或 "FromTheDatabaseConfigurationRetriever : IConfigurationRetriever"
恕我直言,InjectionConstructor 用于处理 "old code" 在构造函数中具有参数的变通方法。并且 InjectionConstructor 不应该被设计成新的代码。再次,恕我直言。