Использовать веб-сервис SOAP, не полагаясь на app.config
Я создаю компонент.NET, который будет вызывать внешний веб-сервис. Я использовал диалоговое окно "Добавить ссылку на службу", чтобы добавить веб-службу в мой компонент, который генерирует код, необходимый для использования службы, и добавляет настройки в файл app.config.
Я тестирую компонент, добавляя ссылку на его DLL из консольного приложения и вызывая соответствующий метод, который создает новый экземпляр веб-службы: ... = new MyServiceSoapClient()
, Однако, когда я делаю это, я получаю следующее исключение:
InvalidOperationException
Не удалось найти элемент конечной точки по умолчанию, который ссылается на контракт "MyServicesSoap" в разделе конфигурации клиента ServiceModel. Это может быть связано с тем, что для вашего приложения не найден файл конфигурации, или из-за того, что в клиентском элементе не найден элемент конечной точки, соответствующий этому контракту.
Это имеет смысл, поскольку app.config не переносится с DLL компонента. Как я могу вызвать веб-сервис, не полагаясь на настройки в App.Config?
3 ответа
Настройки в <system.ServiceModel>
в файле app.config расскажет компоненту, как подключиться к внешнему веб-сервису. Xml - это просто текстовое представление необходимых классов и перечислений, необходимых для подключения по умолчанию к веб-службе.
Например, это код, который был сгенерирован для веб-сервиса, который я добавил:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MyServicesSoap" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://services.mycompany.com/WebServices/MyServices.asmx"
binding="basicHttpBinding" bindingConfiguration="MyServicesSoap"
contract="MyServices.MyServicesSoap" name="MyServicesSoap" />
</client>
</system.serviceModel>
Это может быть переведено в код следующим образом:
'Set up the binding element to match the app.config settings '
Dim binding = New BasicHttpBinding()
binding.Name = "MyServicesSoap"
binding.CloseTimeout = TimeSpan.FromMinutes(1)
binding.OpenTimeout = TimeSpan.FromMinutes(1)
binding.ReceiveTimeout = TimeSpan.FromMinutes(10)
binding.SendTimeout = TimeSpan.FromMinutes(1)
binding.AllowCookies = False
binding.BypassProxyOnLocal = False
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard
binding.MaxBufferSize = 65536
binding.MaxBufferPoolSize = 524288
binding.MessageEncoding = WSMessageEncoding.Text
binding.TextEncoding = System.Text.Encoding.UTF8
binding.TransferMode = TransferMode.Buffered
binding.UseDefaultWebProxy = True
binding.ReaderQuotas.MaxDepth = 32
binding.ReaderQuotas.MaxStringContentLength = 8192
binding.ReaderQuotas.MaxArrayLength = 16384
binding.ReaderQuotas.MaxBytesPerRead = 4096
binding.ReaderQuotas.MaxNameTableCharCount = 16384
binding.Security.Mode = BasicHttpSecurityMode.None
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None
binding.Security.Transport.Realm = ""
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName
binding.Security.Message.AlgorithmSuite = Security.SecurityAlgorithmSuite.Default
'Define the endpoint address'
Dim endpointStr = "http://services.mycompany.com/WebServices/MyServices.asmx"
Dim endpoint = New EndpointAddress(endpointStr)
'Instantiate the SOAP client using the binding and endpoint'
'that were defined above'
Dim client = New MyServicesSoapClient(binding, endpoint)
Обычно, когда вы используете конструктор без параметров (т.е. new MyServicesSoapClient()
), будут использованы настройки в файле app.config. Однако вы можете обойти файл app.config, явно указав binding
а также endpoint
значения в коде и передачи этих экземпляров в конструктор.
Установка конфигурации связывания и конечной точки в коде - это один из способов, но есть другой способ использовать потребительскую DLL и оставить конфигурацию в существующем файле App.config.
Причина, по которой возникает упомянутое исключение InvalidOperationException, заключается в том, что библиотека DLL не содержит в себе параметров конфигурации. Он всегда полагается на App.config, чтобы обеспечить его, но, поскольку вы используете DLL в другом консольном приложении, он не находит параметры конфигурации.
Когда мы используем диалоговое окно "Добавить ссылку на службу" для добавления веб-службы к клиентскому компоненту и создания экземпляра веб-службы, мы позволяем Visual Studio обрабатывать создание канала связи и загружать параметр конфигурации. Итак, если мы можем создайте такой канал сами, тогда мы сможем управлять настройками конфигурации.
Microsoft предоставляет классы для этой цели, ConfigurationChannelFactory<TChannel>
Класс один. MSDN заявляет:
Предоставляет общие функциональные возможности для создания элемента конфигурации канала для определенного типа.
ConfigurationChannelFactory позволяет централизованно управлять конфигурацией клиента WCF.
Используйте диалоговое окно "Добавить ссылку на службу", чтобы добавить веб-службу к клиентскому компоненту, так как нам нужен экземпляр интерфейса канала службы.
Сначала переименуйте сгенерированный файл App.config в App.dll.config и в свойствах его файла измените свойство " Копировать в выходной каталог" на " Всегда копировать".
Создайте класс, у которого есть метод, который возвращает объект Channel для доступа к веб-службе, например:
public class ManageService
{
public static T CreateServiceClient<T>(string configName)
{
string _assemblyLocation = Assembly.GetExecutingAssembly().Location;
var PluginConfig = ConfigurationManager.OpenExeConfiguration(_assemblyLocation);
ConfigurationChannelFactory<T> channelFactory = new ConfigurationChannelFactory<T>(configName, PluginConfig, null);
var client = channelFactory.CreateChannel();
return client;
}
}
Так как мы установили свойство Copy Always VS, мы копируем DLL проекта, а также App.dll.config в папку bin. Assembly.GetExecutingAssembly().Location
вернуть место сборки и ConfigurationManager.OpenExeConfiguration
Открывает указанный файл конфигурации клиента как объект конфигурации.
PluginConfig
содержит файл конфигурации App.Config Object и ConfigurationChannelFactory<T>
использует его для связи с сервисом.
Этот метод может быть вызван путем передачи вашего объекта интерфейса служебного канала следующим образом:
Client = ManageService.CreateServiceClient<SampleService.IKeyServiceChannel>("MetadataExchangeTcpBinding_IKeyService");
SampleService
это пространство имен моего веб-сервиса. Client
содержит экземпляр веб-службы.
Если вам нужно обрабатывать дуплексную связь и обратные вызовы, вы можете посмотреть на ConfigurationDuplexChannelFactory<TChannel>
Учебный класс.
Если это служба WCF (как это звучит из сообщений об ошибках), то по большей части вам понадобится что-то app.config, потому что это app.config, который сообщает остальной части WCF, что MyServiceSoapClient - это веб-служба (с небольшим изменением в двух файлах app.config это может стать именованным каналом, без перекомпиляции кода....)
Теперь, если вы действительно хотите сделать это без app.config, вы должны бросить сгенерированный MyServiceSoapClient()
и написать свой, основываясь на HttpWebRequest
,