Set TextMessageEncoding-message version in wsHttpBinding - wcf

I am trying to call SOAP1.2 service using wsHttpBinding. The service accepts rejects the default Soap12WSAddressing10 message version. It only accepts SOAP12.
One suggestion I could get from the Internet search was to create the TextMessageEncodingElement in a custom binding.
How can it be either be accomplished using code or configuration ?
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Certificate;
//MessageVersion = SOAP12
On using the custom wsBinding as well, there is no suggested placeholder to specify the message version.
<wsHttpBinding>
<binding name="customWS">
<security mode="Transport">
<message clientCredentialType="Certificate"></message>
</security>
</binding>
</wsHttpBinding>

Soap12 specify the soapaction by content-type header. I think it is not implemented in net core. I use the following code.
var encoding = new TextMessageEncodingBindingElement(MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None), Encoding.UTF8);
But this is not implemented in net core.

Related

wcf NetworkCredential with empty user name and password

I created a WCF service and the security mode has been set to Transport and ClientCredentialType is Windows. Below is my client side code:
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
binding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
ChannelFactory<IServices> factory factory = new ChannelFactory<IServices>(binding, service);
NetworkCredential credential = factory.Credentials.Windows.ClientCredential;
credential.UserName = string.Empty;
credential.Password = string.Empty;
IServices connect = factory.CreateChannel();
bResult = connect.IsServerOnline();
Server config:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="tcpConSecure" />
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="TestService.Services">
<endpoint address="tcp" behaviorConfiguration="EndpointBe" binding="netTcpBinding" bindingConfiguration="tcpConSecure" contract="TestServiceInterface.IServices" />
</service>
</services>
</system.serviceModel>
In theory, I should input the correct windows account name and password, but during test, I found I could set the UserName and Password as empty, and channel still could be created. Why?
Client and Server are not on the same machine, but they are in same domain. The logon account of Client machine could login Server machine. In this case, I could use empty user name and password to create connection and call WCF service.
The channel factory created by the client has nothing to do with the WCF server. Even if the server closes the client, the channel factory can be created successfully, but an error will occur when the method is called.
If you only create a channel, then you set the Username and Password in the credential has nothing to do with the WCF Service. Only when the call is made, the client will pass the Username and Password to the server, and the value of Username and Password will be verified.
This is the explanation in the Microsoft documentation:
UPDATE:
There is another possibility that can cause this problem. If the client and server are on the same machine, the client does not need to provide windows credentials.

Call Soap 1.2 service from .net core

I'm trying to consume a SOAP 1.2 WCF service from .net core 3.1.
I have a client in .net framework 4 working. It uses wsHttpBinding with security mode TransportWithMessageCredential.
First I tried to use wsHttpBinding in my .net core client but I got a "Platform not supported" exception. So I switched to BasicHttpsBinding but that led to another exception when I called a function:
ProtocolException: Content Type text/xml; charset=utf-8 was not supported by service https://domain/Service.svc. The client and service bindings may be mismatched.
From what I found BasicHttpsBinding is for Soap 1.1 and wsHttpBinding is for Soap 1.2.
So I tried setting the Soap-version to 1.2 according to https://stackoverflow.com/a/53336689 but that gave me another exception:
SocketException: An existing connection was forcibly closed by the remote host.
This is the working config for .net 4 (somewhat abbreviated for readability):
<bindings>
<wsHttpBinding>
<binding name="ServiceEndpoint"
messageEncoding="Text" textEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
This is my .net core code (not working):
var binding = new BasicHttpsBinding();
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
binding.Security.Mode = BasicHttpsSecurityMode.TransportWithMessageCredential;
// Code from https://stackoverflow.com/a/53336689
var customTransportSecurityBinding = new CustomBinding(binding);
var textBindingElement = new TextMessageEncodingBindingElement
{
MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None)
};
// Replace text element to have Soap12 message version
customTransportSecurityBinding.Elements[1] = textBindingElement;
var serviceClient = new Svc.ServiceClient(customTransportSecurityBinding, new EndpointAddress("https://domain/Service.svc"));
serviceClient.ClientCredentials.UserName.UserName = "usr";
serviceClient.ClientCredentials.UserName.Password = "pwd";
var units = serviceClient.GetUnitsAsync().Result; // Exception here
The server and the client must use the same binding to communicate. Your server uses wsHttpBinding but the client uses BasicHttpsBinding, so they cannot communicate normally.
You are right. Core does not currently support wsHttpBinding, so there are two solutions:
1:Change the wsHttpBinding of the server to BasicHttpBinding, and the core does not support the Message security mode. For the WCF features in the Core, you can refer to the link below:
https://github.com/dotnet/wcf/blob/master/release-notes/SupportedFeatures-v2.1.0.md
2:The client uses the .net framework instead of core.
I suggest you use the second solution. After all, core's support for wcf is not good.
Feel free to let me know if the problem persists.

WCF Service - MTOM Security modes & transport/message property's values

Could you please let me know, how/what to set the Mode and ClientCredentialType property in configuration for MTOM-basicHttpBinding.
For ANONYMOUS authentication- Below configuration is working fine
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
Could you please help me to understand what should the values against each attribute for NTLM and Windows authentication types for Mtom binding?
Thanks,
Both the below security modes support Windows/NTLM authentication and MTOM encoding.
Uri uri = new Uri("https://localhost:21011");
BasicHttpBinding binding = new BasicHttpBinding();
binding.MessageEncoding = WSMessageEncoding.Mtom;
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
// NTLM
//binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
Or,
Uri uri = new Uri("http://localhost:21011");
BasicHttpBinding binding = new BasicHttpBinding();
binding.MessageEncoding = WSMessageEncoding.Mtom;
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
Feel free to let me know if the problem still exists.

Programmatic configuration of [Silverlight] WCF Client

We're developing a Silverlight Client onto a server-based API exposed via WCF.
I'm trying to move my WCF client code (which works fine) from a configuration-based model to a programmatic model. This will enable me to have a single "root" URL which I can apply at start-up and not require installations to have to maintain humongous configuration files.
I'm stuggling converting my configurations to Silverlight-capable code, though.
Where I have the configuration below for one of my services:
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="CustomBinding_ISilverlightHelper">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647">
<extendedProtectionPolicy policyEnforcement="Never" />
</httpTransport>
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://localhost:50072/API/WCF/Silverlight/SilverlightHelper.svc"
binding="customBinding" bindingConfiguration="CustomBinding_ISilverlightHelper"
contract="API.WCF.Silverlight.ISilverlightHelper" name="CustomBinding_ISilverlightHelper" />
</client>
</system.serviceModel>
</configuration>
I can't figure out how to create the equivelant client-config code. At the moment I have:
CustomBinding customBinding = new CustomBinding();
// I see I need to do something with customBinding but the properties don't seem
// logical
// I have used BasicHttpBinding, but it just returns with "Not Found" (the service does resolve to a valid URL)
BasicHttpBinding basicHttpBinding = new BasicHttpBinding() { MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue };
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:50072/API/WCF/Silverlight/SilverlightHelper.svc");
ISilverlightHelper silverlightHelper= new ChannelFactory<ISilverlightHelper>(basicHttpBinding, endpointAddress).CreateChannel();
AsyncCallback asyncCallback = delegate(IAsyncResult result)
{
ISilverlightHelper asyncSilverlightHelper = (ISilverlightHelper)result.AsyncState;
string[] files=asyncSilverlightHelper.EndGetPlugInXapNames(result).ToArray();
};
silverlightHelper.BeginGetPlugInXapNames(asyncCallback, silverlightHelper);
Any clues would be appreciated. I've spent all morning Googling/Binging/Overflowing but haven't come across this scenario. Or I might be just so far wrong ...
Sorted it.
I created the BinaryMessageEncodingBindingElement and HttpTransportBindingElements, added them to the CustomBinding and it all works.
Here's my annotated code:
// create the binding elements
BinaryMessageEncodingBindingElement binaryMessageEncoding = new BinaryMessageEncodingBindingElement();
HttpTransportBindingElement httpTransport = new HttpTransportBindingElement() { MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue };
// add the binding elements into a Custom Binding
CustomBinding customBinding = new CustomBinding(binaryMessageEncoding,httpTransport);
// create the Endpoint URL (I'll use a configured URL later - all web services will then move as one)
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:50072/API/WCF/Silverlight/SilverlightHelper.svc");
// create an interface for the WCF service
ISilverlightHelper silverlightHelper= new ChannelFactory<ISilverlightHelper>(customBinding, endpointAddress).CreateChannel();
// set-up the asynchronous callback
AsyncCallback asyncCallback = delegate(IAsyncResult result)
{
ISilverlightHelper asyncSilverlightHelper = (ISilverlightHelper)result.AsyncState;
string[] files=asyncSilverlightHelper.EndGetPlugInXapNames(result).ToArray();
};
// execute the call
silverlightHelper.BeginGetPlugInXapNames(asyncCallback, silverlightHelper);

Increasing the timeout value in a WCF service

How do I increase the default timeout to larger than 1 minute on a WCF service?
Are you referring to the server side or the client side?
For a client, you would want to adjust the sendTimeout attribute of a binding element. For a service, you would want to adjust the receiveTimeout attribute of a binding elemnent.
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="longTimeoutBinding"
receiveTimeout="00:10:00" sendTimeout="00:10:00">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="longTimeoutService"
behaviorConfiguration="longTimeoutBehavior">
<endpoint address="net.tcp://localhost/longtimeout/"
binding="netTcpBinding" bindingConfiguration="longTimeoutBinding" />
</service>
....
Of course, you have to map your desired endpoint to that particular binding.
Under the Tools menu in Visual Studio 2008 (or 2005 if you have the right WCF stuff installed) there is an options called 'WCF Service Configuration Editor'.
From there you can change the binding options for both the client and the services, one of these options will be for time-outs.
You can choose two ways:
1) By code in the client
public static void Main()
{
Uri baseAddress = new Uri("http://localhost/MyServer/MyService");
try
{
ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService));
WSHttpBinding binding = new WSHttpBinding();
binding.OpenTimeout = new TimeSpan(0, 10, 0);
binding.CloseTimeout = new TimeSpan(0, 10, 0);
binding.SendTimeout = new TimeSpan(0, 10, 0);
binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
serviceHost.AddServiceEndpoint("ICalculator", binding, baseAddress);
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
}
catch (CommunicationException ex)
{
// Handle exception ...
}
}
2)By WebConfig in a web server
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding openTimeout="00:10:00"
closeTimeout="00:10:00"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
For more detail view the official documentations
Configuring Timeout Values on a Binding
Class WSHttpBinding
Different timeouts mean different things. When you're working on the client.. you're probably looking mostly at the SendTimeout - check this reference - wonderful and relevant explanation:
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/84551e45-19a2-4d0d-bcc0-516a4041943d/
It says:
Brief summary of binding timeout knobs...
Client side:
SendTimeout is used to initialize the OperationTimeout, which governs the whole interaction for sending a message (including receiving a reply message in a request-reply case). This timeout also applies when sending reply messages from a CallbackContract method.
OpenTimeout and CloseTimeout are used when opening and closing channels (when no explicit timeout value is passed).
ReceiveTimeout is not used.
Server side:
Send, Open, and Close Timeout same as on client (for Callbacks).
ReceiveTimeout is used by ServiceFramework layer to initialize the session-idle timeout.
In addition to the binding timeouts (which are in Timespans), You may also need this as well. This is in seconds.
<system.web>
<httpRuntime executionTimeout="600"/><!-- = 10 minutes -->