2
votes

I have created a service reference to the CRM 2011 Organization.svc from a test console application. Everything works perfectly using the binding generated in the app.config. (Example of the service hosted by Microsoft here.)

This now needs to be moved into our "real" application and hosted in a DLL that will be deployed to the GAC. In following the app's conventions, the binding needs to be generated by code.

I've started off trying to use the binding we use for our other WCF services:

BasicHttpBinding binding = new BasicHttpBinding();
binding.SendTimeout = TimeSpan.FromMinutes(1);
binding.OpenTimeout = TimeSpan.FromMinutes(1);
binding.CloseTimeout = TimeSpan.FromMinutes(1);
binding.ReceiveTimeout = TimeSpan.FromMinutes(10);
binding.AllowCookies = true;
binding.BypassProxyOnLocal = false;
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
binding.MessageEncoding = WSMessageEncoding.Text;
binding.TextEncoding = System.Text.Encoding.UTF8;
binding.TransferMode = TransferMode.Buffered;
binding.UseDefaultWebProxy = true;
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;

Unfortunately at the point the WCF service is called (using the Execute method with an OrganizationRequest), this error occurs:

System.ServiceModel.ProtocolException: Content Type text/xml; charset=utf-8 was not supported by service http://server:5555/xrmservices/2011/organization.svc. The client and service bindings may be mismatched.

I'm not sure what the specific problem is with the binding, but my attempts at converting it to code have failed with the same error so far. Here's the working binding defined in app.config:

<bindings>
    <customBinding>
        <binding name="CustomBinding_IOrganizationService">
            <security defaultAlgorithmSuite="Default" authenticationMode="SspiNegotiated"
                requireDerivedKeys="true" securityHeaderLayout="Strict" includeTimestamp="true"
                keyEntropyMode="CombinedEntropy" messageProtectionOrder="SignBeforeEncryptAndEncryptSignature"
                messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
                requireSecurityContextCancellation="true" requireSignatureConfirmation="false">
                <localClientSettings cacheCookies="true" detectReplays="true"
                    replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="Infinite"
                    replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00"
                    sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true"
                    timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="60" />
                <localServiceSettings detectReplays="true" issuedCookieLifetime="10:00:00"
                    maxStatefulNegotiations="128" replayCacheSize="900000" maxClockSkew="00:05:00"
                    negotiationTimeout="00:01:00" replayWindow="00:05:00" inactivityTimeout="00:02:00"
                    sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00"
                    reconnectTransportOnFailure="true" maxPendingSessions="128"
                    maxCachedCookies="1000" timestampValidityDuration="00:05:00" />
                <secureConversationBootstrap />
            </security>
            <textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
                messageVersion="Default" writeEncoding="utf-8">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
            </textMessageEncoding>
            <httpTransport manualAddressing="false" maxBufferPoolSize="524288"
                maxReceivedMessageSize="65536" allowCookies="false" authenticationScheme="Anonymous"
                bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                keepAliveEnabled="true" maxBufferSize="65536" proxyAuthenticationScheme="Anonymous"
                realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
                useDefaultWebProxy="true" />
        </binding>
    </customBinding>
</bindings>

Does anyone know how to set the correct binding in code and/or read the binding from XML?

2

2 Answers

2
votes

I just had the same task to solve. This worked for me (for http).

var security = SecurityBindingElement.CreateSspiNegotiationBindingElement();
security.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Default;
security.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
security.IncludeTimestamp = true;
security.KeyEntropyMode = SecurityKeyEntropyMode.CombinedEntropy;
security.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature;
security.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;

security.LocalClientSettings.CacheCookies = true;
security.LocalClientSettings.DetectReplays = true;
security.LocalClientSettings.ReplayCacheSize = 900000;
security.LocalClientSettings.MaxClockSkew = new TimeSpan(0, 5, 0);
security.LocalClientSettings.MaxCookieCachingTime = new TimeSpan(23, 0, 0, 0);
security.LocalClientSettings.ReplayWindow = new TimeSpan(0, 5, 0);
security.LocalClientSettings.SessionKeyRenewalInterval = new TimeSpan(15, 0, 0);
security.LocalClientSettings.SessionKeyRolloverInterval = new TimeSpan(0, 5, 0);
security.LocalClientSettings.ReconnectTransportOnFailure = true;
security.LocalClientSettings.TimestampValidityDuration = new TimeSpan(0, 5, 0);
security.LocalClientSettings.CookieRenewalThresholdPercentage = 60;

security.LocalServiceSettings.DetectReplays = true;
security.LocalServiceSettings.IssuedCookieLifetime = new TimeSpan(10, 0, 0);
security.LocalServiceSettings.MaxStatefulNegotiations = 128;
security.LocalServiceSettings.ReplayCacheSize = 900000;
security.LocalServiceSettings.MaxClockSkew = new TimeSpan(0, 5, 0);
security.LocalServiceSettings.NegotiationTimeout = new TimeSpan(0, 1, 0);
security.LocalServiceSettings.ReplayWindow = new TimeSpan(0, 5, 0);
security.LocalServiceSettings.InactivityTimeout = new TimeSpan(0, 2, 0);
security.LocalServiceSettings.SessionKeyRenewalInterval = new TimeSpan(15, 0, 0);
security.LocalServiceSettings.SessionKeyRolloverInterval = new TimeSpan(0, 5, 0);
security.LocalServiceSettings.ReconnectTransportOnFailure = true;
security.LocalServiceSettings.MaxPendingSessions = 128;
security.LocalServiceSettings.MaxCachedCookies = 1000;
security.LocalServiceSettings.TimestampValidityDuration = new TimeSpan(0, 5, 0);

var textEncoding = new TextMessageEncodingBindingElement
{
   MaxReadPoolSize = 64,
   MaxWritePoolSize = 16,
   MessageVersion = MessageVersion.Default,
   WriteEncoding = System.Text.Encoding.UTF8,
   ReaderQuotas = new XmlDictionaryReaderQuotas
   {
       MaxDepth = 32,
       MaxArrayLength = 16384,
       MaxBytesPerRead = 4096,
       MaxNameTableCharCount = 16384,
       MaxStringContentLength = 8192
   }
};

var httpTransport = new HttpTransportBindingElement
{
    ManualAddressing = false,
    MaxBufferSize = 65536,
    MaxReceivedMessageSize = 65536,
    AllowCookies = false,
    AuthenticationScheme = AuthenticationSchemes.Anonymous,
    BypassProxyOnLocal = false,
    DecompressionEnabled = true,
    HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
    KeepAliveEnabled = true,
    MaxBufferPoolSize = 524288,
    ProxyAuthenticationScheme = AuthenticationSchemes.Anonymous,
    TransferMode = TransferMode.Buffered,
    UnsafeConnectionNtlmAuthentication = false,
    UseDefaultWebProxy = true,
};

var binding = new CustomBinding(new List<BindingElement> { security, textEncoding, httpTransport });
var endpoint = new EndpointAddress(_serviceUri);

var service = new OrganizationServiceClient(binding, endpoint);
1
votes

Creating a custom channel factory is a key part of solving this.

The article Get your WCF client configuration from anywhere is very helpful for reading a .config file from a location of your choice using a custom service client.

The alternative of setting all the values in a very similar way to the app.config format is described in Calling WCF Service using Client Channel Factory which describes how to create a custom binding. I found that not all of the security properties could be set this way (or at least I couldn't find them).