Search code examples
c#asp.netweb-configdynamics-crm-onlinewshttpbinding

How do I configure an ASP.NET web page to use wsHttpBinding when querying CRM Online?


How do I configure an ASP.NET web form to send requests via wsHttpBinding rather than basicHttpBinding when querying CRM Online?

As a bit of background this is a pretty basic ASPX page hosted locally in IIS 8.5.
The page is meant to connect to CRM Online and pull some data.
Edit: This app is authenticated via Azure AD which is why it uses a client ID and key. I want to shy away from using connection strings and domain credentials unless this is unavoidable.

I think I've got the authentication to CRM correct but when I run a query I receive the error below:

System.Net.WebException: The remote server returned an error: (415) Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'..

I think this is because I haven't specified a binding in web.config so my page is sending everything via basicHttpBinding and the CRM Online interface is expecting wsHttpBinding.

I've tried using the example at the bottom of this MSDN article (and variations thereof) but it makes no difference.

Here's the code for connecting to CRM in case it makes a difference. Obviously I've obscured the real configuration details.

// CONFIGURE OAUTH
var tenantName = "mycompany.onmicrosoft.com";
var authString = string.Format(@"https://login.microsoftonline.com/{0}",tenantName);
var authContext = new AuthenticationContext(authString, false);
var clientId = "123ab123-123a-1a23-abcd-1a2345612345";
var key = "nStgfrdk0oyaC1P5+/FQ4wGn4fRgUTr8HTKejytf0bv=";
var clientCred = new ClientCredential(clientId, key);
var resource = "https://myinstance.crm4.dynamics.com";

// ACQUIRE THE AUTH TOKEN
var authResult = await authContext.AcquireTokenAsync(resource, clientCred);

// CREATE THE CONNECTION TO CRM
var orgService = new OrganizationWebProxyClient(
    new Uri("https://dev.crm4.dynamics.com/XRMServices/2011/Discovery.svc"), true)
    {
        HeaderToken = authResult.AccessToken,
        SdkClientVersion = "8.1.0"
    };

// RUNNING THIS QUERY CAUSES THE ERROR
var contacts = orgService.RetrieveMultiple(new QueryExpression
{
    EntityName = "contact",
    ColumnSet = new ColumnSet("firstname", "lastname")
})
.Entities
.Select(item => item.ToEntity<Contact>());

Here's the stack trace in case it's of use:

[WebException: The remote server returned an error: (415) Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'..] System.Net.HttpWebRequest.GetResponse() +1740 System.ServiceModel.Channels.HttpChannelRequest.WaitForReply(TimeSpan timeout) +75

[ProtocolException: Content Type text/xml; charset=utf-8 was not supported by service https://dev.crm4.dynamics.com/XRMServices/2011/Discovery.svc. The client and service bindings may be mismatched.] System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) +14350190 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) +388 Microsoft.Xrm.Sdk.IOrganizationService.RetrieveMultiple(QueryBase query) +0 Microsoft.Xrm.Sdk.WebServiceClient.WebProxyClient1.ExecuteAction(Func1 action) +51 Quote_Robot_Demo.d__4.MoveNext() +887 System.Runtime.CompilerServices.<>c.b__6_0(Object state) +56 System.Web.Util.SynchronizationHelper.SafeWrapCallback(Action action) +110 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +13847892 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +61 System.Web.Util.WithinCancellableCallbackTaskAwaiter.GetResult() +32 System.Web.UI.d__523.MoveNext() +7970

Edit: Once I added the service reference I got this in my web.config:

  <system.serviceModel>
<bindings>
  <customBinding>
    <binding name="CustomBinding_IDiscoveryService">
      <textMessageEncoding />
      <httpsTransport />
    </binding>
  </customBinding>
</bindings>
<client>
  <endpoint address="https://dev.crm4.dynamics.com/XRMServices/2011/Discovery.svc"
    binding="customBinding" bindingConfiguration="CustomBinding_IDiscoveryService"
    contract="CRMService.IDiscoveryService" name="CustomBinding_IDiscoveryService" />
</client>
</system.serviceModel>

Solution

  • Although I now have some other issues I did discover how to alter the binding.
    You can add the organization service as a service reference to your project as I did and then assign the binding like this:

    orgService.Endpoint.Binding = new CustomBinding("CustomBinding_IOrganizationService");
    

    The string passed to the custom binding is just the name taken from the config:

    <system.serviceModel>
      <bindings>
        <customBinding>
          <binding name="CustomBinding_IOrganizationService">
            ....
    

    Edit: I discovered later on that changing the binding was not necessary. The error seemed to be being caused by an invalid security token. I changed the way I generated security tokens to use the grant_type of password and the error went away on its own.