SOAP с сервисной тканью - привязка Https и Http
В настоящее время я разрабатываю приложение для сервисов, которое выведет слушателя мыла, который будет потребляться другим приложением
Я продолжаю ошибаться, говоря:
Не удалось найти базовый адрес, соответствующий схеме https для конечной точки со связыванием CustomBinding. Схемы зарегистрированных базовых адресов: []
здесь используется метод CreateServiceInstanceListener
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
var serviceInstanceListers = new List<ServiceInstanceListener>()
{
new ServiceInstanceListener(context =>
{
return CreateSoapListener(context);
})
,
new ServiceInstanceListener(context =>
{
return CreateSoapHTTPSListener(context);
}),
};
return serviceInstanceListers;
}
private static ICommunicationListener CreateSoapHTTPSListener(StatelessServiceContext context)
{
string host = context.NodeContext.IPAddressOrFQDN;
var endpointConfig = context.CodePackageActivationContext.GetEndpoint("SecureServiceEndpoint");
int port = endpointConfig.Port;
string scheme = endpointConfig.Protocol.ToString();
string uri = string.Format(CultureInfo.InvariantCulture, "{0}://{1}:{2}/MyService/", scheme, host, port);
var listener = new WcfCommunicationListener<IServiceInterface>(
serviceContext: context,
wcfServiceObject: new Service(),
listenerBinding: new BasicHttpsBinding(BasicHttpsSecurityMode.Transport),
address: new EndpointAddress(uri)
);
// Check to see if the service host already has a ServiceMetadataBehavior
ServiceMetadataBehavior smb = listener.ServiceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
// If not, add one
if (smb == null)
{
smb = new ServiceMetadataBehavior();
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
smb.HttpsGetEnabled = true;
smb.HttpsGetUrl = new Uri(uri);
listener.ServiceHost.Description.Behaviors.Add(smb);
}
return listener;
}
private static ICommunicationListener CreateSoapListener(StatelessServiceContext context)
{
string host = context.NodeContext.IPAddressOrFQDN;
var endpointConfig = context.CodePackageActivationContext.GetEndpoint("ServiceEndpoint");
int port = endpointConfig.Port;
string scheme = endpointConfig.Protocol.ToString();
string uri = string.Format(CultureInfo.InvariantCulture, "{0}://{1}:{2}/MyService/", scheme, host, port);
var listener = new WcfCommunicationListener<IServiceInterface>(
serviceContext: context,
wcfServiceObject: new Service(),
listenerBinding: new BasicHttpBinding(BasicHttpSecurityMode.None),
address: new EndpointAddress(uri)
);
// Check to see if the service host already has a ServiceMetadataBehavior
ServiceMetadataBehavior smb = listener.ServiceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
// If not, add one
if (smb == null)
{
smb = new ServiceMetadataBehavior();
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
smb.HttpGetEnabled = true;
smb.HttpGetUrl = new Uri(uri);
listener.ServiceHost.Description.Behaviors.Add(smb);
}
return listener;
}
и вот app.config (извините, если есть бесполезные записи, я скопировал их из существующего приложения WCF)
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
</startup>
<system.web>
<customErrors mode="On"></customErrors>
<compilation debug="true" targetFramework="4.6.2"/>
<httpModules>
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web"/>
</httpModules>
<machineKey decryption="AES" decryptionKey="decryptionkey" validation="SHA1" validationKey="validationkey"/>
</system.web>
<system.serviceModel>
<diagnostics wmiProviderEnabled="true">
<messageLogging logEntireMessage="true" logKnownPii="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true"/>
<endToEndTracing propagateActivity="true" activityTracing="true" messageFlowTracing="true"/>
</diagnostics>
<bindings>
<customBinding>
<binding name="HubBinding">
<security defaultAlgorithmSuite="Basic256Sha256Rsa15" allowSerializedSigningTokenOnReply="true" authenticationMode="MutualCertificateDuplex" securityHeaderLayout="Lax" messageProtectionOrder="EncryptBeforeSign" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"/>
<textMessageEncoding messageVersion="Default"/>
<httpsTransport maxReceivedMessageSize="1073741824"/>
</binding>
<binding name="AuthorityCustomBinding">
<security defaultAlgorithmSuite="Basic256Sha256Rsa15" allowSerializedSigningTokenOnReply="true" authenticationMode="MutualCertificateDuplex" securityHeaderLayout="Lax" messageProtectionOrder="EncryptBeforeSign" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"/>
<textMessageEncoding messageVersion="Default"/>
<httpsTransport maxReceivedMessageSize="1073741824"/>
</binding>
<binding name="CustomBinding_IServiceInterface">
<security/>
<textMessageEncoding/>
<httpsTransport/>
</binding>
</customBinding>
</bindings>
<services>
<service name="MyApp.ProductServiceManufacturer" behaviorConfiguration="ManufacturerBehaviour">
<endpoint address="" name="ManufacturerProductService" binding="customBinding" bindingConfiguration="HubBinding" contract="MyApp.IProductServiceV20161"/>
</service>
</services>
<client>
<endpoint address="https://serverurl:8088/IServiceInterface/Service.svc" behaviorConfiguration="HubManufacturerBehavior" binding="customBinding" bindingConfiguration="AuthorityCustomBinding" contract="Service.IServiceInterface" name="CustomBinding_IProductServiceManufacturerV20161">
<identity>
<dns value="ServerCert"/>
</identity>
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="HubManufacturerBehavior">
<clientCredentials>
<clientCertificate findValue="XXXXXX" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint"/>
<serviceCertificate>
<defaultCertificate findValue="XXXXXX" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint"/>
</serviceCertificate>
</clientCredentials>
</behavior>
<behavior name="MyApp.ReportingServiceManufacturerAspNetAjaxBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ManufacturerBehaviour">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<serviceCertificate findValue="XXXXXX" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint"/>
</serviceCredentials>
<serviceSecurityAudit auditLogLocation="Application" suppressAuditFailure="true" serviceAuthorizationAuditLevel="Failure" messageAuthenticationAuditLevel="Failure"/>
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
<extensions>
<bindingElementExtensions>
<add name="securityBindingElementExtension" type="MyApp.BindingExtensions.SecurityBindingElementExtension, MyApp"/>
</bindingElementExtensions>
</extensions>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="http"/>
<add binding="customBinding" scheme="https"/>
</protocolMapping>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="TelemetryCorrelationHttpModule"/>
<add name="TelemetryCorrelationHttpModule" type="Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule, Microsoft.AspNet.TelemetryCorrelation" preCondition="integratedMode,managedHandler"/>
<remove name="ApplicationInsightsWebTracking"/>
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler"/>
</modules>
<directoryBrowse enabled="true"/>
<validation validateIntegratedModeConfiguration="false"/>
</system.webServer>
</configuration>
Что я делаю неправильно или что пропустил код Любая помощь будет оценена, так как я никогда не делал WCF раньше. Кстати, приложение WCF работает с той же конфигурацией при развертывании на сервере, но если вы блуждаете, почему я делаю это с помощью сервиса, это не для меня :)
ОБНОВЛЕНИЕ Рассмотрение ответа LoekD Я обновил мое объявление метода CreateSoapHTTPSListener, вот что выглядит:
private static ICommunicationListener CreateSoapHTTPSListener(StatelessServiceContext context)
{
string host = context.NodeContext.IPAddressOrFQDN;
var endpointConfig = context.CodePackageActivationContext.GetEndpoint("SecureServiceEndpoint");
int port = endpointConfig.Port;
string scheme = endpointConfig.Protocol.ToString();
var binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.MaxReceivedMessageSize = 1073741824;
string uri = ConfigurationManager.AppSettings.Get("ProductManufacturerService");
Tools.TraceMessage(uri);
var listener = new WcfCommunicationListener<IProductServiceV20161>(
serviceContext: context,
wcfServiceObject: new ProductServiceManufacturer(),
listenerBinding: binding,
address: new EndpointAddress(uri)
);
listener.ServiceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, ConfigurationManager.AppSettings.Get("ServiceCertificateThumbprint"));
listener.ServiceHost.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, ConfigurationManager.AppSettings.Get("ClientCertificateThumbprint"));
// Check to see if the service host already has a ServiceMetadataBehavior
ServiceMetadataBehavior smb = listener.ServiceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
// If not, add one
if (smb == null)
{
smb = new ServiceMetadataBehavior();
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
smb.HttpsGetEnabled = true;
smb.HttpGetEnabled = false;
smb.HttpsGetUrl = new Uri(uri);
listener.ServiceHost.Description.Behaviors.Add(smb);
}
return listener;
}
Затем я получил сообщение об ошибке:
Служба содержит несколько ServiceEndpoint с различными Контрактами, каждая из которых имеет имя = 'IProductServiceV20161' и Namespace = 'namespaceurl/'
Я думаю, это потому, что есть два определения конечной точки службы в файле app.config, а в файле.cs я прокомментировал тэг конечной точки в app.config, и он сработал. Тем не менее, файл wsdl, который я получаю, пропускает некоторые записи по сравнению с файлом, который я получаю с приложением WCF.
ОБНОВЛЕНИЕ 2: Как указать идентификатор конечной точки для службы? и можно ли использовать собственный класс BindingElementExtensionElement?
Ответы
Ответ 1
Убедитесь, что конечная точка в манифесте службы объявлена как тип "HTTPS" и добавлена SSL-сертификат к хосту WCF.
Можете ли вы попробовать изменить это:
listenerBinding: new BasicHttpsBinding(BasicHttpsSecurityMode.Transport)
в это:
listenerBinding: binding
где привязка определяется как:
var binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport)
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
Больше информации здесь.
И настройте хост службы с помощью вашего SSL-сертификата:
listener.ServiceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "Certificate Thumbprint Here");
Ответ 2
Я собираюсь предположить, что вы замаскировали отпечаток вашего сертификата с этими X, а также изменили имя сервера на serverurl для адреса конечной точки клиента.
С этими предположениями я собираюсь использовать значения, которые я вижу в конечной точке вашего клиента, чтобы показать вам, что, как представляется, отсутствует в конфигурации конечной точки службы.
При настройке базового адреса на ваш сервис есть два варианта. Первый вариант хорошо работает для одной конечной точки обслуживания, и это простое исправление в вашей конфигурации; просто добавьте адрес в свою службу. Как это:
<service name="MyApp.ProductServiceManufacturer" behaviorConfiguration="ManufacturerBehaviour">
<endpoint address="https://serverurl:8088/IServiceInterface/Service.svc" name="ManufacturerProductService" binding="customBinding" bindingConfiguration="HubBinding" contract="MyApp.IProductServiceV20161"/>
</service>
Второй вариант, который хорошо работает для нескольких заголовков хостов или даже если вы используете несколько сервисов и хотите использовать конфигурационные преобразования для развертывания среды. Это решение требует, чтобы вы добавляли базовый адрес отдельно, а затем ссылались только на *.svc в адрес конечной точки. Как это:
<service name="MyApp.ProductServiceManufacturer" behaviorConfiguration="ManufacturerBehaviour">
<endpoint address="Service.svc" name="ManufacturerProductService" binding="customBinding" bindingConfiguration="HubBinding" contract="MyApp.IProductServiceV20161"/>
<host>
<baseAddresses>
<add baseAddress="https://serverurl:8088/IServiceInterface" />
</baseAddresses>
</host>
</service>
Дайте один из этих вариантов попробовать и счастливое кодирование.
-TwistedStem
Ответ 3
Для тех, кто работает над подобным, вот что я в итоге (и который отлично работает):
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
var serviceInstanceListers = new List<ServiceInstanceListener>()
{
new ServiceInstanceListener(context =>
{
//return CreateRestListener(context);
return CreateSoapHTTPSListener(context);
}),
};
return serviceInstanceListers;
}
private static ICommunicationListener CreateSoapHTTPSListener(StatelessServiceContext context)
{
var binding = new CustomBinding();
AsymmetricSecurityBindingElement assbe = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement(
MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
binding.Elements.Add(assbe);
binding.Elements.Add(new TextMessageEncodingBindingElement());
binding.Elements.Add(new HttpsTransportBindingElement());
// Extract the STS certificate from the certificate store.
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindByThumbprint, ConfigurationManager.AppSettings.Get("ClientCertificateThumbprint"), false);
store.Close();
var identity = EndpointIdentity.CreateX509CertificateIdentity(certs[0]);
string uri = ConfigurationManager.AppSettings.Get("ServiceUri");
var listener = new WcfCommunicationListener<IService>(
serviceContext: context,
wcfServiceObject: new Service(),//where service implements IService
listenerBinding: binding,
address: new EndpointAddress(new Uri(uri), identity)
);
listener.ServiceHost.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, ConfigurationManager.AppSettings.Get("ServiceCertificateThumbprint"));
listener.ServiceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, ConfigurationManager.AppSettings.Get("ClientCertificateThumbprint"));
// Check to see if the service host already has a ServiceMetadataBehavior
ServiceMetadataBehavior smb = listener.ServiceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
// If not, add one
if (smb == null)
{
smb = new ServiceMetadataBehavior();
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy12;
smb.HttpsGetEnabled = true;
smb.HttpGetEnabled = false;
smb.HttpsGetUrl = new Uri(uri);
listener.ServiceHost.Description.Behaviors.Add(smb);
}
return listener;
}