Skip to main content

Notifications

Announcements

No record found.

Finance | Project Operations, Human Resources, ...
Answered

Custom service

(0) ShareShare
ReportReport
Posted on by 31
Hello guys, I am creating a custom service that submits items to workflow, not sure if I am doing it right. I have created a request class
[DataContractAttribute]class ARFWorkflowRequestClass{    DataAreaId dataAreaId;    //RecID recID;    Main_AssetRequestID requestID;    [DataMemberAttribute]    public DataAreaId parmDataAreaId(DataAreaId _dataAreaId = dataAreaId)    {        dataAreaId = _dataAreaId;        return dataAreaId;    }    [DataMemberAttribute]    public Main_AssetRequestID parmMain_AssetRequestID(Main_AssetRequestID _requestID = requestID)    {        requestID = _requestID;        return requestID;    }
and a response class
[DataContractAttribute]class ARFWorkflowResponseClass{    boolean result;    List errors;    [DataMemberAttribute]    public boolean parmResult(boolean _result = result)    {        result = _result;        return result;    }    [DataMemberAttribute]    public List parmErrors(List _errors = errors)    {        errors = _errors;        return errors;    }}
and a service class
class ARFWorkflowServiceClass{    public ARFWorkflowResponseClass submitToWorkflow(ARFWorkflowRequestClass contract)    {        boolean result = true;        List errors = new List(Types::String);         // Retrieve data from the request object        DataAreaId dataAreaId = contract.parmDataAreaId();        Main_AssetRequestID requestID;        Main_AssetRelocationHeader main_AssetRelocationHeader;        boolean submitted = false; // Initialize as false        WorkflowVersionTable workflowVersionTable;        // Find the workflow configuration        workflowVersionTable = Workflow::findWorkflowConfigToActivateForType(            WorkflowTypeStr(Main_ARFWorkflowType), // Replace with your specific workflow type            main_AssetRelocationHeader.RecId,            main_AssetRelocationHeader.TableId);        // Perform the workflow submission logic here        if (workflowVersionTable)        {            // Submit to workflow            Workflow::activateFromWorkflowType(                WorkflowTypeStr(Main_ARFWorkflowType),                main_AssetRelocationHeader.RecId,                /Auto submit to workflow/,                false,                curUserId());            // Update the workflow state            main_AssetRelocationHeader.ARFWorkflowStatus = ARFWorkflowStatus::Submitted;            main_AssetRelocationHeader.update();            submitted = true;        }         // Populate the response object with the results        ARFWorkflowResponseClass response = new ARFWorkflowResponseClass();        response.parmErrors(errors);        response.parmResult(result);         return response;    }}
It builds successfully, but I am not sure my service class is actually pointing to the right information.
  • capedcrusader Profile Picture
    capedcrusader 31 on at
    Custom service
    Thanks, Martin for your help. Very grateful
  • Verified answer
    Martin Dráb Profile Picture
    Martin Dráb 230,466 Most Valuable Professional on at
    Custom service
    Good to hear!
     
    Let me just suggest some changes in your code:
    public ARFWorkflowResponseClass submitToWorkflow(ARFWorkflowRequestClass _request)
    {
        var response = new ARFWorkflowResponseClass();
        
        changecompany(_request.parmDataAreaId())
        {
            System.Exception ex;
        
            try
            {
                boolean submitted; // No need to explicitly initialize it to false. It's the default value.
                
                ttsbegin; // Start a transaction
    
                Main_AssetRelocationHeader main_AssetRelocationHeader;
    
                select forupdate main_AssetRelocationHeader
                    where main_AssetRelocationHeader.RequestID == _request.parmRequestID() &&
                          main_AssetRelocationHeader.DataAreaId == _request.parmDataAreaId() &&
                          main_AssetRelocationHeader.ARFWorkflowStatus == ARFWorkflowStatus::Draft;
    
                if (main_AssetRelocationHeader)
                {
                    // Find the workflow configuration
                    WorkflowVersionTable workflowVersionTable = Workflow::findWorkflowConfigToActivateForType(
                        WorkflowTypeStr(Main_ARFWorkflowType),
                        main_AssetRelocationHeader.RecId,
                        main_AssetRelocationHeader.TableId);
    
                    if (workflowVersionTable)
                    {
                        // Submit to workflow
                        Workflow::activateFromWorkflowType(
                            WorkflowTypeStr(Main_ARFWorkflowType),
                            main_AssetRelocationHeader.RecId,
                            "Auto submit to workflow",
                            true,
                            curUserId());
    
                        // Update the workflow state
                        main_AssetRelocationHeader.ARFWorkflowStatus = ARFWorkflowStatus::Submitted;
                        main_AssetRelocationHeader.update();
    
                        submitted = true;
                    }
                }
    
                ttscommit; // Commit the transaction
    
                if (submitted)
                {
                    info("Invoice submitted to workflow.");
                    response.parmSuccess(true);
                }
                else
                {
                    info("Invoice not eligible for submission to workflow.");
                    //TODO: Is it correct that you leave the response object empty?
                }
            }
            catch (ex)
            {
                response.parmSuccess(true); //TODO: didn't you mean false?
                response.parmErrorMessage(ex.ToString());
            }
        }
    
        return response;
    }
  • Peta Peta Profile Picture
    Peta Peta 59 on at
    Custom service
    Thanks Martin. i have been able to get it ton work. this is my sample code that takes 2 parameters and uses it to identify the record to submit to workflow
     
    using Microsoft.DynamicsOnline.Infrastructure.Components.SharedServiceUnitStorage;
    using System.IO;
    
    public class ARFWorkflowServiceClass
    {
        public ARFWorkflowResponseClass SubmitToWorkflow(ARFWorkflowRequestClass _request)
        {
            var response = new ARFWorkflowResponseClass();
            changecompany(_request.parmDataAreaId())
            
            try
            {
                
                WorkflowVersionTable workflowVersionTable;
                Main_AssetRelocationHeader main_AssetRelocationHeader;
                boolean submitted = false; // Initialize as false
    
                ttsbegin; // Start a transaction
    
                select forupdate main_AssetRelocationHeader
                    where main_AssetRelocationHeader.RequestID == _request.parmRequestID() &&
                          main_AssetRelocationHeader.DataAreaId == _request.parmDataAreaId() &&
                          main_AssetRelocationHeader.ARFWorkflowStatus == ARFWorkflowStatus::Draft;
    
                if (main_AssetRelocationHeader)
                {
                    // Find the workflow configuration
                    workflowVersionTable = Workflow::findWorkflowConfigToActivateForType(
                        WorkflowTypeStr(Main_ARFWorkflowType),
                        main_AssetRelocationHeader.RecId,
                        main_AssetRelocationHeader.TableId);
    
                    if (workflowVersionTable)
                    {
                        // Submit to workflow
                        Workflow::activateFromWorkflowType(
                            WorkflowTypeStr(Main_ARFWorkflowType),
                            main_AssetRelocationHeader.RecId,
                            "Auto submit to workflow",
                            true,
                            curUserId());
    
                        // Update the workflow state
                        main_AssetRelocationHeader.ARFWorkflowStatus = ARFWorkflowStatus::Submitted;
                        main_AssetRelocationHeader.update();
    
                        submitted = true;
                    }
                }
    
                ttscommit; // Commit the transaction
    
                if (submitted)
                {
                    info("Invoice submitted to workflow.");
                    response.parmSuccess(true);
                }
                else
                {
                    info("Invoice not eligible for submission to workflow.");
                }
            }
            catch (Exception::CLRError)
            {
                System.Exception interopException = CLRInterop::getLastException();
    
                response.parmSuccess(true);
                response.parmErrorMessage(interopException.ToString());
            }
    
            return response;
        }
    
    }
     
  • Martin Dráb Profile Picture
    Martin Dráb 230,466 Most Valuable Professional on at
    Custom service
    ARFWorkflowServiceClass indeed doesn't have any main() method. But I have no idea where you're trying to use it and why. Also, it seems that you get some code executed anyway.
     
    Where are the errors thrown? Finding this type information is the point of debugging.
  • capedcrusader Profile Picture
    capedcrusader 31 on at
    Custom service
    Thanks Martin, I debugged and this is what I got
    - Cannot find method with signature: 'public static void Main(Args args)' on class ARFWorkflowServiceClass'
    - Workflow configuration with type name Main_ARFWorkflowType was not found.
    - The expected type was str, but the encountered type was class.
     
    This is my service class code:

     
    class ARFWorkflowServiceClass
    {
        public ARFWorkflowResponseClass submitToWorkflow(ARFWorkflowRequestClass contract)
        {
            boolean result = true;
            List errors = new List(Types::String);
     
            // Retrieve data from the request object
            DataAreaId dataAreaId = contract.parmDataAreaId();
            Main_AssetRequestID requestID = contract.parmMain_AssetRequestID();
            
            boolean submitted = false; // Initialize as false
            WorkflowVersionTable workflowVersionTable;
            ARFWorkflowResponseClass response = new ARFWorkflowResponseClass(); // Create response object
            try
            {
                Main_AssetRelocationHeader main_AssetRelocationHeader;
                select firstonly requestID from main_AssetRelocationHeader
                    where main_AssetRelocationHeader.requestID == requestID;
                if (1 == 1)
                {
                    // Declare a new MCRHoldCodeTrans record (apply hold code)
                    Main_AssetRelocationHeader mmain_AssetRelocationHeader;
                    ttsbegin;
                    Workflow::activateFromWorkflowType(
                        WorkflowTypeStr(Main_ARFWorkflowType),
                        main_AssetRelocationHeader.RecId,
                        "Auto submit to workflow",
                        false,
                        curUserId());
     
                    // Update the workflow state
                    main_AssetRelocationHeader.ARFWorkflowStatus = ARFWorkflowStatus::Submitted;
                    main_AssetRelocationHeader.update();
     
                    submitted = true;
                    ttscommit;
                }
                else
                {
                    // If not submitted
                    throw error(strFmt("failed, main_AssetRelocationHeader.ARFWorkflowStatus"));
                }
            }
            catch
            {
                result = false;
                //store errors
                SysInfologEnumerator enumerator;
                SysInfologMessageStruct msgStruct;
     
                enumerator = SysInfologEnumerator::newData(infolog.cut());
     
                while (enumerator.moveNext())
                {
                    msgStruct = new SysInfologMessageStruct(enumerator.currentMessage());
                    //str errorMessage = strFmt("Error occurred: %1. main_AssetRelocationHeader: %2", msgStruct.message(), main_AssetRelocationHeader.ARFWorkflowStatus);
     
                    errors.addEnd(msgStruct);
                }
                 
                //clear infolog
                infolog.clear();
            }
            // Populate the response object with the results
            response.parmErrors(errors);
            response.parmResult(submitted);
            return response;
        }
    }
  • capedcrusader Profile Picture
    capedcrusader 31 on at
    Custom service
    Thank Martin, I will try that and see what I have.
     
  • Martin Dráb Profile Picture
    Martin Dráb 230,466 Most Valuable Professional on at
    Custom service
    Yes, you can debug it; it normal X++ code. Simply attach debugger to the web server process (IIS or IISExpress) and make the request.
     
    Note that I don't see the error in your reply.
  • capedcrusader Profile Picture
    capedcrusader 31 on at
    Custom service
    Thanks Marti, I am not sure on how to even debug this, do I debug as I would normal class? 
    I have been running it in postman and I end up with this error : 

    Response:

    {

        "$id": "1",

        "parmResult": false,

        "parmErrors": [

            "failed"

        ]

    }

  • Martin Dráb Profile Picture
    Martin Dráb 230,466 Most Valuable Professional on at
    Custom service
    Do you have any problem with your service? If so, please describe it. We can't give you a solution if we don't know what problem you have.
     
    If you know that something is wrong but you have no idea where your code fails, don't forget that you have the debugger at your disposal.

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Congratulations 2024 Spotlight Honorees

Kudos to all of our 2024 community stars! 🎉

Meet the Top 10 leaders for December

Congratulations to our December super stars! 🥳

Start Your Super User Journey

Join the ranks of our community heros! 🦹

Leaderboard

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 291,735 Super User 2024 Season 2

#2
Martin Dráb Profile Picture

Martin Dráb 230,466 Most Valuable Professional

#3
nmaenpaa Profile Picture

nmaenpaa 101,156

Leaderboard

Product updates

Dynamics 365 release plans