3CX Call Flow Designer - NullReferenceException in external C# script

Discussion in 'Call Flow Designer' started by BrechtD, Apr 16, 2018 at 1:26 PM.

  1. BrechtD

    Joined:
    Apr 8, 2018
    Messages:
    10
    Likes Received:
    0
    Hello everyone

    I am trying to create a call flow application which should make it possible for my employees to login to our queues by entering the queunumber. After entering the queenumber, they should enter their ID and pin number to authorize themselves. I am having the problem that my external C# script keeps complaining about a NullreferenceException (I know what this means) and I have not clue where there could be a problem in my code.

    Here is the error ouput:

    ExternalCodeExecutionComponent - CallID QQNQMAGBIZKR] Trace: Start executing component with objectType='QueueDesign.CustomQueueLogin' - methodName='GetFreeIndexAndExpandIfNecessary'
    18/04/16 13:48:33.287|100030| Err|10|0018|: PlugIn[CallQueueForwarding - Callflow - MainFlow - CallID QQNQMAGBIZKR] ERROR: Error executing last component: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NullReferenceException: Object reference not set to an instance of an object.

    at QueueDesign.CustomQueueLogin.GetQueueMembersOfQueue(String queuenumber)
    at QueueDesign.CustomQueueLogin.GetFreeIndexAndExpandIfNecessary(String memberextension, String queuenumber)
    --- End of inner exception stack trace ---
    at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
    at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
    at CallQueueForwarding.ExternalCodeExecutionComponent.executeStart(QMExtendAPI iface, String id)
    at CallQueueForwarding.ExternalCodeExecutionComponent.Start(QMExtendAPI iface, CallQueue callQueue, QueueCall queueCall, ActiveConnection activeConnection, TimerManager timerManager, Dictionary`2 variableMap, TempWavFileManager tempWavFileManager, PromptQueue promptQueue)
    at CallQueueForwarding.SequenceContainerComponent.Start(QMExtendAPI iface, CallQueue callQueue, QueueCall queueCall, ActiveConnection activeConnection, TimerManager timerManager, Dictionary`2 variableMap, TempWavFileManager tempWavFileManager, PromptQueue promptQueue)
    at CallQueueForwarding.ConditionalComponent.Start(QMExtendAPI iface, CallQueue callQueue, QueueCall queueCall, ActiveConnection activeConnection, TimerManager timerManager, Dictionary`2 variableMap, TempWavFileManager tempWavFileManager, PromptQueue promptQueue)
    at CallQueueForwarding.SequenceContainerComponent.Start(QMExtendAPI iface, CallQueue callQueue, QueueCall queueCall, ActiveConnection activeConnection, TimerManager timerManager, Dictionary`2 variableMap, TempWavFileManager tempWavFileManager, PromptQueue promptQueue)
    at CallQueueForwarding.SequenceContainerComponent.OnTimeout(QMExtendAPI iface, CallQueue callQueue, QueueCall queueCall, ActiveConnection activeConnection, TimerManager timerManager, Dictionary`2 variableMap, TempWavFileManager tempWavFileManager, PromptQueue promptQueue, Object state)
    at CallQueueForwarding.ConditionalComponent.OnTimeout(QMExtendAPI iface, CallQueue callQueue, QueueCall queueCall, ActiveConnection activeConnection, TimerManager timerManager, Dictionary`2 variableMap, TempWavFileManager tempWavFileManager, PromptQueue promptQueue, Object state)
    at CallQueueForwarding.SequenceContainerComponent.OnTimeout(QMExtendAPI iface, CallQueue callQueue, QueueCall queueCall, ActiveConnection activeConnection, TimerManager timerManager, Dictionary`2 variableMap, TempWavFileManager tempWavFileManager, PromptQueue promptQueue, Object state)
    at CallQueueForwarding.LoopComponent.OnTimeout(QMExtendAPI iface, CallQueue callQueue, QueueCall queueCall, ActiveConnection activeConnection, TimerManager timerManager, Dictionary`2 variableMap, TempWavFileManager tempWavFileManager, PromptQueue promptQueue, Object state)
    at CallQueueForwarding.SequenceContainerComponent.OnTimeout(QMExtendAPI iface, CallQueue callQueue, QueueCall queueCall, ActiveConnection activeConnection, TimerManager timerManager, Dictionary`2 variableMap, TempWavFileManager tempWavFileManager, PromptQueue promptQueue, Object state)
    at CallQueueForwarding.ConditionalComponent.OnTimeout(QMExtendAPI iface, CallQueue callQueue, QueueCall queueCall, ActiveConnection activeConnection, TimerManager timerManager, Dictionary`2 variableMap, TempWavFileManager tempWavFileManager, PromptQueue promptQueue, Object state)
    at CallQueueForwarding.Callflow.ProcessTimeout(Object state)

    Here is my code of my script:

    using System;
    using TCX.Configuration;

    namespace QueueDesign {

    public class CustomQueueLogin
    {

    public Queue GetQueueByExtension(string queuenumber) {
    return (Queue)PhoneSystem.Root.GetDNByNumber(queuenumber);
    }

    public DN[] GetQueueMembersOfQueue(string queuenumber) {
    return GetQueueByExtension(queuenumber).Members;
    }

    public void AddMemberToQueue(string memberextension, string queuenumber) {
    DN[] queuemembers = GetQueueMembersOfQueue(queuenumber);
    int freePos = GetFreeIndexAndExpandIfNecessary(memberextension, queuenumber);
    Extension extAgent = (Extension)PhoneSystem.Root.GetDNByNumber(memberextension);
    queuemembers[freePos] = extAgent;
    extAgent.QueueStatus = QueueStatusType.LoggedIn;
    GetQueueByExtension(queuenumber).Save();


    }

    public int GetFreeIndexAndExpandIfNecessary(string memberextension, string queuenumber) {
    DN[] queuemembers = GetQueueMembersOfQueue(queuenumber);
    int currentPos;
    if (Array.IndexOf(queuemembers, null) != -1)
    {
    currentPos = Array.IndexOf(queuemembers, null);
    }
    else
    {
    DN[] old = new DN[queuemembers.Length];
    Array.Copy(queuemembers, old, queuemembers.Length);
    queuemembers = new DN[queuemembers.Length * 2];
    Array.Copy(old, queuemembers, old.Length);
    currentPos = Array.IndexOf(queuemembers,null);
    }
    return currentPos;
    }

    public void RemoveMemberFromQueue(string memberextension, string queuenumber) {
    Extension extAgent = (Extension)PhoneSystem.Root.GetDNByNumber(memberextension);
    DN[] QueueMembers = GetQueueMembersOfQueue(queuenumber);
    if (CheckIfMemberIsInQueue(memberextension, queuenumber)) {
    int agentIndex = Array.IndexOf(QueueMembers, extAgent);
    extAgent.QueueStatus = QueueStatusType.LoggedOut;
    QueueMembers[agentIndex] = null;
    GetQueueByExtension(queuenumber).Save();

    }
    }

    public bool CheckIfMemberIsInQueue(string memberextension, string queuemember) {
    Extension extAgent = (Extension) PhoneSystem.Root.GetDNByNumber(queuemember);
    return Array.IndexOf(GetQueueMembersOfQueue(queuemember), extAgent) != -1;

    }
    }
    }

    Next to this, I'll add some pictures to show my application so far and where I am using this script:

    upload_2018-4-16_14-24-4.png
    upload_2018-4-16_14-24-27.png

    Is there anyone who might have an idea ??
     
  2. edossantos

    edossantos Support Team
    Staff Member 3CX Support

    Joined:
    Jun 27, 2007
    Messages:
    893
    Likes Received:
    66
    From the stack trace, the exception is being thrown here:
    Code:
    public DN[] GetQueueMembersOfQueue(string queuenumber) {
    return GetQueueByExtension(queuenumber).Members;
    }
    And that means that "GetQueueByExtension(queuenumber)" is returning null...

    Kind regards.
    Ernesto .
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  3. edossantos

    edossantos Support Team
    Staff Member 3CX Support

    Joined:
    Jun 27, 2007
    Messages:
    893
    Likes Received:
    66
    You're probably passing a wrong or empty queue extension number...
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  4. Brecht Dedecker

    Joined:
    Feb 22, 2018
    Messages:
    8
    Likes Received:
    0
    Ok thx for the reply, don't know if my code is well written according to you ? I mean , do you now if it's written with the right properties/methods for using the 3cx API correctly?