Monday, September 2, 2019

c# extension method to retrieve documents from Dynamics Ax and expose them to a WebApi via a repository class

As an introduction let me show you a piece of X++ to get a document.

You can find much more if you google it.

static void JobEF_DocumentSearch(Args _args)
{
    Notes notes = "";
    DocuRef docuRefTmp;
    HcmDiscussion hcmDiscussion;
    DocuRefSearch docuRefSearchTmp;
    DocuTypeId docuTypeId;
    FilePath filePath, filePathGeneric, path;

    hcmDiscussion = HcmDiscussion::findByDiscussionWorker('000024', HcmWorker::findByPersonnelNumber('2002450').RecId);
    if ( ! hcmDiscussion ) return;


    //docuRefSearchTmp = DocuRefSearch::newCommon( hcmDiscussion );
    //filter per document type
    docuTypeId = 'Appraisal';
    docuRefSearchTmp = DocuRefSearch::newDocuTypeId(hcmDiscussion, docuTypeId);

    filePathGeneric = Docu::archivePath(curExt());
    filePath = DocuType::find(docuTypeId).ArchivePath;

    info(filePathGeneric);
    info(filePath);

    while ( docuRefSearchTmp.next() )
    {
        docuRefTmp = docuRefSearchTmp.docuRef();

        notes = docuRefTmp.docuValue().FileName;
        path = docuRefTmp.path();
        info(strFmt('%1 --- %2', path, notes));
    }
}

now let me show you how we can do the same from c# using proxy objects

to open a session i will use the code described in this post, read it first:
https://enricoariel.blogspot.com/2019/08/proxy-classes-for-net-interop-to-x.html

step1: create an extension class

using System;
using System.Collections.Generic;
using Microsoft.Dynamics.AX.Framework.Linq.Data;
using U23 = Microsoft.Dynamics.AX.ManagedInterop;
using U22 = Microsoft.Dynamics.AX.Framework.Linq.Data;

namespace MydDynamicsIntegration.DynamicsCommon
{
    public static class GenericRecord
    {
        public static List<DocuRefProperties> GetAttachments<T>(this T axTable, string docuTypeId = null) where T : Common
        {
            var ret = new List<DocuRefProperties>();

            var docuRefSearchTmp = docuTypeId == null ? DocuRefSearch.newCommon(axTable) : DocuRefSearch.newDocuTypeId(axTable, docuTypeId);

            while (docuRefSearchTmp.next())
            {
                DocuRef docuRefTmp = docuRefSearchTmp.docuRef();
                var docuref = new DocuRefProperties
                {
                    RecId = docuRefTmp.RecId,
                    ValueRecId = docuRefTmp.ValueRecId,
                    Path = docuRefTmp.path(),
                    FileName = docuRefTmp.docuValue().fileName(),
                    Description = docuRefTmp.Name,
                    TypeId = docuRefTmp.TypeId,
                    CreatedDateTime = (DateTime) docuRefTmp.CreatedDateTime
                };
                ret.Add(docuref);
            }

            return ret;
        }

        public class DocuRefProperties
        {
            public long RecId { get; set; }
            public long ValueRecId { get; set; }
            public string Path { get; set; }
            public string FileName { get; set; }
            public string Description { get; set; }
            public string TypeId { get; set; }
            public DateTime CreatedDateTime { get; set; }
        }
    }
}

Note: import the relevant proxy objects in your .Net project

step2: create the repository

in this example I made a repository for documents attached to HcmDiscussion

DiscussionRepository.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using MydDynamicsIntegration.DynamicsCommon;
using MydDynamicsIntegration.Models;
using MydDynamicsIntegration.Repositories.Interfaces;

namespace MydDynamicsIntegration.Repositories.Implementation
{
    public class DiscussionRepository : IAmDiscussionRepository
    {
        private const string AppraisalDocuTypeId = "Appraisal";
        public List<Attachment> GetAttachments(string discussionId, string personnelNumber)
        {
            using (var axSession = new AxSessionManager())
            {
                axSession.OpenConnection();

                var workerRecId = HcmWorker.findByPersonnelNumber(personnelNumber).RecId;
                var discussion = HcmDiscussion.findByDiscussionWorker(discussionId, workerRecId);

                return discussion.GetAttachments(AppraisalDocuTypeId).Select(attachment => new Attachment
                {
                    RecId = attachment.RecId,
                    ValueRecId = attachment.ValueRecId,
                    Path = attachment.Path,
                    FileName = attachment.FileName,
                    Description = attachment.Description,
                    TypeId = attachment.TypeId,
                    CreatedDateTime = attachment.CreatedDateTime
                }).ToList();
            }
        }       
    }
}

Attachment.cs:

using System;

namespace MydDynamicsIntegration.Models
{
    public class Attachment
    {
        public long RecId { get; set; }
        public long ValueRecId { get; set; }
        public string Path { get; set; }
        public string FileName { get; set; }
        public string Description { get; set; }
        public string TypeId { get; set; }
        public DateTime CreatedDateTime { get; set; }
    }
}

I omitted to copy the IAmDiscussionRepository, but is quite intuitive.

step3: use the repository in the WebApi controller class:

        [Authorize]
        [GET("api/worker/{personnelNumber}/discussions/{discussionId}/attachments/{attachmentRecId}")]
        [HttpGet]
        public HttpResponseMessage Attachment(string personnelNumber, string discussionId, long attachmentRecId)
        {
            var attachment = _discussionRepository.GetAttachment(discussionId, personnelNumber, attachmentRecId);

            return attachment.IsNullOrEmptyObject() ?
                Request.CreateErrorResponse(HttpStatusCode.NotFound, HttpStatusCode.NotFound.ToStringWithSpaces()) : 
                Request.CreateResponse(HttpStatusCode.OK, _attachmentMapping.Map(attachment));
        }

Note: in the webApi project I used Ninject and Attribute routing.

finally here the mapping class:

using System.Collections.Generic;
using System.IO;
using System.Linq;
using IDHGroup.DynamicsApi.CIT.Services.Interfaces;
using IDHGroup.DynamicsDataTransfer.CIT.Models.Dtos.RequestView;
using MydDynamicsIntegration.Models;

namespace IDHGroup.DynamicsApi.CIT.Services.Implementations
{
    public class AttachmentMappingService : IAmAttachmentMapping
    {
        public List<AttachmentViewDto> Map(List<Attachment> attachments)
        {
            return attachments.Select(MapAttachmentViewDto).ToList();
        }

        public AttachmentViewDto Map(Attachment attachment)
        {
            return MapAttachmentViewDto(attachment);
        }

        private static AttachmentViewDto MapAttachmentViewDto(Attachment attachment)
        {
            return new AttachmentViewDto
            {
                RecId = attachment.RecId,
                FilePath = Path.Combine(attachment.Path, attachment.FileName),
                Description = attachment.Description,
                TypeId = attachment.TypeId,
                CreatedDateTime = attachment.CreatedDateTime
            };
        }
    }
}

No comments:

Post a Comment