How can I programmatically create this custom binding? - wcf

We've got to access a web service that uses soap11... no problem I'll just set the binding as:
BasicHttpBinding wsBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
Nope. No dice. So I asked the host of the service why we're having authentication issues and he said that our config needed to have this custom binding:
<bindings>
<customBinding>
<binding name="lbinding">
<security authenticationMode="UserNameOverTransport"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11"
securityHeaderLayout="Strict"
includeTimestamp="false"
requireDerivedKeys="true"
keyEntropyMode="ServerEntropy">
</security>
<textMessageEncoding messageVersion="Soap11" />
<httpsTransport authenticationScheme ="Negotiate" requireClientCertificate ="false" realm =""/>
</binding>
</customBinding>
</bindings>
Only problem is we're creating our binding programmatically not via the config. So if someone could point me in the right direction in regards to changing my BasicHttpBinding into a custombinding that conforms to the .config value provided I'll give them a big shiny gold star for the day.

Solved it!
Here's the winning code for those who are in a similar predicament.
Uri epUri = new Uri(_serviceUri);
CustomBinding binding = new CustomBinding();
SecurityBindingElement sbe = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
sbe.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11;
sbe.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
sbe.IncludeTimestamp = false;
sbe.SetKeyDerivation(true);
sbe.KeyEntropyMode = System.ServiceModel.Security.SecurityKeyEntropyMode.ServerEntropy;
binding.Elements.Add(sbe);
binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, System.Text.Encoding.UTF8));
binding.Elements.Add(new HttpsTransportBindingElement());
EndpointAddress endPoint = new EndpointAddress(epUri);

#D. Forrest already found the solution, but a simple way to see what objects are involved for a given WCF configuration is to call .Endpoint.Binding.CreateBindingElements() on the client proxy you are using. You can the dump the object tree of each item in the list that is returned and see how the binding is configured.

You can use :
Uri epUri = new Uri("http://localhost/TestWCFService/Service.svc");
CustomBinding binding = new CustomBinding()
{
Name = "anyname",
ReceiveTimeout = new TimeSpan(0, 0, 10, 0, 0),
SendTimeout = new TimeSpan(0, 0, 10, 0, 0),
};
var element1 = new TextMessageEncodingBindingElement()
{
ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
{
MaxDepth = 2147483647,
MaxStringContentLength = 2147483647,
MaxArrayLength = 2147483647,
MaxBytesPerRead = 2147483647,
MaxNameTableCharCount = 2147483647
}
};
var element2 = new HttpsTransportBindingElement()
{
ManualAddressing = false,
MaxReceivedMessageSize = 2147483647,
AllowCookies = false,
AuthenticationScheme = System.Net.AuthenticationSchemes.Anonymous,
BypassProxyOnLocal = false,
MaxBufferSize = 2147483647,
ProxyAuthenticationScheme = System.Net.AuthenticationSchemes.Anonymous,
TransferMode = TransferMode.Buffered,
UseDefaultWebProxy = true
};
var element3 = new TextMessageEncodingBindingElement(MessageVersion.Soap11, System.Text.Encoding.UTF8);
binding.Elements.Add(element1);
binding.Elements.Add(element2);
binding.Elements.Add(element3);
//binding.Elements.Add(new HttpsTransportBindingElement());
EndpointAddress endPoint = new EndpointAddress(epUri);
var client = new ServiceClient(binding, endPoint);

Related

WCF 413 Request Entity Too Large - Self Hosted WebHttpBinding

There are many discussions about this problem, however I have now tried every possible solution and we are still getting 413 Request Entity Too Large errors from the server.
Our WCF service is self hosted via an Azure Worker role, and does not use IIS. All of our configuration is specified in code:
var host = new ServiceHost(searchEngine);
// Create binding
var binding = new WebHttpBinding(WebHttpSecurityMode.Transport);
binding.MaxReceivedMessageSize = 2147483647;
binding.MaxBufferSize = 2147483647;
binding.MaxBufferPoolSize = 2147483647;
var readerQuotas = new XmlDictionaryReaderQuotas
{
MaxStringContentLength = 2147483647,
MaxArrayLength = 2147483647,
MaxBytesPerRead = 2147483647,
MaxDepth = 2147483647,
MaxNameTableCharCount = 2147483647
};
// Setting quotas on a BindingElement after the binding is created has no effect on that binding.
// See: https://stackoverflow.com/questions/969479/modify-endpoint-readerquotas-programatically
binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, readerQuotas, null);
binding.ReceiveTimeout = new TimeSpan(1, 0, 0);
binding.SendTimeout = new TimeSpan(1, 0, 0);
// Add the service endpoint
var ep = host.AddServiceEndpoint(
typeof(ISearchEngine),
binding,
string.Format("https://{0}/SearchEngine", externalEndpoint));
ep.Behaviors.Add(new WebHttpBehavior());
// Increase the MaxItemsInObjectGraph quota for all operations in this service
foreach (var operation in ep.Contract.Operations)
{
operation.Behaviors.Find<DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = 10000000;
}
return host;
And this is our client configuration - also specified in code:
var binding = new WebHttpBinding(WebHttpSecurityMode.Transport);
binding.MaxReceivedMessageSize = 2147483647;
binding.MaxBufferSize = 2147483647;
binding.MaxBufferPoolSize = 2147483647;
var readerQuotas = new XmlDictionaryReaderQuotas
{
MaxStringContentLength = 2147483647,
MaxArrayLength = 2147483647,
MaxBytesPerRead = 2147483647,
MaxDepth = 2147483647,
MaxNameTableCharCount = 2147483647
};
// Setting quotas on a BindingElement after the binding is created has no effect on that binding.
// See: https://stackoverflow.com/questions/969479/modify-endpoint-readerquotas-programatically
binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, readerQuotas, null);
binding.ReceiveTimeout = new TimeSpan(1, 0, 0);
binding.SendTimeout = new TimeSpan(1, 0, 0);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
var channelFactory = new ChannelFactory<ISearchEngine>(binding, endpointAddress);
channelFactory.Endpoint.Behaviors.Add(new WebHttpBehavior());
// Increase the MaxItemsInObjectGraph quota for all operations in this service
foreach (var operation in channelFactory.Endpoint.Contract.Operations)
{
operation.Behaviors.Find<DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = 10000000;
}
return channelFactory.CreateChannel();
My only hunch could be a problem with the SSL connection? There are some articles mentioning a problem specific to IIS, however I'm not sure if this is relevant to self hosted services.
Any advice very much appreciated.
UPDATE:
To confirm my hunch that SSL was the problem, I temporarily disabled SSL and lo and behold the problem disappeared.
So now I need to figure out why SSL would be causing the problem. There is a fair bit of documentation about a similar problem, but it relates to IIS hosted services only (ours is self hosted from a windows service):
IIS7 - (413) Request Entity Too Large | uploadReadAheadSize
Would anyone out there know an equivalent setting that would apply to self hosted WCF services only?
I found the problem, thanks to this seemingly unrelated post:
http://forums.newatlanta.com/messages.cfm?threadid=554611A2-E03F-43DB-92F996F4B6222BC0&#top
It was absolutely an SSL issue, and it's to do with binding the SSL certificate to the port you are hosting on. You must bind the certificate using netsh and add clientcertnegotiation=enable to the binding.
In our case we were already using netsh since we were using a different port, so our binding now looks like this:
netsh http add sslcert ipport=0.0.0.0:10100 certhash=000000089A6679262D845B650FDDE5390F0D86AB appid={000007b4-2d4b-4587-ae99-7a6627476f76} clientcertnegotiation=enable
For those of you hosting through IIS, and changing the value of UploadReadAheadSize, the forum post above notes that this may cause high CPU and instead this solution may be better.
In cases where you need to transfer large data, you should use transferMode = "Streaming".
Take a look at this paper from MS:
http://msdn.microsoft.com/en-us/library/ms733742(v=vs.110).aspx
<webHttpBinding>
<binding name="TransportSecurity" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="Transport" />
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="16384" />
</binding>

System.InsufficientMemoryException: Failed to allocate a managed memory buffer of 536870912 bytes. The amount of available memory may be low

Below mentioned in Web.Config on Server Side.
<bindings>
<wsHttpBinding>
<binding name="NewBinding0" closeTimeout="00:50:00" openTimeout="00:50:00" sendTimeout="00:50:00" receiveTimeout="00:50:00" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<reliableSession enabled="true" />
<security mode="None">
<transport clientCredentialType="None" />
<message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
Also at client side I mention below settings.
WSHttpBinding binding = new WSHttpBinding();
//binding.ReaderQuotas.MaxArrayLength = 10485760;
//binding.MaxReceivedMessageSize = 10485760;
binding.Security.Mode = SecurityMode.None;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
binding.Security.Message.EstablishSecurityContext = false;
//binding.Security.Message.NegotiateServiceCredential = true;
binding.ReliableSession.Enabled = true;
binding.ReaderQuotas.MaxArrayLength = 2147483647;
binding.ReaderQuotas.MaxDepth = 2147483647;
binding.ReaderQuotas.MaxNameTableCharCount = 2147483647;
binding.ReaderQuotas.MaxBytesPerRead = 2147483647;
//binding.MaxReceivedMessageSize = 20000000;2147483647
binding.MaxReceivedMessageSize = 2147483647;
//binding.MaxReceivedMessageSize = Int32.MaxValue;
binding.ReaderQuotas.MaxStringContentLength = 2147483647;
//binding.MaxBufferPoolSize = 20000000;
binding.MaxBufferPoolSize = 2147483647;
//binding.MaxBufferPoolSize = Int32.MaxValue;
binding.ReaderQuotas.MaxArrayLength = 2147483647;
binding.ReaderQuotas.MaxDepth = 2147483647;
binding.SendTimeout = TimeSpan.FromMinutes(50);
binding.CloseTimeout = TimeSpan.FromMinutes(50);
binding.OpenTimeout = TimeSpan.FromMinutes(50);
binding.ReceiveTimeout = TimeSpan.FromMinutes(50);
//EndpointIdentity.CreateUpnIdentity("user#domain");
ChannelFactory<IDBSyncContract> factory = new ChannelFactory<IDBSyncContract>(binding, new EndpointAddress(endPointURL));
dbProxy = factory.CreateChannel();
this.dbProxy = dbProxy as IDBSyncContract;
I am getting above mentioned error.
Is there any concerns regarding wsHttpBindings.
Your problem is that the service is consuming all available memory on the host machine. I'd recommend that you remove all your config changes and return the config to the WCF default values. These default values were chosen by Microsoft for best performance in the average WCF service and you should only change them when you have a demonstrated need to do so.
The only exceptions I would recommend to the default values are the maxReceivedMessageSize and the maxBufferSize values. I'd start those at 262,144 bytes. If you get specific exceptions with any of these settings then changes only the affected setting.
If you're still having problems after upping a setting to max integer then consider changing your service design to get a successful call within the normal config setting. Staying as close as possible to the WCF default values will give your service the best overall performance.

How to use a Service Reference with a basic authentication WCF SOAP Service

I have a WCF SOAP service that uses basic access authentication. SSL is not being used - I understand the security issues here.
Using the WCFTestClient application I have verified the service works by temporarily hard coding into the service a user name and password to use when the Authorization header is not present.
I am now trying to write a test application that passes the credentials via the Authorization header. I've added a service reference to my service in my test app but the Authorization header is not present in the http request. The generated MyServiceClient class uses System.ServiceModel.ClientBase
In my test app I am setting the credentials as follows
MyServiceClient client = new MyServiceClient("BasicHttpBinding_MyService");
client.ClientCredentials.UserName.UserName = "WebServiceUsername";
client.ClientCredentials.UserName.Password = "WebServicepassword";
I have also tried as follows
MyServiceClient client = new MyServiceClient();
ClientCredentials loginCredentials = new ClientCredentials();
loginCredentials.UserName.UserName = "WebServiceUsername";
loginCredentials.UserName.Password = "WebServicepassword";
client.Endpoint.Behaviors.Remove(client.Endpoint.Behaviors.Find<ClientCredentials>());
client.Endpoint.Behaviors.Add(loginCredentials);
The service web.config is as follows
<services>
<service name="MyService" behaviorConfiguration="MyBehavior" >
<endpoint contract="MyService" binding="basicHttpBinding" />
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
</services>
The test app.config is as follows
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_MyService">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:55314/MyService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_MyService"
contract="MyService" name="BasicHttpBinding_MyService" />
</client>
</system.serviceModel>
</configuration>
Any thoughts on what I am missing?
This is a good starting point, move your binding and endpoint info from config file to your class:
protected BasicHttpBinding binding = new BasicHttpBinding()
{
Name = "Name your binding here",
CloseTimeout = new TimeSpan(0, 1, 0),
OpenTimeout = new TimeSpan(0, 1, 0),
ReceiveTimeout = new TimeSpan(0, 10, 0),
SendTimeout = new TimeSpan(0, 1, 0),
AllowCookies = false,
BypassProxyOnLocal = false,
HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
MaxBufferSize = 65536,
MaxBufferPoolSize = 524288,
MaxReceivedMessageSize = 65536,
MessageEncoding = WSMessageEncoding.Text,
TransferMode = TransferMode.Buffered,
UseDefaultWebProxy = true,
Security = new BasicHttpSecurity()
{
Mode = BasicHttpSecurityMode.Transport,
Message = new BasicHttpMessageSecurity() { AlgorithmSuite = SecurityAlgorithmSuite.Default, ClientCredentialType = BasicHttpMessageCredentialType.UserName},
Transport = new HttpTransportSecurity() { ClientCredentialType = HttpClientCredentialType.Digest }
},
};
protected EndpointAddress endPoint = new EndpointAddress("http://localhost:55314/MyService.svc");
and then
MyServiceClient client = new MyServiceClient(binding, endpont);
Try this, and tweak the binding into your needs, especially "Security".
BasicHttpBinding doesn't seem to have a Security Property in WP8, I am very frustrated with trying to access a sharepoint list under WP8. Xamarin IOS/Android it is no problem.

WCF service on ServiceBus fails if call longer than 1 minute

I have a WCF Service that is hosted in a ServiceHost object. The ServiceHost is created on the OnStart method of an Azure Worker Role. Here is the code:
ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.Http;
Uri baseAddress = ServiceBusEnvironment.CreateServiceUri("http", "my_sb", "SimpleService");
host = new ServiceHost(typeof(SimpleService1.Service1), baseAddress);
BasicHttpRelayBinding binding = new BasicHttpRelayBinding(EndToEndBasicHttpSecurityMode.None, RelayClientAuthenticationType.None);
binding.OpenTimeout = new TimeSpan(1, 1, 0);
binding.ReceiveTimeout = new TimeSpan(1, 10, 0);
binding.SendTimeout = new TimeSpan(1, 10, 0);
binding.MaxReceivedMessageSize = 73400320;
XmlDictionaryReaderQuotas readerQuotas = new XmlDictionaryReaderQuotas();
readerQuotas.MaxArrayLength = 73400320;
binding.ReaderQuotas = readerQuotas;
TransportClientEndpointBehavior sharedSecretServiceBusCredential = new TransportClientEndpointBehavior();
sharedSecretServiceBusCredential.CredentialType = TransportClientCredentialType.SharedSecret;
sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerName = "owner";
sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerSecret = "blablablabla==";
ContractDescription contractDescription = ContractDescription.GetContract(typeof(SimpleService1.IService1), typeof(SimpleService1.Service1));
ServiceEndpoint serviceEndPoint = new ServiceEndpoint(contractDescription);
serviceEndPoint.Address = new EndpointAddress(baseAddress);
serviceEndPoint.Binding = binding;
IEndpointBehavior serviceRegistrySettings = new ServiceRegistrySettings(DiscoveryType.Public);
serviceEndPoint.Behaviors.Add(serviceRegistrySettings);
serviceEndPoint.Behaviors.Add(sharedSecretServiceBusCredential);
host.Description.Endpoints.Add(serviceEndPoint);
try
{
host.Open();
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message, "Error");
throw;
}
Trace.WriteLine("SimpleService1 running...");
and the binding configuration on the client side is:
<basicHttpBinding>
<binding name="FileTransferBinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="73400320">
<readerQuotas maxArrayLength="73400320"/>
<security mode="None"/>
</binding>
</basicHttpBinding>
and
<endpoint address="http://my_sb.servicebus.windows.net/simpleservice" binding="basicHttpBinding" bindingConfiguration="FileTransferBinding" contract="Service1reference.IService1" name="FileTransferBinding" behaviorConfiguration="sbBehavior"/>
The problem is that if one call to the service takes longer than 1 minute, the client receives this exception:
The content type application/xml; charset=utf-8 of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly
If I change the binding to a netTcpRelayBinding everything works fine.
This is because the Windows Azure load-balancer disconnects you if the connection is idle for more than a minute.
Your best bet is to use a WCF callback. This will execute a call from the server to the client to let it know that the long-running operation has completed. For more on how to do this have a look at this blog [WCF Callbacks

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);