如何配置 ASP.NET 网页以在查询 CRM Online 时使用 wsHttpBinding?

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

如何配置 ASP.NET Web 表单以在查询 CRM Online 时通过 wsHttpBinding 而不是 basicHttpBinding 发送请求?

作为背景知识,这是在 IIS 8.5 中本地托管的非常基本的 ASPX 页面。
该页面旨在连接到 CRM Online 并提取一些数据。
编辑:此应用通过 Azure AD 进行身份验证,这就是它使用客户端 ID 和密钥的原因。我想避免使用连接字符串和域凭据,除非这是不可避免的。

我想我的 CRM 身份验证是正确的,但是当我 运行 查询时,我收到以下错误:

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'..

我认为这是因为我没有在 web.config 中指定绑定,所以我的页面通过 basicHttpBinding 发送所有内容,而 CRM Online 界面期望 wsHttpBinding

我已经尝试使用 this MSDN article 底部的示例(及其变体),但没有任何区别。

以下是连接到 CRM 的代码,以防有所不同。显然我已经掩盖了真正的配置细节。

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

如果有用的话,这里是堆栈跟踪:

[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

编辑:添加服务参考后,我在 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>

尽管我现在遇到了一些其他问题,但我确实发现了如何更改绑定。
您可以像我一样将组织服务作为服务引用添加到您的项目中,然后像这样分配绑定:

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

传递给自定义绑定的字符串只是从配置中获取的名称:

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

编辑:后来我发现没有必要更改绑定。该错误似乎是由无效的安全令牌引起的。我更改了生成安全令牌的方式以使用 passwordgrant_type,错误自行消失。