You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux/Mac下通过Dataverse.Client.Dynamics连接本地Dynamics 365 v9.1

问题说明
  • 适用环境:CRM Dynamics 365 v9.1 本地部署版(on-premise)
  • 支持运行操作系统:Linux、Mac OS

微软官方为Dynamics 365 v9.x提供的传统NuGet SDK包仅支持.Net Framework,不兼容.Net Core/5/6版本;目前另有官方预览版NuGet包Microsoft.PowerPlatform.Dataverse.Client.Dynamics,官方文档标注可支持.Net Core/5/6版本。

当前正在开发对接该版本CRM的.Net 6应用,后续将打包发布为Docker镜像。现阶段已通过Dynamics Web API实现通信:创建配置了NTLM认证的HttpClient,连接所用的账号密码存储在系统环境变量中,该方案在Mac OS下运行正常,实现代码如下:

static HttpClient CreateCrmHttpClient(string domain, string crmWebApiUrl, string authType, string crmLogin, 
    string crmPassword, Guid? callerId)
{
    var uri = new Uri(crmWebApiUrl);
    var credentialsCache = new CredentialCache
        {{uri, authType, new NetworkCredential(crmLogin, crmPassword, domain)}};

    var handler = new HttpClientHandler {Credentials = credentialsCache};

    var httpClient = new HttpClient(handler) {BaseAddress = uri, Timeout = new TimeSpan(0, 2, 0)};

    httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
    httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
    httpClient.DefaultRequestHeaders.Add("Prefer", "odata.include-annotations=\"*\"");

    if (callerId != null)
    {
        httpClient.DefaultRequestHeaders.Add("MSCRMCallerID", callerId.Value.ToString());
    }
    return httpClient;
}

调用示例:

string domain = "MyCompany";
string crmWebApiUrl = "https://crm-dev.MyCompany.ru:456/MyCompany/api/data/v9.1/";
string crmLogin = Environment.GetEnvironmentVariable("CrmLogin");
string crmPassword = Environment.GetEnvironmentVariable("CrmPassword");
Guid callerId = Guid.Parse("81CF7EFF-A996-44C2-8710-06E8177586C2"); // J.Smith
string authType = "NTLM";    

using (var httpClient = CreateCrmHttpClient(domain, crmWebApiUrl, authType, crmLogin, crmPassword, callerId)) {
  // 执行业务逻辑
}

目前希望改用Microsoft.PowerPlatform.Dataverse.Client.Dynamics包实现与CRM的通信,但遇到连接问题:该包未直接提供NTLM认证的连接能力,尝试多种官方示例给出的连接方式均未成功。需要可在Linux或Mac环境下正常运行的、通过Microsoft.PowerPlatform.Dataverse.Client.Dynamics包连接本地部署CRM Dynamics 365 v9.1的可运行代码示例。

可行解决方案

核心实现逻辑:Microsoft.PowerPlatform.Dataverse.Client.Dynamics 1.0.9及以上版本支持自定义HttpClient注入,可以直接复用已经验证跨平台可用的NTLM认证HttpClientHandler配置,不需要依赖SDK内置的Windows专属SSPI认证实现,即可在Linux/Mac环境正常连接。

前置准备

安装版本号不低于1.0.9的Microsoft.PowerPlatform.Dataverse.Client.Dynamics NuGet包,推荐使用1.0.14及以上的预览版本,低版本未开放自定义HttpClient注入接口,无法实现跨平台NTLM认证。

实现代码

using Microsoft.PowerPlatform.Dataverse.Client;
using Microsoft.Xrm.Sdk.Query;
using System.Net;
using System.Net.Http.Headers;

static ServiceClient CreateCrmDataverseClient(string domain, string crmOrgRootUrl, string authType, string crmLogin, 
    string crmPassword, Guid? callerId)
{
    var orgUri = new Uri(crmOrgRootUrl);
    // 复用已验证可用的NTLM认证凭证配置
    var credentialsCache = new CredentialCache
    {
        {orgUri, authType, new NetworkCredential(crmLogin, crmPassword, domain)}
    };
    var ntlmHandler = new HttpClientHandler 
    {
        Credentials = credentialsCache
        // 测试环境如果是自签名SSL证书,可临时放开下一行配置跳过证书验证,生产环境建议部署合法可信证书
        // ServerCertificateCustomValidationCallback = (_, _, _, _) => true
    };

    // 初始化Dataverse客户端,注入配置好NTLM认证的HttpClient
    var serviceClient = new ServiceClient(orgUri, async (_, _) => 
    {
        return await Task.FromResult(new HttpClient(ntlmHandler)
        {
            Timeout = TimeSpan.FromMinutes(2)
        });
    }, disposeHttpClient: true);

    // 配置通用请求头
    serviceClient.HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    serviceClient.HttpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
    serviceClient.HttpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
    serviceClient.HttpClient.DefaultRequestHeaders.Add("Prefer", "odata.include-annotations=\"*\"");

    // 配置模拟调用用户ID
    if (callerId != null)
    {
        serviceClient.CallerId = callerId.Value;
    }

    // 校验连接状态
    if (!serviceClient.IsReady)
    {
        throw new InvalidOperationException($"CRM连接失败: {serviceClient.LastError}", serviceClient.LastException);
    }
    return serviceClient;
}

调用示例

string domain = "MyCompany";
// 注意此处传入CRM组织根地址即可,不需要带/api/data/v9.1后缀,SDK会自动拼接Web API路由
string crmOrgRootUrl = "https://crm-dev.MyCompany.ru:456/MyCompany/";
string crmLogin = Environment.GetEnvironmentVariable("CrmLogin");
string crmPassword = Environment.GetEnvironmentVariable("CrmPassword");
Guid callerId = Guid.Parse("81CF7EFF-A996-44C2-8710-06E8177586C2"); // J.Smith
string authType = "NTLM";    

using (var serviceClient = CreateCrmDataverseClient(domain, crmOrgRootUrl, authType, crmLogin, crmPassword, callerId)) 
{
    // 测试连接:查询第一条客户记录
    var testQuery = new QueryExpression("account")
    {
        ColumnSet = new ColumnSet("name"),
        TopCount = 1
    };
    var firstAccount = serviceClient.RetrieveMultiple(testQuery).Entities.FirstOrDefault();
    Console.WriteLine($"连接验证成功,第一条客户记录名称:{firstAccount?.GetAttributeValue<string>("name")}");
    
    // 后续执行业务逻辑
}

注意事项

  • Linux环境(含Docker容器部署)需要提前安装NTLM认证依赖组件:基于Debian/Ubuntu的基础镜像需要在Dockerfile中执行apt-get update && apt-get install -y gss-ntlmssp,基于RHEL/CentOS的基础镜像执行yum install -y gss-ntlmssp,否则会抛出NTLM认证不支持的异常。
  • 不要使用SDK内置的连接字符串配置NTLM认证,内置NTLM实现依赖Windows系统的SSPI接口,跨平台环境无法正常运行,必须走自定义HttpClient注入的方式。
  • 传入ServiceClient的地址必须是CRM组织根地址,不要带Web API版本路由后缀,否则会出现404错误。

内容的提问来源于stack exchange,提问作者Andrey Bushman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 23:57:19