Использование службы WCF из веб-приложения.net core 2.1
У меня есть приложение.net Framework, которое успешно использует службу WCF, и когда я пытаюсь скопировать настройки в мою библиотеку классов.net standard 2.0 - которая используется веб-приложением.net core 2.1 - я получаю различные ошибки в зависимости от того, как я установил это.
Во-первых, это рабочая конфигурация потребителя:
<netTcpBinding>
<binding name="netTcpBinding_Service" closeTimeout="00:10:00" openTimeout="00:40:00" receiveTimeout="00:32:00" sendTimeout="00:10:00" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" />
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" algorithmSuite="Default" />
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
</security>
</binding>
</netTcpBinding>
<behaviors>
<endpointBehaviors>
<behavior name="ClientBehavior">
<clientCredentials>
<clientCertificate findValue="Client" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
<serviceCertificate>
<defaultCertificate findValue="Server" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
<authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</endpointBehaviors>
</behaviors>
<endpoint address="net.Tcp://localhost:8004/Service" behaviorConfiguration="ClientBehavior" binding="netTcpBinding" bindingConfiguration="netTcpBinding_RACService" contract="ServiceInterfaces.IRACService" name="IService">
<identity>
<dns value="Server" />
</identity>
Сценарий 1: Попытайтесь дублировать настройки настолько, насколько это возможно:
private static NetTcpBinding CreateNetTcpBinding()
{
var security = new NetTcpSecurity
{
Message = new MessageSecurityOverTcp(),
Transport = new TcpTransportSecurity()
};
security.Message.ClientCredentialType = MessageCredentialType.Certificate;
security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
security.Transport.SslProtocols |= SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
security.Mode = SecurityMode.TransportWithMessageCredential;
var binding = new NetTcpBinding
{
CloseTimeout = new TimeSpan(0, 10, 0),
OpenTimeout = new TimeSpan(0, 40, 0),
ReceiveTimeout = new TimeSpan(0, 32, 0),
Name = "NetTcpBinding",
SendTimeout = new TimeSpan(0, 10, 0),
MaxBufferPoolSize = 524288,
MaxReceivedMessageSize = 2147483647,
Security = security,
};
return binding;
}
Получение исключения для этой строки: security.Message.ClientCredentialType = MessageCredentialType.Certificate;
Исключение:
{System.PlatformNotSupportedException: MessageSecurityOverTcp.ClientCredentialType не поддерживается для значений, отличных от "MessageCredentialType.None". в System.ServiceModel.MessageSecurityOverTcp.set_ClientCredentialType(значение MessageCredentialType)
Сценарий 2: значение MessageCrendentialType изменено на None
private static NetTcpBinding CreateNetTcpBinding()
{
var security = new NetTcpSecurity
{
Message = new MessageSecurityOverTcp(),
Transport = new TcpTransportSecurity()
};
security.Message.ClientCredentialType = MessageCredentialType.None;
security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
security.Transport.SslProtocols |= SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
security.Mode = SecurityMode.TransportWithMessageCredential;
var binding = new NetTcpBinding
{
CloseTimeout = new TimeSpan(0, 10, 0),
OpenTimeout = new TimeSpan(0, 40, 0),
ReceiveTimeout = new TimeSpan(0, 32, 0),
Name = "NetTcpBinding",
SendTimeout = new TimeSpan(0, 10, 0),
MaxBufferPoolSize = 524288,
MaxReceivedMessageSize = 2147483647,
Security = security,
};
return binding;
}
private static EndpointAddress CreateEndpoint()
{
var identity = new DnsEndpointIdentity("Server");
var uri = new Uri("net.Tcp://localhost:8004/Service");
var endpoint = new EndpointAddress(uri, identity);
return endpoint;
}
public static ServiceProxy CreateClientProxy(string url)
{
ServiceProxy racServiceProxy;
racServiceProxyStore.TryGetValue(url, out racServiceProxy);
try
{
if ((racServiceProxy != null) && (racServiceProxy.State == CommunicationState.Faulted ||
racServiceProxy.State == CommunicationState.Closed))
{
racServiceProxy.Abort();
racServiceProxy = null;
}
if (racServiceProxy == null)
{
CallBackProxy cb = new CallBackProxy();
InstanceContext ctx = new InstanceContext(cb);
var binding = CreateNetTcpBinding();
var endpoint = CreateEndpoint();
racServiceProxy = new ServiceProxy(ctx, binding, endpoint);
racServiceProxy.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "Client");
}
}
catch (InvalidOperationException ex)
{
throw;
}
catch (Exception ex)
{
}
return racServiceProxy;
}
public void InvokeService(IWCFMessage message, OnStatusReceived onStatusReceived, OnResultReceived onResultReceived)
{
try
{
Guid processId = ((WCFMessage)message).ProcessID;
callBackProxy.AddEvents(onStatusReceived, onResultReceived, processId);
if (this.State == CommunicationState.Opened || this.State == CommunicationState.Created)
{
if (this.State == CommunicationState.Created)
this.ChannelFactory.Open();
base.Channel.InvokeRACService(message);
}
else
{
throw new RacServiceProxyChannelException("Channel Faulted", (int)this.State);
}
}
Получение исключения по: this.ChannelFactory.Open();
, Если я пропущу эту строку, я получу исключение: base.Channel.InvokeRACService(message);
Исключение:
{System.PlatformNotSupportedException: NetTcpBinding.CreateMessageSecurity не поддерживается. в System.ServiceModel.NetTcpBinding.CreateMessageSecurity() в System.ServiceModel.NetTcpBinding.CreateBindingElements() в System.ServiceModel.Channels.Binding.EnsureInvariants(строковый contractName) сервисное_категоризация_источник_услуги_произведения_источник_источника_произв.) в System.ServiceModel.ChannelFactory.OnOpening() в System.ServiceModel.Channels.CommunicationObject.System.ServiceModel.IAsyncCommunicationObject.OpenAsync(тайм-аут TimeSpan) в системном.ServiceModel.Cternal.OynSynOInSynOInSynOInSynOInSynOInSynOInSynCoreSynCoreSynSynCoreSynSynC.ChannelFactory.EnsureOpened() в System.ServiceModel.DuplexChannelFactory1.CreateChannel(InstanceContext callbackInstance, адрес EndpointAddress, Uri через) в System.ServiceModel.ClientBase1.get_Channel()}
Сценарий 3: Изменение режима безопасности: security.Mode = SecurityMode.None;
(в методе CreateNetTcpBinding)
Получение исключения при вызове сервиса base.Channel.InvokeService(message);
Исключение:
{System.ServiceModel.CommunicationException: соединение с сокетом было прервано. Это может быть вызвано ошибкой обработки вашего сообщения или превышением тайм-аута приема удаленным хостом, или проблемой основного сетевого ресурса. Тайм-аут локального сокета был '00:09:59.8599605'. ---> System.Net.Sockets.SocketException: существующее соединение было принудительно закрыто удаленным хостом в System.ServiceModel.Channels.SocketConnection.HandleReceiveAsyncCompleted() в System.ServiceModel.Channels.SocketConnection.BeginReadCore(смещение Int32, Int32, Int32, Int32, Время ожидания, Действие
1 callback, Object state) --- End of inner exception stack trace --- at System.ServiceModel.Channels.SocketConnection.BeginReadCore(Int32 offset, Int32 size, TimeSpan timeout, Action
1 обратный вызов, состояние объекта) в System.ServiceModel.Channels.SocketConnection.BeginRead (смещение Int32, размер Int32, время ожидания TimeSpan, действие1 callback, Object state) at System.ServiceModel.Channels.DelegatingConnection.BeginRead(Int32 offset, Int32 size, TimeSpan timeout, Action
1 обратный вызов, состояние объекта) в System.ServiceModel.Channels.ConnectionHelpers.IConnectionExtensions.ReadAsync (соединение IConnection, смещение Int32, размер Int32, время ожидания TimeSpan) в System.ServiceModel.Channels.ConnectionHelpers.IConnectionExtensions.ReonAsction connection, IConnectionExtensions.ReonAsction буфер, смещение Int32, размер Int32, время ожидания TimeSpan) в System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.SendPreambleAsync (соединение IConnection, ArraySegment1 preamble, TimeSpan timeout) at System.ServiceModel.Channels.ConnectionPoolHelper.EstablishConnectionAsync(TimeSpan timeout) at System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.OnOpenAsync(TimeSpan timeout) at System.ServiceModel.Channels.CommunicationObject.OnOpenAsyncInternal(TimeSpan timeout) at System.ServiceModel.Channels.CommunicationObject.System.ServiceModel.IAsyncCommunicationObject.OpenAsync(TimeSpan timeout) at System.ServiceModel.Channels.CommunicationObject.OpenAsyncInternal(TimeSpan timeout) at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) at System.Runtime.TaskHelpers.CallActionAsync[TArg](Action
1 действие, аргумент TArg) в System.ServiceModel.Channels.CommunicationObject.OpenOtherAsync (ICommunicationObject other, тайм-аут TimeSpan) в System.ServiceModel.Channels.ServiceChannel.OnOpenAsync (тайм-аут TimeSpan TimeSource.OnCoNec.. Channels.ServiceChannel.ICallOnce.Call (канал ServiceChannel, тайм-аут TimeSpan) в System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce (тайм-аут TimeSpan, каскад CallOnceManager) в системном System.ServiceModel.Channelpen.Sime ServiceModel.Channels.ServiceChannel.Call (строковое действие, логический односторонний процесс, операция ProxyOperationRuntime, объект [] в s, Object [] ауты, время ожидания TimeSpan) в System.ServiceModel.Channels.ServiceChannelProxy.InvokeService (операция MethodCall methodCall, ProxyOperationRuntime) в System.ServiceModel.Channels.ServiceChannelProxy.Invoke (MethodInfo targetMethogs) трассировки стека из предыдущего местоположения, где было сгенерировано исключение --- в System.Reflection.DispatchProxyGenerator.Invoke(Object[] args)}