Задание адреса конечной точки
Вся связь со службой Windows Communication Foundation (WCF) осуществляется через ее конечные точки. Каждая конечная точка службы ServiceEndpoint содержит адрес Address, привязку Binding и контракт Contract. В контракте задается, какие операции доступны. Привязка определяет, как осуществлять взаимодействие со службой, а адрес показывает, где можно найти службу. Каждая конечная точка должна иметь уникальный адрес. Адрес конечной точки представляется классом EndpointAddress, содержащим универсальный код ресурса (URI), который, в свою очередь, обозначает адрес службы, Identity, представляющий удостоверение безопасности службы и коллекцию необязательных заголовков Headers. Необязательные заголовки содержат более подробную информацию для идентификации конечной точки и взаимодействия с ней. Например, в заголовках может содержаться информация о том, как следует обрабатывать входящее сообщение, куда конечная точка должна отправить ответное сообщение или какой экземпляр службы необходимо использовать для обработки входящего сообщения от конкретного пользователя, если доступно несколько экземпляров.
Определение адреса конечной точки
В WCF адрес EndpointAddress моделирует ссылку на конечную точку (EPR) согласно определению в стандарте WS-Addressing.
Универсальный код ресурса (URI) адреса для большинства видов транспорта состоит из четырех частей. Например, код «http://www.fabrikam.com:322/mathservice.svc/secureEndpoint» состоит из следующих четырех частей.
Схема: http:
Компьютер: www.fabrikam.com
(Необязательно) Порт: 322
Путь: /mathservice.svc/secureEndpoint
Одной из особенностей модели EPR является то, что каждая ссылка на конечную точку может содержать некоторые ссылочные параметры, которые добавляют дополнительные идентификационные сведения. В WCF эти ссылочные параметры моделируются как экземпляры класса AddressHeader.
Адрес конечной точки службы можно задать императивно с помощью кода или декларативно с помощью конфигурации. Как правило, определять конечные точки в коде непрактично, поскольку привязки и адреса для развернутой службы чаще всего отличаются от привязок и адресов, используемых в процессе разработки службы. Обычно более целесообразно задать конечные точки службы в конфигурации, а не в коде. Если не указывать привязку и адрес в коде, их можно изменять без повторной компиляции и повторного развертывания приложения. Если конечные точки не заданы в коде или в конфигурации, то среда выполнения добавляет одну конечную точку по умолчанию для каждого базового адреса в каждом контракте службы, реализованном в службе.
В WCF существует два способа задания адресов конечных точек для службы. Можно задать абсолютный адрес для каждой конечной точки, связанной со службой, или указать базовый адрес для узла службы ServiceHost, а затем задать адрес для каждой связанной с этой службой конечной точки, которая определяется относительно этого базового адреса. Любой из этих методов можно использовать для задания адресов конечных точек для службы как в конфигурации, так и в коде. Если не указывать относительный адрес, служба использует базовый адрес. Можно указать несколько базовых адресов для службы, однако для каждого транспорта каждая служба может иметь только один базовый адрес. Если имеется несколько конечных точек, настроенных по разным привязкам, каждая из них должна иметь уникальный адрес. Конечные точки, использующие одну привязку, но разные контракты, могут иметь один и тот же адрес.
При размещении в службах IIS управление экземпляром ServiceHost не осуществляется пользователем. При размещении в службах IIS базовый адрес — это всегда адрес службы, указанный в файле SVC. Следовательно, для конечных точек служб, размещенных в IIS, следует использовать относительные адреса. Указание полного адреса конечной точки может привести к ошибкам при развертывании службы. Дополнительные сведения см. в разделе Развертывание службы WCF, размещенной в IIS.
Определение адреса конечной точки в конфигурации
Для того чтобы определить конечную точку в файле конфигурации, следует использовать элемент <endpoint>.
<configuration>
<system.serviceModel>
<services>
<service name="UE.Samples.HelloService"
behaviorConfiguration="HelloServiceBehavior">
<endpoint address="/Address1"
binding="basicHttpBinding"
contract="UE.Samples.IHello"/>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="HelloServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Когда вызывается метод Open (то есть ведущее приложение пытается запустить службу), система осуществляет поиск элемента <service> с атрибутом name, где задано значение «UE.Samples.HelloService». При нахождении элемента <service> система загружает указанный класс и создает конечные точки с помощью определений конечных точек, заданных в файле конфигурации. Благодаря такому механизму можно загружать и запускать службу с двумя строками кода, при этом не указывая привязку и адрес в коде. Преимуществом этого подхода является отсутствие необходимости в повторной компиляции или повторном развертывании приложения при внесении этих изменений.
Необязательные заголовки объявлены в элементе <headers> element. Ниже приведен пример элементов, используемых для задания конечных точек службы в файле конфигурации, различающем два заголовка: клиентов типа "Gold" из «http://tempuri1.org/» и клиентов типа "Standard" из «http://tempuri2.org/». В файле конфигурации клиента, вызывающего данную службу, должен содержаться соответствующий элемент заголовка <headers> element.
<configuration>
<system.serviceModel>
<services>
<service name="UE.Samples.HelloService"
behaviorConfiguration="HelloServiceBehavior">
<endpoint address="/Address1"
binding="basicHttpBinding"
contract="UE.Samples.IHello">
<headers>
<Member xmlns="http://tempuri1.org/">Gold</Member>
</headers>
</endpoint>
<endpoint address="/Address2"
binding="basicHttpBinding"
contract="UE.Samples.IHello">
<headers>
<Member xmlns="http://tempuri2.org/">Silver</Member>
</headers>
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="HelloServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Можно настроить заголовки для отдельных сообщений конечной точки, а не всех одновременно (как показано выше). В этом случае для создания нового контекста в клиентском приложении для добавления пользовательского заголовка в исходящее сообщение используется OperationContextScope, как показано в следующем примере.
Dim wcfClient As New SampleServiceClient(New InstanceContext(Me))
Try
Using scope As New OperationContextScope(wcfClient.InnerChannel)
Dim header As MessageHeader = MessageHeader.CreateHeader("Service-Bound-CustomHeader", _
"http://Microsoft.WCF.Documentation", "Custom Happy Value.")
OperationContext.Current.OutgoingMessageHeaders.Add(header)
' Making calls.
Console.WriteLine("Enter the greeting to send: ")
Dim greeting As String = Console.ReadLine()
'Console.ReadLine();
header = MessageHeader.CreateHeader("Service-Bound-OneWayHeader", _
"http://Microsoft.WCF.Documentation", "Different Happy Value.")
OperationContext.Current.OutgoingMessageHeaders.Add(header)
' One-way
wcfClient.Push(greeting)
Me.wait.WaitOne()
' Done with service.
wcfClient.Close()
Console.WriteLine("Done!")
Console.ReadLine()
End Using
Catch timeProblem As TimeoutException
Console.WriteLine("The service operation timed out. " & timeProblem.Message)
Console.ReadLine()
wcfClient.Abort()
Catch commProblem As CommunicationException
Console.WriteLine("There was a communication problem. " & commProblem.Message)
Console.ReadLine()
wcfClient.Abort()
End Try
SampleServiceClient wcfClient = new SampleServiceClient(new InstanceContext(this));
try
{
using (OperationContextScope scope = new OperationContextScope(wcfClient.InnerChannel))
{
MessageHeader header
= MessageHeader.CreateHeader(
"Service-Bound-CustomHeader",
"http://Microsoft.WCF.Documentation",
"Custom Happy Value."
);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
// Making calls.
Console.WriteLine("Enter the greeting to send: ");
string greeting = Console.ReadLine();
//Console.ReadLine();
header = MessageHeader.CreateHeader(
"Service-Bound-OneWayHeader",
"http://Microsoft.WCF.Documentation",
"Different Happy Value."
);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
// One-way
wcfClient.Push(greeting);
this.wait.WaitOne();
// Done with service.
wcfClient.Close();
Console.WriteLine("Done!");
Console.ReadLine();
}
}
catch (TimeoutException timeProblem)
{
Console.WriteLine("The service operation timed out. " + timeProblem.Message);
Console.ReadLine();
wcfClient.Abort();
}
catch (CommunicationException commProblem)
{
Console.WriteLine("There was a communication problem. " + commProblem.Message);
Console.ReadLine();
wcfClient.Abort();
}
Адрес конечной точки в метаданных
Адрес конечной точки представляется на языке описания веб-служб (WSDL) в виде элемента ссылки на конечную точку EPR WS-Addressing EndpointReference в элементе wsdl:port соответствующей конечной точки. Ссылка на конечную точку (EPR) содержит адрес конечной точки и любые свойства адреса. Обратите внимание, что EPR в элементе wsdl:port заменяет soap:Address, как показано в следующем примере.
Определение адреса конечной точки в коде
Адрес конечной точки можно создать в коде с помощью класса EndpointAddress. URI, заданный для адреса конечной точки, может представлять собой полный путь или путь относительно базового адреса службы. В следующем фрагменте кода показано создание экземпляра класса EndpointAddress и его добавление в экземпляр ServiceHost, в котором размещается служба.
В следующем примере показано, как задавать полный адрес конечной точки в коде.
Uri baseAddress = new Uri("https://localhost:8000/HelloService");
string address = "https://localhost:8000/HelloService/MyService";
using (ServiceHost serviceHost = new ServiceHost(typeof(HelloService), baseAddress))
{
serviceHost.AddServiceEndpoint(typeof(IHello), new BasicHttpBinding(), address);
serviceHost.Open();
Console.WriteLine("Press <enter> to terminate service");
Console.ReadLine();
serviceHost.Close();
}
В следующем примере показано, как добавлять относительный адрес ("MyService") в базовый адрес узла службы.
Uri baseAddress = new Uri("https://localhost:8000/HelloService");
using (ServiceHost serviceHost = new ServiceHost(typeof(HelloService), baseAddress))
{
serviceHost.AddServiceEndpoint(typeof(IHello), new BasicHttpBinding(), "MyService");
serviceHost.Open();
Console.WriteLine("Press <enter> to terminate service");
Console.ReadLine();
serviceHost.Close();
}
Примечание |
---|
Свойства объекта ServiceDescription в приложении службы нельзя изменять после вызова метода OnOpening для объекта ServiceHostBase. Некоторые члены, такие как свойство Credentials и методы AddServiceEndpoint классов ServiceHostBase и ServiceHost, создают исключение, если их изменить после вызова этого метода. Другие члены можно изменять без появления исключения, но результат при этом будет неопределенным. Аналогично на стороне клиента нельзя изменять значения ServiceEndpoint после вызова метода OnOpening для объекта ChannelFactory. Если после вызова этого метода изменить свойство Credentials, создается исключение. Изменение других значений описания клиента происходит без ошибок, но результат изменения в этом случае является неопределенным. Как для службы, так и для клиента, рекомендуется изменять описание до вызова метода Open. |
Использование конечных точек по умолчанию
Если конечные точки не заданы в коде или в конфигурации, то среда выполнения предоставляет конечные точки по умолчанию, добавляя одну конечную точку по умолчанию для каждого базового адреса в каждом контракте службы, реализованном в службе. Базовый адрес можно указывать в коде или в конфигурации, а конечные точки по умолчанию добавляются, когда вызывается метод Open в объекте ServiceHost.
Если конечные точки предоставляются явно, то конечные точки по умолчанию можно добавить, вызвав метод AddDefaultEndpoints в объекте ServiceHost перед вызовом Open. Дополнительные сведения о конечных точках по умолчанию, привязках и поведениях см. в разделах Упрощенная конфигурация и Упрощенная конфигурация служб WCF.
См. также
Справочник
Основные понятия
Идентификация и проверка подлинности службы
Общие сведения о создании конечных точек