更多 WCF 困境...:)
我的所有工作流程都实现相同的 3 种方法。经过大量的复制和粘贴,我决定让它们继承同一个接口:
[ServiceContract(Namespace = "http://schema.company.com/messages/")]
public interface IBasicContract<TRequest, TResponse>
where TRequest : class
where TResponse : class
{
[OperationContract(Name = "GetReport",
Action = "http://schema.company.com/messages/GetReport",
ReplyAction = "http://schema.company.com/messages/GetReportResponse")]
TResponse GetReport(TRequest inquiry);
[OperationContract(Name = "GetRawReport",
Action = "http://schema.company.com/messages/GetRawReport",
ReplyAction = "http://schema.company.com/messages/GetRawReportResponse")]
string GetRawReport(string guid);
[OperationContract(Name = "GetArchiveReport",
Action = "http://schema.company.com/messages/GetArchiveReport",
ReplyAction = "http://schema.company.com/messages/GetArchiveReportResponse")]
TResponse GetArchiveReport(string guid);
}
我还决定创建服务客户端的通用实现:
public class BasicSvcClient<TRequest, TResponse> : ClientBase<IBasicContract<TRequest, TResponse>>, IBasicContract<TRequest, TResponse>
where TRequest : class
where TResponse : class
{
public BasicSvcClient()
{
}
public BasicSvcClient(string endpointConfigurationName) :
base(endpointConfigurationName)
{
}
public BasicSvcClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public BasicSvcClient(string endpointConfigurationName, EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public BasicSvcClient(Binding binding, EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}
public TResponse GetReport(TRequest inquiry)
{
return Channel.GetReport(inquiry);
}
public string GetRawReport(string guid)
{
return Channel.GetRawReport(guid);
}
public TResponse GetArchiveReport(string guid)
{
return Channel.GetArchiveReport(guid);
}
}
问题是当我尝试使用这个时:
using (var client = new BasicSvcClient<TRequest, TResponse>())
{
var response = client.GetReport(inquiry);
context.Response.ContentType = "text/xml";
context.Response.Write(response.AsXML());
}
我总是收到一条错误消息,说它找不到合约 IBasicContract 的配置,其中 .NET 使用的奇怪语法是:
找不到默认端点
引用合同的元素
'BasicWorkflow.IBasicContract`2...
我尝试这样做:
using (var client = new BasicSvcClient<TRequest, TResponse>("myConfig"))
这没有帮助——它仍在寻找特定的合同。
我知道 ServiceContract 属性有一个 ConfigurationName 参数,但我无法在编译时使用它,因为我有many我从同一程序调用的工作流程(因此有许多配置条目)。有没有办法在运行时设置 ConfigurationName?我认为这就是 ClientBase 构造函数应该做的事情,但显然不是。
[编辑] 这是 .config 文件中的端点,我认为在这种情况下它不是很有帮助:
<endpoint address="https://localhost/services/Contract.svc"
binding="basicHttpBinding"
bindingConfiguration="httpsDataEndpoint"
contract="IContract" name="IContractSvc" />
[Edit2] 好的...我找到了一种有效的方法,尽管我仍然不完全满意:
using (var wf = new BasicSvcClient<TRequest, TResponse>(
new BasicHttpBinding("httpsDataEndpoint"),
new EndpointAddress("https://localhost/services/Contract.svc")))
我现在遇到的唯一问题是我更愿意从 .config 文件中检索端点地址(使用实际的合约名称,如 IContract)。有人可以帮助我完成那部分吗?
[Edit3] 终于找到了完整的解决方案:) Reflector万岁!
var cf = (ClientSection) ConfigurationManager.GetSection("system.serviceModel/client");
foreach (ChannelEndpointElement endpoint in cf.Endpoints)
{
if (endpoint.Name != "ContractSvc")
continue;
using (var wf = new BasicSvcClient<TRequest, TResponse>(
new BasicHttpBinding("httpsDataEndpoint"),
new EndpointAddress(endpoint.Address.ToString())))
{
//... call wf.GetReport()
}
break;
}