no session has started!!

Jun 1, 2012 at 11:10 AM

Hi All,

Im using CCA for MSCRM 2011. Im integrating with a specific CTI Plateform. I replace the CTI Toolbar of CCA with a specific one. I implement the callAlerting and the CallSecces of that Toolbar. I created a WebApplication and a workflow to open the customer form when he call.

In the callSucess Event Im trying fo lanch the dynamic application but the CCA return to me an error: (Application Host: APPLICATION_HOST_ERR_LOADING_DYNAMIC_APP_NO_SESSION_EXIST:Unable to load non-global dynamic application.  No session has started.)

 

The CodeSource in the CallSucess Event:

bool success = true;
            if (!uiiDesktop.AppExistsInUI("Crm Customer View"))
                success = uiiDesktop.CreateDynamicApplication("Crm Customer View");
            if (success)
            {

                uiiDesktop.SetFocusOnApplication("Crm Customer View");

                RequestActionEventArgs args = new RequestActionEventArgs("Crm Customer View", "OpenCustomerForm", "");
                FireRequestAction(args);
            }

Thanks for Help

Jun 1, 2012 at 8:58 PM

Balhino,

Before you can launch a Dynamic Application, you have to create a session first.  There is an OpenSession method that takesa CustomerEntity & CallRefId parameter.  Once the session is started and loaded you can create the Dynamic Applications (if needed).   However, if you set your Uii Hosted Controls you should be able to let CCA open the session without having to create a Dynamic Application or Fire an action.

Also, I wouldn't start a session from the CTI Control.  Really, the best place for this is in the WpfCustomerSearch.cs control in CCA.  Have you written/updated the CtiConnector.cs, CallStateManager, AgentStateManager controls to work with your specific CTI platform?   The best way to do this is in the CtiConnector when a new call comes in is to raise the NewCallEvent from the CtiConnector.  From there it will bubble up into the CallStateManager and once you Raise the event from there it will execute the CtiLookupRequest Action in the WpfCustomerSearch control. 

The search control is where you setup the CustomerRecord, Context and ultimately where the session should open from.  Once you get through this part and you've set your Context correctly in your Uii Hosted Applications Default Action you can do this:

Url:  http://<crm_url>/<org_name>/main.aspx
QueryString:  etn=%CustomerTypeCode&pagetype=entityrecord&id=%CustomerId

The %CustomerTypeCode & %CustomerId correspond to variables in the Context object for the specific session.  Uii/CCA at runtime will substitute these 2 parameters with data from your Context object and CRM will open the appropriate page for you without having to use a Dynamic App or FireRequestAction.

Jeremy

Jun 6, 2012 at 10:25 AM

Hi Jeremy

Thanks for your reply.

In fact what I have done is the following:

First the new cti control is an ActiveX control (Hermes.net) and the CCA is a WPF tools, so to integrate the ActiveX toolbar I followed the steps described in the following link: (Hosting an ActiveX Control in WPF) http://msdn.microsoft.com/en-us/library/ms742735.aspx

 

I replaced the cticontrol with our specific toolbar. So the is no more the list of cti event of the old cticontrol. The new cti control has his own cti event like callAlerting , CallSuccess, CallTransfert…

And I tried to implement and dowing my own logic in every event specificly in the callAlerting to open the customerform of the caller in a dynamic application. For this I create a HAT project with a workflow to do this. to test the functionality Im using a fixed customerId to open his form the following is the code of CallAlerting event:

 

private void AX_CallSuccess(object sender, AxAgentLink._IToolbarEvents_CallSuccessEvent e)

     {

 

 

           Context context = new Uii.Csr.Context();

 

           context["CustomerID"] = "85405143-70E8-DD11-A630-000C29EED626";

           context["CustomerType"] = "account";

 

           AgentDesktopSession IadSession = (AgentDesktopSession)LocalSessionManager.ActiveSession;

 

 

           IadSession.AppHost.SetContext(context);

          

 

           bool success = true;

           if (!uiiDesktop.AppExistsInUI("Crm Customer View"))

               success = uiiDesktop.CreateDynamicApplication("Crm Customer View");

           if (success)

           {

 

               uiiDesktop.SetFocusOnApplication("Crm Customer View");

 

               RequestActionEventArgs args = new RequestActionEventArgs("Crm Customer View", "OpenCustomerForm", "");

               FireRequestAction(args);

           }

 

 

       }

 

So if you say that I need to Open a session with the customer and the CallId as a parameter so I need to create a CustomerEntity with my specific Id and the CallId will be new Guid. Ok this is will be easy, but as you say to do the with the best practice I need to create a cticonnector and modifying CallStateManager. This is will be hard to me J.

 

Jeremy if you can really help me on this I will appreciate a lot I can olso send you the dev server parameter if you need to see the control and show me the way and were I must add the code or I can send you our ActiveX control and all my CCA project .

 

Thanks Jeremy.

Jun 6, 2012 at 2:35 PM

Bahlinio,

I'm not as familiar with the ActiveX and WPF integration, but it does sound like this is a 3rd party tool.  The information I had in my original post was if you were writing your own custom connector which we did.  

If you're using this control for call processing, a few questions:

1. How do you know the GUID of the customer that is calling in so you can open the appropriate CRM Screen?  Is this all contained within the ActiveX Control?

What I would probably do, in order to keep a level of separation:

1. In the WPFCustomerSearch control, add a method to handle a custom action for your customer lookup/session info.  In this method, create the CustomerRecord & Customer Entity objects (there is code in the search already for converting the CustomerRecord (data) to a Customer Entity (used for a session).  Call OpenSession(<customer_entity_record>,Guid.Empty).  This will open up a new session and automatically open whatever additional hosted applications you have configured in CRM.

2.  Create a new action under the Actions within the Uii Hosted Application for Customer Search.  In the WPFCustomerSearch Control modify the DoAction method so that you do a switch/case on the action parameter to check for action.Name.  Then when there is a match on your custom action name, call the method you created in #1.

3. In your ActiveX scenario, when the Call Alerting is triggered, package that in a RequestActionEventArgs message, include the necessary call data from the Active X control as your data parameter.  It works well to either serialize a custom object, or pass the data in an XML string.   Fire your new custom action, with the target being the Customer Search control.

From there CCA should pop-open your session and tabs.

Jeremy

Jun 6, 2012 at 5:06 PM

Bahlinio, 

dont Ever EVER do :

IadSession.AppHost.SetContext(context);

All sorts of odd things happen...

Use this method instead :

// Get the current context. 
Context newCtx = new Context(this.Context.GetContext());
// Change it
newCtx["key"] = "value";
// Raise the update
FireChangeContext(new ContextEventArgs(newCtx)); 

Futher, You should o as Jwinchell instructs and fire off an action to the search control to process the session creation action..  

This is a copy of a post I made in another thread... hopefully it will clear up some of the process for you:

>>>

The CTI Subsystem is designed to work through a desktop manager and Search Control. You will find one in the samples, and if you’re using the solution starters to build your own CTI adapter, you will see a project for it in the template the CTI Solution template builds.

When developing CTI enabled solutions, you first start with basic Search to work out your hosted application invoke’ s and contextual loading. Once you have that, you add the CTI bits in to trigger Session create via the same search method you have been using up to that point.

Fundamentally, CTI supports/invokes the Search process in CCA.

CTI actions are not intended to directly invoke any hosted application. The sequence that should be followed is, and you will see this in the examples:

CTI Inbound call >

  1. CTI Root control accepts and decomposes the event and raises an New Call event to Call State manager.
  2. Call State Manager accepts the new call event and breaks down the event information into the UII CTI Objects, creating a UII Call Tracking object, then raised a New Call event to the desktop manager.
  3. Desktop manager Does any parsing on the event necessary, creates any desktop level tracking info necessary, Creates the CTI Lookup Request Payload , Seralizes it to a string and sends it as the data payload in an Action Call to * ( all apps) , using the message CtiLookupRequest.CTILOOKUPACTIONNAME.
  4. The Search control catch’s the CtiLookupRequest.CTILOOKUPACTIONNAME action request and processes that to the DoSearchFromCTIRequest method.
  5. Search control breaks down the CTI Lookup Request and runs the search process, invoking session create as necessary, and associating the UII CTI Call Object to the session.

In short: Get Session creation and Hosted Application bits working BEFORE you bring CTI into the picture.

<<<

The key message here is that the UI elements for CTI control should not do anything to the session persay,  they should act on the CTI connection and allow the CTI connection to raise events to notifiy the session of state changes ( Call Pickup being such an event )

Does that make sense?

Mattb-msft.

Jun 6, 2012 at 5:18 PM

Thank you Matt,

Before you send me your reply I start a little bit a solution like yours.

In the CallSuccess event of the activeX cti toolbar Im searching the customer

By using CrmCustomerService. I add the CustomerID and the customertype to the context.

I create a customer entity record from the result and I Open a new session with that customer. After that I call my DynamicApplication and the customer form is displayed perfectly. But the Tab in CCA doesn’t display data (MainPhone,OtherPhone, email…) and the is no customer name as a title of the Tab. I think that the customer record is not mapped to the new Tab. What do you think?

The following is the CallSuccess:

 

private void AX_CallSuccess(object sender, AxAgentLink._IToolbarEvents_CallSuccessEvent e)
        {


            Context context = new new Context(this.Context.GetContext());
            

            AgentDesktopSession IadSession = (AgentDesktopSession)LocalSessionManager.ActiveSession;
            
            
            CustomerEntity customer=new CustomerEntity();


            CrmCustomerService Custo = new CrmCustomerService();
           
            results = new CustomerRecord[1];
            results = Custo.GetCustomer(null, "", AX.get_CallInformation().DNIS, null, null, null, 1);


            customer = new CustomerEntity(results[0].CustomerId, results[0], "<CustomerID>1<CustomerID/>", false, this.ApplicationName);
            
            context["CustomerID"] = results[0].CustomerId;
            context["CustomerType"] = "account";

            uiiDesktop.OpenSession(customer, Guid.Empty);
            

            

            bool success = true;
            if (!uiiDesktop.AppExistsInUI("CrmAccountContactView"))
                success = uiiDesktop.CreateDynamicApplication("CrmAccountContactView");
           
            if (success)
            {

                uiiDesktop.SetFocusOnApplication("CrmAccountContactView");

                RequestActionEventArgs args = new RequestActionEventArgs("CrmAccountContactView", "OpenForm", "");
                FireRequestAction(args);
            }
        }

 



and Jeremy propose to me the following solution:

1. In the WPFCustomerSearch control, add a method to handle a custom action for your customer lookup/session info.  In this method, create the CustomerRecord & Customer Entity objects (there is code in the search already for converting the CustomerRecord (data) to a Customer Entity (used for a session).  Call OpenSession(<customer_entity_record>,Guid.Empty).  This will open up a new session and automatically open whatever additional hosted applications you have configured in CRM.

2.  Create a new action under the Actions within the Uii Hosted Application for Customer Search.  In the WPFCustomerSearch Control modify the DoAction method so that you do a switch/case on the action parameter to check for action.Name.  Then when there is a match on your custom action name, call the method you created in #1.

3. In your ActiveX scenario, when the Call Alerting is triggered, package that in a RequestActionEventArgs message, include the necessary call data from the Active X control as your data parameter.  It works well to either serialize a custom object, or pass the data in an XML string.   Fire your new custom action, with the target being the Customer Search control.

Jun 6, 2012 at 5:32 PM

Hi Jeremy,

I followed the steps as you mentioned. so first I add the

SearchCustomerByPhone Methode in WpfCustomerSearch as the following:

public void SearchCustomerByPhone(string phonenumber)
        {
            CustomerEntity customer = new CustomerEntity();
            ICustomerService CustomerLookup = AifServiceContainer.Instance.GetService<ICustomerService>(); ;
            CustomerRecord[] results = null;
            results=CustomerLookup.GetCustomer(null, "", phonenumber, null, null, null, 1);
            customer = new CustomerEntity(results[0].CustomerId, results[0], "<CustomerID>1<CustomerID/>", false, this.ApplicationName);

            Context context = new Uii.Csr.Context(this.Context.GetContext());
            context["CustomerID"] = results[0].CustomerId;
            context["CustomerType"] = "account";
            
            Session ss = OpenSession(customer, Guid.Empty);
            
        }

after that I modifyed the DoAction in WpfCustomerSearch as the following:



protected override void DoAction(RequestActionEventArgs args)
        {
            if (args.Action.Equals(CtiLookupRequest.CTILOOKUPACTIONNAME, StringComparison.Ordinal))
            {
                // Process request coming from the CTI Desktop Manager 
                DoSearchFromCtiRequest(args.Data);
            }
            else
            {
                if (args.Action.Equals("StartSessionFromQueue", StringComparison.Ordinal))
                {
                    DoSearchFromQueue(args.Data);
                }
                else
                {
                    base.DoAction(args);
                }
            }

            if (args.Action == "OpenForm")
            {
                SearchCustomerByPhone("95008108");
            } 
        }

the phone number is hardcoded just to test.



and finally I modify the CallAlerting Event of the ActiveX as the following:



private void AX_CallSuccess(object sender, AxAgentLink._IToolbarEvents_CallSuccessEvent e)
        {


                       RequestActionEventArgs args = new RequestActionEventArgs("CrmAccountContactView", "OpenForm", "");
            FireRequestAction(args);
}
as a result: the dynamic application display an error, I think that the CustomerID and the customerType are empty and the is no Tab opned
Jun 7, 2012 at 1:21 PM

Balhinio,

I think at this point, there may be some issues with how the web applications are setup in your Uii Hosted Application configuration.  The OpenSession() method will handled setting your context values so you do not have to do that.  However, in the wpfcustomersearch control check the 2 methods that set context, it may just be called setContext but it gets called during the OpenSession call.   Make sure all the variables are being set in context.

If you could take screenshots or post what your Uii Hosted Application configuration is for your Customer Form that would be helpful.  For now, I would try to at least get tabs to open when using the "Search Customer" button in CCA.  If you get that working then hooking up the rest of the CTI will be easy.

Jeremy