来自 SOAP 和 REST 客户端共享的 SOAP 响应的 HTTP Cookie 标头

Acumatica 的基于 SOAP 契约的 API 存在限制,允许仅为顶级实体下载附件。遗憾的是,任何尝试使用 GetFiles() 方法获取详细信息实体的附件都会导致错误没有屏幕绑定的实体不能用作顶级实体。告诉我们它只能用于顶层实体。 Web 服务端点中定义的级别实体。

GetFiles() 方法的另一个限制是它始终返回附加到实体的所有文件的内容。没有选项可以先检索文件名,然后决定从 Acumatica 下载哪些特定文件。

值得庆幸的是,有一种更好,更可控的方式来处理随基于合同的 REST API 提供的附件。作为基于合同的 REST API 导出的每个实体的一部分返回的 files 数组仅包含:

  • 文件名( 文件名属性)
  • 文件标识符( id 属性)
  • 超文本引用( href 属性),可以在以后用于下载文件内容

有关从 Web 服务端点获取附加到任何实体的文件列表并通过基于合同的 REST API 检索特定文件内容的示例,请查看 Acumatica 产品帮助

如果整个集成项目是使用基于 SOAP 契约的 API 开发的,那么如何下载附加到详细实体的文件?如下面的代码片段所示,可以将 SOAP 响应从 SOAP 响应传递到专门用于处理附件的 REST API 客户端:

using (var soapClient = new DefaultSoapClient())
{
    var address = new Uri("http://localhost/AcumaticaERP/entity/Default/6.00.001/");
    CookieContainer cookieContainer;
    using (new OperationContextScope(soapClient.InnerChannel))
    {
        soapClient.Login(login, password, null, null, null);
        string sharedCookie = WebOperationContext.Current.IncomingResponse.Headers["Set-Cookie"];
        cookieContainer = new CookieContainer();
        cookieContainer.SetCookies(address, sharedCookie);
    }
    try
    {
        var shipment = new Shipment()
        {
            ShipmentNbr = new StringSearch { Value = "001301" },
            ReturnBehavior = ReturnBehavior.OnlySpecified
        };
        shipment = soapClient.Get(shipment) as Shipment;

        var restClient = new HttpClient(
            new HttpClientHandler
            {
                UseCookies = true,
                CookieContainer = cookieContainer
            });
        restClient.BaseAddress = address;// new Uri("http://localhost/059678/entity/Default/6.00.001/");

        var res = restClient.GetAsync("Shipment/" + shipment.ID + "?$expand=Packages")
            .Result.EnsureSuccessStatusCode();
        var shipmentWithPackages = res.Content.ReadAsStringAsync().Result;

        JObject jShipment = JObject.Parse(shipmentWithPackages);
        JArray jPackages = jShipment.Value<JArray>("Packages");
        foreach (var jPackage in jPackages)
        {
            JArray jFiles = jPackage.Value<JArray>("files");
            string outputDirectory = ".\\Output\\";
            if (!Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }

            foreach (var jFile in jFiles)
            {
                string fullFileName = jFile.Value<string>("filename");
                string fileName = Path.GetFileName(fullFileName);
                string href = jFile.Value<string>("href");

                res = restClient.GetAsync(href).Result.EnsureSuccessStatusCode();
                byte[] file = res.Content.ReadAsByteArrayAsync().Result;
                System.IO.File.WriteAllBytes(outputDirectory + fileName, file);
            }
        }
    }
    finally
    {
        soapClient.Logout();
    }
}