i have a WCF service, i can connect to it, but i cannot call it's method. the exception i get is 'The operation timed out.
but i can call it throw SoapUI very fast and without any error. in soap-ui i should add authorization to make it work :
what i did to solve the problem is:
-adding credentials :
communicationClient.ClientCredentials.UserName.UserName = "XXXX";
communicationClient.ClientCredentials.UserName.Password = "XXXX";
-increasing time out :
communicationClient.Endpoint.Binding.SendTimeout = TimeSpan.FromMinutes(5);
communicationClient.Endpoint.Binding.ReceiveTimeout = TimeSpan.FromMinutes(5);
-doing the same in app.config
they didn't work.
where i create and start the service (in client app) is :
private bool StartService()
{
BasicHttpBinding hb = new BasicHttpBinding()
{
CloseTimeout = new TimeSpan(0, 1, 0, 0),
//MaxBufferSize = 4096,
OpenTimeout = new TimeSpan(0, 1, 0, 0),
ReceiveTimeout = new TimeSpan(0, 1, 0, 0),
SendTimeout = new TimeSpan(0, 1, 0, 0),
};
EndpointAddressBuilder epb = new EndpointAddressBuilder()
{
Uri = new System.Uri("....myServiceUri....")
};
try
{
communicationClient = new SendLetterServiceClient(hb, epb.ToEndpointAddress());
}
catch (EndpointNotFoundException en) { throw en; }
catch (CommunicationException ce) { throw ce; }
communicationClient.ClientCredentials.UserName.UserName = "xxxxxxxx";
communicationClient.ClientCredentials.UserName.Password = "xxxxxxxx";
communicationClient.Endpoint.Binding.SendTimeout = TimeSpan.FromMinutes(5);
communicationClient.Endpoint.Binding.ReceiveTimeout = TimeSpan.FromMinutes(5);
//communicationClient.
if (communicationClient.State != CommunicationState.Opened && communicationClient.State != CommunicationState.Opening)
communicationClient.OpenAsync();
return true;
}
where i use it is :
public async Task<string> SendLetter(string nationalCode, string fileName, byte[] attachments)
{
if (!serviceHasBeenStarted)
{
try{serviceHasBeenStarted = StartService();}
catch{throw new Exception("service has not been started, and can not restart it");}
}
string orgUserName = "XXXXXX";
string orgPassword = "XXXXXX";
string orgCode = "XXXX";
sendLetterAttach attachedLetter = new sendLetterAttach()
{
fileData = attachments,
fileName = fileName
};
try
{
var response1 = Task<getLetterTypeResponse>.Run(() =>
{
return communicationClient.getLetterTypeAsync(
orgCode, orgUserName, orgPassword);
}).Result;
return response1.#return[0];
}
catch(Exception e1)
{
Console.WriteLine("error: \n\t" + e1.Message);
}
return "";
}
when it calls the method, it waits for a minute, then throws exception.
i had added the service through 'add service reference' using visual studio in my .netCore solution.
...Ah! when i add the service, i get following warning:
Warning:Warning: No endpoints compatible with .Net Core apps were found.
This is because core does not support Message:
<binding name="Binding1">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
The above binding configuration is not supported in core,if a service with the above binding configuration is added to the core, an error will be reported:
Core only supports None, Transport:
About core's support for WCF, you can refer to this link:
https://github.com/dotnet/wcf/tree/master/release-notes
solution
You need to change the Message of the server to Transport:
<bindings>
<basicHttpBinding>
<binding name="Binding1">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
Username and password need to be added when the client is calling:
Client.ClientCredentials.UserName.UserName = "test";
Client.ClientCredentials.UserName.Password = "tset";
Feel free to let me know if the problem persists.
UPDATE
You can directly generate proxy classes through the Svcutil command:
Access the singlewsdl of the WCF service through the browser, and then save it locally.
Use Svcutil command to generate proxy class and configuration file.
Finally add them to your project.
Related
I am trying to establish connection to external PKI SOAP web service, but not sure how to set BasicHttpBinding security in .NET 6. Constantly getting exception:
*System.ServiceModel.ProtocolException: 'The header 'Security' from the namespace 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' was not understood by the recipient of this message, causing the message to not be processed. This error typically indicates that the sender of this message has enabled a communication protocol that the receiver cannot process. Please ensure that the configuration of the client's binding is consistent with the service's binding. '
*
I am using auto generated class from wsdl, but create my own binding.
BasicHttpBinding:
public BasicHttpBinding GetCustomBinding()
{
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport)
{
Security =
{
Message =
{
ClientCredentialType = BasicHttpMessageCredentialType.Certificate
},
Transport =
{
ClientCredentialType = HttpClientCredentialType.Certificate
},
Mode = BasicHttpSecurityMode.Transport
},
MaxReceivedMessageSize = MaxMessageSizeBytes
};
return binding;
}
Creating proxy client:
public autoGeneratedClient GetClient(string endpointUrl, string dnsIdentity, string clientCertificatePath, string clientCertificatePassword, string serviceCertificatePath, int timeout = 10)
{
DnsEndpointIdentity endpointIdentity = new DnsEndpointIdentity(dnsIdentity);
EndpointAddress endpointAddress = new EndpointAddress(new Uri(endpointUrl), endpointIdentity);
//CustomBinding for eBox web service with security setup
MyCustomBinding myCustomBinding = new MyCustomBinding();
Binding binding = myCustomBinding.GetCustomBinding();
binding.CloseTimeout = new TimeSpan(0, timeout, 0);
binding.ReceiveTimeout = new TimeSpan(0, timeout, 0);
binding.SendTimeout = new TimeSpan(0, timeout, 0);
binding.OpenTimeout = new TimeSpan(0, timeout, 0);
autoGeneratedClient client = new autoGeneratedClient(binding, endpointAddress);
client.ClientCredentials.ClientCertificate.Certificate = X509CertificateFactory.GetClientCertificate(clientCertificatePath, clientCertificatePassword);
client.ClientCredentials.ServiceCertificate.DefaultCertificate = X509CertificateFactory.GetServiceCertificate(serviceCertificatePath);
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
return client;
}
I'm trying to access a REST service in a WCF server from power BI using Windows Authentication.
Currently the web request from Power BI is done to a nodejs server where we can get the NTLM authentication data in the 'authorization' header of the request.
But I need to do the same request on a WCF server instead. The Rest service of the WCF is working well, when not using any authentication I can access it with the power BI request through https without any issue.
But when I activate the authentication in the WCF server (with binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows), the request is rejected because the authentication fails. I cannot even use the NTLM data as the 'authentication' field in header is not in the received request (when authentication is not set, but I assume that's normal).
For now, everything is running on my machine, and I'm using the "Use my current credentials" option when doing the Windows authentication in Power BI. OF course there's an Active Directory.
the code in the WCF server:
private void StartRestServiceHosts(int port)
{
try
{
using (ServerContainerScope containerScope = new ServerContainerScope())
{
RequestContext.Current.Initialize(LogAreas.Server, Shared.MainUserLogin);
string protocol = Shared.HttpsEnabled ? "https" : "http";
string uri = string.Format("{0}://{1}:{2}/Rest/", protocol, System.Environment.MachineName, port);
Uri httpBaseAddress = new Uri(uri);
var defaultWebHttpBehavior = new WebHttpBehavior()
{
AutomaticFormatSelectionEnabled = true,
DefaultBodyStyle = WebMessageBodyStyle.Wrapped,
DefaultOutgoingRequestFormat = WebMessageFormat.Json,
DefaultOutgoingResponseFormat = WebMessageFormat.Json,
HelpEnabled = false
};
foreach (ServiceDefinition serviceDefinition in _registeredRestServices.Values)
{
string currentServiceName = serviceDefinition.Name;
if (!_restServiceHosts.ContainsKey(currentServiceName))
{
ServiceHost host = new ServiceHost(serviceDefinition.Type,
new Uri(httpBaseAddress, serviceDefinition.Type.Name));
host.Authorization.ServiceAuthorizationManager = new PublicAuthorization();
Type contract = serviceDefinition.Type.GetInterface("I" + serviceDefinition.Type.Name);
ServiceEndpoint endPoint = new ServiceEndpoint(
ContractDescription.GetContract(contract),
_restBinding,
new EndpointAddress("{0}{1}".FormatWith(uri, contract.Name))
);
endPoint.Behaviors.Add(defaultWebHttpBehavior);
endPoint.Behaviors.Add(new CorsSupportBehavior());
host.AddServiceEndpoint(endPoint);
_restServiceHosts.Add(currentServiceName, host);
}
// Open
if (_restServiceHosts[currentServiceName].State != CommunicationState.Opened)
{
_restServiceHosts[currentServiceName].Open();
}
}
OnWcfRestServicesStarted?.Invoke(null, true);
}
}
catch (Exception ex)
{
OnWcfRestServicesStarted?.Invoke(null, false);
}
}
public WebHttpBinding CreateWebHttpBinding(string name)
{
WebHttpBinding binding = new WebHttpBinding();
binding.Security.Mode = Shared.HttpsEnabled ? WebHttpSecurityMode.Transport : WebHttpSecurityMode.None;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
//binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
binding.Name = name;
binding.ReceiveTimeout = new TimeSpan(1, 0, 0);
binding.MaxBufferSize = 2147483647;
binding.MaxReceivedMessageSize = 2147483647;
return binding;
}
<appSettings>
<add key="HttpsEnabled" value="true"/>
</appSettings>
Any ideas as to why the authentication is not working?
Thanks in advance!!!
I am trying to download the subscribers from marketing cloud using the SOAP API and it throws the following exception after couple of iterations.
It does not fail consistently. Sometimes it completes 50 iterations and fails and sometimes it fails after 5 or 10 iterations.
Here is the code I am using to make the retrieve request:
public List<Subscriber> GetSubscribers(string RequestId = null)
{
string message = string.Empty;
_lstSubscribers = new List<Subscriber>();
SoapClient client = new SoapClient();
client.ClientCredentials.UserName.UserName = _username;
client.ClientCredentials.UserName.Password = _password;
RetrieveRequest retrieveRequest = new RetrieveRequest();
retrieveRequest.ObjectType = "Subscriber";
string[] props = { "Client.ID", "CreatedDate", "EmailAddress", "EmailTypePreference", "ID", "PartnerKey", "SubscriberKey", "UnsubscribedDate" };
retrieveRequest.Properties = props;
retrieveRequest.ClientIDs = new ClientID[] { _clientID };
//retrieveRequest.QueryAllAccounts = true;
//retrieveRequest.QueryAllAccountsSpecified = true;
String requestId = RequestId;
String response = string.Empty;
int tryCount = 0;
try
{
RunRetrieveRequest(client, out requestId, out response, retrieveRequest);
}
catch (Exception ex)
{
if (response == "MoreDataAvailable")
{
tryCount++;
if (tryCount <= 10)
{
}
retrieveRequest.ContinueRequest = requestId;
RunRetrieveRequest(client, out requestId, out response, retrieveRequest);
}
}
return _lstSubscribers;
}
private void RunRetrieveRequest(SoapClient client, out string RequestID, out string Response, RetrieveRequest Request)
{
List<Subscriber> lstSubscribers = new List<Subscriber>();
APIObject[] results = null;
do
{
Response = client.Retrieve(Request, out RequestID, out results);
Subscriber subscriber = null;
if (Response != null && results != null)
{
foreach (var result in results)
{
subscriber = (Subscriber)result;
_lstSubscribers.Add(subscriber);
}
}
Request = new RetrieveRequest();
Request.ContinueRequest = RequestID;
} while (Response == "MoreDataAvailable");
}
Here is the config. I have tried changing the timeout attributes from 30 to 59, but this didn't help.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="SoapBinding">
<security mode="Transport" />
</binding>
<binding name="SoapBinding1" />
</basicHttpBinding>
<customBinding>
<binding name="SoapBinding" closeTimeout="00:59:00" openTimeout="00:59:00" receiveTimeout="00:59:00" sendTimeout="00:59:00">
<security authenticationMode="UserNameOverTransport">
<secureConversationBootstrap />
</security>
<textMessageEncoding messageVersion="Soap11WSAddressingAugust2004" />
<httpsTransport maxReceivedMessageSize="655360000" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="https://mySubDomain.soap.marketingcloudapis.com/Service.asmx"
binding="customBinding" bindingConfiguration="SoapBinding"
contract="sfmc.Soap" name="Soap" />
</client>
</system.serviceModel>
I will appreciate any help or suggestion. Thanks in advance.
I have been able to resolve this issue and posting the answer as it may help someone else struggling with a similar issue. The Salesforce marketing cloud API (both SOAP and REST) has stopped supporting the default TLS 1.0 protocol. So I needed to add the following code before I sent any request to the API.
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12 | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls;
The following link has more explained insights on the same.
WCF Error "This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case"
I have the following configuration in my app.config:
<bindings>
<customBinding>
<binding name="myBinding">
<textMessageEncoding messageVersion="Soap12"/>
<httpTransport/>
</binding>
</customBinding>
<wsHttpBinding>
<binding name="myBinding" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8">
<security mode="Transport">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="/../" binding="wsHttpBinding" bindingConfiguration="myBinding" contract="myContract" name="myName"/>
</client>
Using this configuration the service works as expected.
For several reasons i can't use the app.config file in the production environment, so i want to define the bindings in c# instead. I did the following:
var binding = new BasicHttpBinding();
var address = new EndpointAddress(url);
binding.Security = new BasicHttpSecurity() { Mode = BasicHttpSecurityMode.Transport };
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
var client = new MyClient(binding, address);
This works for the first part, but then fails on using an incorrect message version. I can see this is defined in the custombinding, but i'm not sure how to translate this binding to my code. I did try quite a lot, but with no result so far.
Does anyone know how to do this?
I would recommend you to leverage the ConfigurationChannelFactory<TChannel> class to configure your client using XML configuration from a source other than an app.config file (e.g. an XML string read from a database, from a resource in your executable, or from some other custom source).
The XML format is IMHO easier to read and maintain than a configuration built using code.
To do this, the steps are as follows:
Get a string with your XML configuration data, e.g.:
string configurationData = #"<configuration>
<system.serviceModel>
...
";
Save it to a temporary file:
var tempFileName = Path.GetTempFileName();
File.WriteAllText(tempFileName, configurationData);
Generate a System.Configuration.Configuration object from the temp file:
var filemap = new ExeConfigurationFileMap
{
ExeConfigFilename = tempFileName
};
var config = ConfigurationManager.OpenMappedExeConfiguration(filemap, ConfigurationUserLevel.None);
Create a ChannelFactory<TChannel> from the configuration:
var channelFactory = new ConfigurationChannelFactory<TChannel>(endpointConfigurationName, config, remoteAddress);
Once you've created your ChannelFactory<TChannel>, you can delete the temporary file.
You are using BasicHttpBinding instead of CustomBinding
you should do something like this:
var binding = new CustomBinding();
TextMessageEncodingBindingElement textBindingElement = new TextMessageEncodingBindingElement
{
MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None),
WriteEncoding = System.Text.Encoding.UTF8,
ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max
};
binding.Elements.Add(textBindingElement);
But, if you are using .net core you might have issues with this, because there is an open issue for this on GitHub: https://github.com/dotnet/wcf/issues/2711
It seems you are using wshttpbinding.
You could try the code below.Please change to your address and contract.
WSHttpBinding wsbinding = new WSHttpBinding();
wsbinding.MaxBufferPoolSize = 2147483647;
wsbinding.MaxReceivedMessageSize = 2147483647;
wsbinding.MessageEncoding = WSMessageEncoding.Mtom;
wsbinding.TextEncoding = Encoding.UTF8;
wsbinding.Security.Mode = SecurityMode.Transport;
wsbinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
using (ChannelFactory<ICalculatorService> channelFacoty = new ChannelFactory<ICalculatorService>(wsbinding, new EndpointAddress("http://localhost")))
{
ICalculatorService cal = channelFacoty.CreateChannel();
Console.WriteLine( cal.Add(1, 3));
Console.Read();
}
Try the WebHttBinding:
binding = new WebHttpBinding
{
TransferMode = TransferMode.Buffered,
ReceiveTimeout = TimeSpan.FromMinutes(1),
SendTimeout = TimeSpan.FromMinutes(1),
MaxReceivedMessageSize = 2147483647,
MaxBufferPoolSize = 2147483647,
ReaderQuotas =
{
MaxDepth = 2147483647,
MaxStringContentLength = 2147483647,
MaxArrayLength = 2147483647,
MaxBytesPerRead = 2147483647,
MaxNameTableCharCount = 2147483647
},
Security = new WebHttpSecurity()
{
Mode = WebHttpSecurityMode.Transport,
Transport = new HttpTransportSecurity()
{
ClientCredentialType = HttpClientCredentialType.Ntlm
}
}
};
I followed this post (WCF - How to Increase Message Size Quota) and set the MaxBuffer size the largest size it can be and I still get the error. What else could I change?
I used Fiddler to view the response and it is 67,934 bytes. Below is the binding.
<basicHttpBinding>
<binding name="MCPClaimsService_InterfaceSOAP"
maxReceivedMessageSize="21474836470"
maxBufferSize="2147483647"
maxBufferPoolSize="2147483647">
<readerQuotas maxDepth="32"
maxArrayLength="2147483647"
maxStringContentLength="2147483647"/>
</binding>
</basicHttpBinding>
This code has a custom binding. I did not write it.
public static CustomBinding HttpsSSLBinding()
{
var textmessageEncoding = new TextMessageEncodingBindingElement();
textmessageEncoding.WriteEncoding = Encoding.UTF8;
textmessageEncoding.MessageVersion = MessageVersion.Soap11;
MessageSecurityVersion securityVersion = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
AsymmetricSecurityBindingElement bindingElement =
(AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement(securityVersion, true);
bindingElement.SetKeyDerivation(false);
bindingElement.EnableUnsecuredResponse = true;
X509SecurityTokenParameters istp = bindingElement.InitiatorTokenParameters as X509SecurityTokenParameters;
if (istp != null)
{
istp.X509ReferenceStyle = X509KeyIdentifierClauseType.IssuerSerial;
istp.InclusionMode = SecurityTokenInclusionMode.Never;
}
X509SecurityTokenParameters rstp = bindingElement.RecipientTokenParameters as X509SecurityTokenParameters;
if (rstp != null)
{
rstp.X509ReferenceStyle = X509KeyIdentifierClauseType.IssuerSerial;
rstp.InclusionMode = SecurityTokenInclusionMode.Never;
}
HttpsTransportBindingElement transport = new HttpsTransportBindingElement();
return new CustomBinding(bindingElement, textmessageEncoding, transport);
}
}
After I realized it had a custom binding in addition to the binding statement in app.config I added the lines below to the custom binding code and that solved the problem. Hopefully this waste of my time will help someone in the future.
transport.MaxBufferSize = 2147483647;
transport.MaxReceivedMessageSize = 2147483647;
transport.MaxBufferPoolSize = 2147483647;