Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В примере CustomServiceHost показано, как использовать пользовательский производный ServiceHost класс для изменения поведения среды выполнения службы. Этот подход предоставляет повторно используемое решение для настройки большого числа служб единым образом. В образце также демонстрируется, как использовать класс ServiceHostFactory для применения пользовательского ServiceHost в среде размещения служб Internet Information Services (IIS) или службы активации процессов Windows (WAS).
О сценарии
Чтобы предотвратить непреднамеренное раскрытие потенциально конфиденциальных метаданных службы, конфигурация по умолчанию для служб Windows Communication Foundation (WCF) отключает публикацию метаданных. Это поведение безопасно по умолчанию, но также означает, что вы не можете использовать средство импорта метаданных (например, Svcutil.exe) для создания клиентского кода, необходимого для вызова службы, если в конфигурации не включено поведение публикации метаданных службы.
Включение публикации метаданных для большого количества служб включает добавление одинаковых элементов конфигурации в каждую отдельную службу, что приводит к большому количеству сведений о конфигурации, которые, по сути, одинаковы. В качестве альтернативы настройке каждой службы по отдельности можно написать императивный код, который позволяет публиковать метаданные один раз, а затем повторно использовать этот код в нескольких разных службах. Это достигается путем создания нового класса, который наследуется от ServiceHost, и переопределяет метод ApplyConfiguration(), чтобы явно добавить функциональность публикации метаданных.
Это важно
Для ясности в этом примере показано, как создать незащищенную конечную точку публикации метаданных. Такие конечные точки потенциально доступны анонимным неавторентированным потребителям и должны быть приняты меры, прежде чем развертывать такие конечные точки, чтобы обеспечить общедоступное раскрытие метаданных службы.
Реализация кастомного ServiceHost
Класс ServiceHost предоставляет несколько полезных виртуальных методов, которые наследующие могут переопределить для изменения поведения среды выполнения службы. Например, ApplyConfigurationметод () считывает сведения о конфигурации службы из хранилища конфигурации и изменяет данные конфигурации узла ServiceDescription соответствующим образом. Реализация по умолчанию считывает конфигурацию из файла конфигурации приложения. Пользовательские реализации могут переопределить ApplyConfiguration() для дальнейшего изменения ServiceDescription с использованием императивного кода или даже полностью заменить хранилище конфигураций по умолчанию. Например, чтобы считывать конфигурацию конечной точки службы из базы данных вместо файла конфигурации приложения.
В этом примере мы хотим создать пользовательский ServiceHost, который добавляет ServiceMetadataBehavior (который обеспечивает публикацию метаданных), даже если это поведение не добавляется в файл конфигурации службы явным образом. Для этого создайте новый класс, наследующий от ServiceHost, и переопределяющий ApplyConfiguration().
class SelfDescribingServiceHost : ServiceHost
{
public SelfDescribingServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses) { }
//Overriding ApplyConfiguration() allows us to
//alter the ServiceDescription prior to opening
//the service host.
protected override void ApplyConfiguration()
{
//First, we call base.ApplyConfiguration()
//to read any configuration that was provided for
//the service we're hosting. After this call,
//this.Description describes the service
//as it was configured.
base.ApplyConfiguration();
//(rest of implementation elided for clarity)
}
}
Поскольку мы не хотим игнорировать любую конфигурацию, предоставленную в файле конфигурации приложения, первое, что делает наше переопределение ApplyConfiguration() — это заключается в вызове базовой реализации. После завершения этого метода мы можем императивно добавить ServiceMetadataBehavior в описание, используя следующий императивный код.
ServiceMetadataBehavior mexBehavior = this.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (mexBehavior == null)
{
mexBehavior = new ServiceMetadataBehavior();
this.Description.Behaviors.Add(mexBehavior);
}
else
{
//Metadata behavior has already been configured,
//so we do not have any work to do.
return;
}
Последнее, что должно сделать наше ApplyConfigurationпереопределение, — добавить конечную точку метаданных по умолчанию. По соглашению создается одна конечная точка метаданных для каждого URI в коллекции BaseAddresses узла службы.
//Add a metadata endpoint at each base address
//using the "/mex" addressing convention
foreach (Uri baseAddress in this.BaseAddresses)
{
if (baseAddress.Scheme == Uri.UriSchemeHttp)
{
mexBehavior.HttpGetEnabled = true;
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex");
}
else if (baseAddress.Scheme == Uri.UriSchemeHttps)
{
mexBehavior.HttpsGetEnabled = true;
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpsBinding(),
"mex");
}
else if (baseAddress.Scheme == Uri.UriSchemeNetPipe)
{
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexNamedPipeBinding(),
"mex");
}
else if (baseAddress.Scheme == Uri.UriSchemeNetTcp)
{
this.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexTcpBinding(),
"mex");
}
}
Использование пользовательского ServiceHost в локальном узле
Теперь, когда мы выполнили свою пользовательскую реализацию ServiceHost, мы можем использовать её для добавления поведения публикации метаданных в любую службу, разместив эту службу в экземпляре нашего SelfDescribingServiceHost. В следующем коде показано, как использовать его в сценарии самообслуживания.
SelfDescribingServiceHost host =
new SelfDescribingServiceHost( typeof( Calculator ) );
host.Open();
Наш пользовательский узел по-прежнему считывает конфигурацию конечной точки сервиса из файла конфигурации приложения, как если бы мы использовали класс по умолчанию ServiceHost для размещения сервиса. Тем не менее, так как мы добавили логику для включения публикации метаданных внутри пользовательского узла, мы больше не должны явно включить поведение публикации метаданных в конфигурации. Этот подход имеет определенное преимущество при создании приложения, содержащего несколько служб, и вы хотите включить публикацию метаданных на каждом из них, не записывая одни и те же элементы конфигурации.
Использование пользовательского ServiceHost в IIS или WAS
Использование настраиваемого хоста службы в сценариях самостоятельного хостинга просто, поскольку код вашего приложения в конечном счете отвечает за создание и открытие экземпляра хоста службы. Однако в среде размещения IIS или WAS инфраструктура WCF динамически инициирует хостинг вашей службы в ответ на входящие сообщения. Пользовательские хосты служб также можно использовать в этой среде размещения, но для них требуется дополнительный код в форме ServiceHostFactory. Следующий код показывает производную от ServiceHostFactory, которая возвращает экземпляры нашего пользовательского SelfDescribingServiceHost.
public class SelfDescribingServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType,
Uri[] baseAddresses)
{
//All the custom factory does is return a new instance
//of our custom host class. The bulk of the custom logic should
//live in the custom host (as opposed to the factory)
//for maximum
//reuse value outside of the IIS/WAS hosting environment.
return new SelfDescribingServiceHost(serviceType,
baseAddresses);
}
}
Как видите, реализация пользовательской ServiceHostFactory довольно проста. Вся настраиваемая логика находится внутри реализации «ServiceHost». Фабрика возвращает экземпляр производного класса.
Чтобы использовать пользовательскую фабрику с реализацией сервиса, необходимо добавить дополнительные метаданные в .svc файл службы.
<% @ServiceHost Service="Microsoft.ServiceModel.Samples.CalculatorService"
Factory="Microsoft.ServiceModel.Samples.SelfDescribingServiceHostFactory"
language=c# Debug="true" %>
Здесь мы добавили в директиву Factory дополнительный атрибут @ServiceHost, и передали имя типа CLR нашей пользовательской фабрики в качестве значения этого атрибута. Когда IIS или WAS получает сообщение для этой службы, инфраструктура размещения WCF сначала создает экземпляр ServiceHostFactory, а затем инстанцирует узел службы путём вызова ServiceHostFactory.CreateServiceHost().
Запуск примера
Хотя этот пример обеспечивает полнофункциональную реализацию клиента и службы, в этом примере показано, как изменить поведение среды выполнения службы с помощью пользовательского узла. Выполните следующие действия.
Наблюдать за эффектом пользовательского хоста
Откройте файл Web.config службы и обратите внимание, что конфигурация явно не включает метаданные для службы.
Откройте файл .svc службы и обратите внимание, что его @ServiceHost директива содержит атрибут Factory, указывающий имя настраиваемого ServiceHostFactory.
Настройка, сборка и запуск примера
Убедитесь, что вы выполнили процедуру настройки One-Time для образцов Windows Communication Foundation.
Чтобы создать решение, следуйте инструкциям по созданию примеров Windows Communication Foundation.
После создания решения запустите Setup.bat, чтобы настроить приложение ServiceModelSamples в IIS 7.0. Каталог ServiceModelSamples теперь должен отображаться как приложение IIS 7.0.
Чтобы запустить пример в конфигурации с одним или несколькими компьютерами, следуйте инструкциям в запуска примеров Windows Communication Foundation.
Чтобы удалить приложение IIS 7.0, запустите Cleanup.bat.