viernes, 24 de junio de 2016

Calling the DocumentHandling service

Today we're obtaining files via WCF web services from Visual Studio, the DocumentHandling service to be exact.
Activate the standard AX DocumentHandling service!
Now remember that these files are all available via a shared directory, and so before launching into using this service do investigate if it's worth obtaining the directory from DocuType, file name and file type from the DocuValue entity

From Visual Studio register the service from the WSDL URI and add the service reference to your project.  Remember that we will need to change the server and port in our project when it's time to move our project reference to the production environment.

Now all you would need to do is find a RecId from the DocuRef entity.  In the example below we can see a document associated with an Item Lot number:
Document Management is activated for multiple entities from Lots to Sales Invoices

Pseudo code below.  I have a paranoia with the Client object where we could leave connections open and therefore no garbage collection. Adapt the below to your requirements.:
using XXXProj.DocumentHandlingServiceReference;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections;
using System.Configuration;
using System.IO;
using System.Text;

/// <summary>
/// Download PDF Quality Certificate associated with lot '140801-033711'.
/// RecId 5637152126 (DEVELOPMENT environment)
/// </summary>
[TestMethod]
public void TestCertificate_GetPDF1()
{
  // We have a doc associated with InventBatch, lot '140801-033711' - See table DocuRef
  Int64 CERT_RECID1 = 5637152126;
        
  DocumentFileDataContract docuContract = new DocumentFileDataContract();

  // Create a client only for as long as we need to.  Note the exception handling with client.
  using (DocumentHandlingServiceClient client = new DocumentHandlingServiceClient())
  {
    try
    {
      // *NO* company context for Document Management
      //CallContext context = this.setCompanyContext("CONT");

      //Execute as another user, and he's called 'Bob'
      RunAsBob(client.ClientCredentials);

      // Set the AX AIF service endpoint.
      client.Endpoint.Address = setAXEnvironment(client.Endpoint.Address);
      
      // Obtain file, String format, encoded in base 64
      docuContract = client.getFile(null, CERT_RECID1);
      client.Close();
    }
    catch (System.ServiceModel.CommunicationException e)
    {
      client.Abort();
      Assert.Fail(e.ToString());
    }
    catch (TimeoutException e)
    {
      client.Abort();
      Assert.Fail(e.ToString());
    }
    catch (Exception e)
    {
      client.Abort();
      Assert.Fail(e.ToString());
    }
  }

  Assert.IsNotNull(docuContract);
  Assert.IsTrue(docuContract.RecId > 0, "Document not found - " + CERT_RECID1.ToString());
  Assert.IsNotNull(docuContract.Attachment, "Document is empty");

  // Let's save the document in a temporary directory
  string documentAttachment = docuContract.Attachment;
  string file = "C:\\TEMP\\file.pdf";
  byte[] ba = System.Convert.FromBase64String(documentAttachment);
  System.IO.File.WriteAllBytes(file, ba);
}

Helper or shared methods:
using System.Configuration;
using System;
using System.ServiceModel;

/// <summary>
/// Execute as user 'Bob'.  Data saved in app.config xml file.
/// </summary>
/// <param name="clientCredentials"></param>
protected static void RunAsBob(System.ServiceModel.Description.ClientCredentials clientCredentials)
{
  clientCredentials.Windows.ClientCredential.Domain = ConfigurationManager.AppSettings["Domain"];
  clientCredentials.Windows.ClientCredential.UserName = ConfigurationManager.AppSettings["UserName"];
  clientCredentials.Windows.ClientCredential.Password = ConfigurationManager.AppSettings["Password"];
}

/// <summary>
/// Assign the environment's Host/Port.  Are we testing DEVELOPMENT or PRODUCTION?
/// e.h.: srvax2012:8202
/// </summary>
/// <param name="address">client.EndpointAddress</param>
/// <returns></returns>
protected static System.ServiceModel.EndpointAddress setAXEnvironment(System.ServiceModel.EndpointAddress address)
{
  var newUriBuilder = new UriBuilder(address.Uri);
  newUriBuilder.Host = ConfigurationManager.AppSettings["NEW_ENDPOINT_HOST"];
  newUriBuilder.Port = System.Int16.Parse(ConfigurationManager.AppSettings["NEW_ENDPOINT_PORT"]);
  address = new EndpointAddress(newUriBuilder.Uri, address.Identity, address.Headers);
  return address;
}

/// <summary>
/// Context - Select Company.  DataAreaId: CONT/CONZ/TEST/DAT/...
/// </summary>
/// <param name="dataAreaId"></param>
/// <returns></returns>
private CustPackingSlipServiceReference.CallContext setCompanyContext(String dataAreaId)
{
  CustPackingSlipServiceReference.CallContext context = new CustPackingSlipServiceReference.CallContext();
  context.Company = dataAreaId;
  context.MessageId = Guid.NewGuid().ToString();
  return context;
}

3 comentarios:

  1. I'm trying to use getFile(), but the Attachment property of my DocumentFileDataContract object is empty. Any ideas?

    ResponderEliminar
  2. Nope. Sorry. I'd try posting your question with the full code in https://community.dynamics.com/ax or http://stackoverflow.com
    My only suggestion is to double check the DocuRef RECID once more and if it does exist also check if the file actually exists. Can you download the file from your demo environment, for example? Good luck.

    ResponderEliminar
  3. Thanks for the response. It was my fault... I assumed attachments contained notes as well, it does not.

    ResponderEliminar