Больше проблем 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, но я не могу использовать его во время компиляции, потому что у меня много рабочих процессов, которые я вызываю из одной и той же программы (и, следовательно, много записей конфигурации). Есть ли способ установить 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] Наконец-то нашли полное решение :) Да здравствует отражатель!
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;
}