我正在使用一个有用的RestClient,它处理对其他Web服务的Rest调用。此RestClient是较大的Service-Client的一部分,后者通过提供由businesslogic等使用的便捷方法来处理不同的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
实现这一目标?
答案 0 :(得分:0)
您必须为此使用工厂。如果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注入Factory,而不注入RestClient。
如果要模拟RestClient,则应将工厂切换为模拟工厂。
答案 1 :(得分:0)
除了您自己想出的方法之外,另一种方法是在解析过程中使用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)
);
答案 2 :(得分:0)
恕我直言,您正在将“注入依赖项”与“注入参数”混合在一起。如果您的代码是新的,那么这将是一个不太理想的设计。
使用新代码,您应该(恕我直言)注入依赖关系。
..
现在,您如何处理自己的需求?
有办法。
将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用于处理在构造函数中具有参数的“旧代码”,这是一种变通方法。而且不应将InjectionConstructor设计成新代码。再次,恕我直言。