public virtual async Task <HttpResponseMessage> Post([FromBody] Activity activity) { // check if activity is of type message if (activity != null && activity.GetActivityType() == ActivityTypes.Message) { await Conversation.SendAsync(activity, () => new EchoDialog()); } if (activity.GetActivityType() == ActivityTypes.ConversationUpdate) { // Handle conversation state changes, like members being added and removed // Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info // Not available in all channels IConversationUpdateActivity iConversationUpdated = activity as IConversationUpdateActivity; ConnectorClient connector = new ConnectorClient(new System.Uri(activity.ServiceUrl)); if (iConversationUpdated != null) { if ((string)activity.Text == "Address" || (activity.From.Name == "User" && iConversationUpdated.MembersAdded.Where(m => m.Id == iConversationUpdated.Recipient.Id).Count() > 0)) { //Initialize the CRM connection IOrganizationService service = Dynamics.GetService(); //Extract the direct line address (if applicable) CXAddress address = JsonConvert.DeserializeObject <CXAddress>(activity.Value != null ? (string)activity.Value : "{}"); if (address.Address == null) { address.Address = "3145783471"; address.Message = "Initialize Conversation"; address.Bot = "Default Bot"; } //get bot EntityCollection botResults = service.RetrieveMultiple(new FetchExpression(string.Format(@"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false' no-lock='true'> <entity name='aspect_cxbot'> <attribute name='aspect_cxbotid' /> <attribute name='aspect_name' /> <attribute name='createdon' /> <order attribute='aspect_name' descending='false' /> <filter type='and'> <filter type='or'> <condition attribute='aspect_name' operator='eq' value='{0}' /> <condition attribute='aspect_default' operator='eq' value='1' /> </filter> </filter> </entity> </fetch>", address.Bot == null ? string.Empty : address.Bot))); if (botResults.Entities.Count() == 0) { var responseMessage = activity.CreateReply(); responseMessage.Text = "There is currently no default CX bot configured in your environment or the bot speicified does not exist."; responseMessage.Speak = "There is currently no default CX bot configured in your environment or the bot speicified does not exist."; ResourceResponse msgResponse = connector.Conversations.ReplyToActivity(responseMessage); return(new HttpResponseMessage(System.Net.HttpStatusCode.Accepted)); } Xrm.Sdk.Entity cxBot = botResults.Entities[0]; var namedMatchedBot = (from b in botResults.Entities where (string)b["aspect_name"] == address.Address select b); if (namedMatchedBot.Count() > 0) { cxBot = namedMatchedBot.First(); } //get first step Xrm.Sdk.Entity cxCurrentStep = service.RetrieveMultiple(new FetchExpression(string.Format(@"<fetch mapping='logical' version='1.0' distinct='false' output-format='xml-platform' no-lock='true'> <entity name='aspect_cxstep'> <all-attributes /> <link-entity name='aspect_cxbot' to='aspect_cxbotid' from='aspect_cxbotid' alias='aspect_cxbot'> <all-attributes /> </link-entity> <order descending='false' attribute='aspect_name' /> <filter type='and'> <condition value='1' attribute='aspect_root' operator='eq' /> <condition value='{0}' attribute='aspect_cxbotid' operator='eq' /> </filter> </entity> </fetch>", cxBot.Id))).Entities[0]; //create initial conversation Xrm.Sdk.Entity cxConversation = new Xrm.Sdk.Entity("aspect_cxconversation", "aspect_conversationid", activity.Conversation.Id); cxConversation["aspect_name"] = activity.Conversation.Id; cxConversation["aspect_from"] = address.Address; cxConversation["aspect_lastanswer"] = address.Message; cxConversation["aspect_cxbotid"] = new EntityReference(cxBot.LogicalName, cxBot.Id); cxConversation["aspect_currentcxstepid"] = new EntityReference(cxCurrentStep.LogicalName, cxCurrentStep.Id); UpsertResponse cxConversationResponse = (UpsertResponse)service.Execute(new UpsertRequest() { Target = cxConversation }); if (!string.IsNullOrEmpty(address.Message)) { //Create a conversation message with the initial Xrm.Sdk.Entity conversationClient = new Xrm.Sdk.Entity("aspect_cxconversationmessage"); conversationClient["aspect_cxconversationid"] = new EntityReference("aspect_cxconversation", "aspect_conversationid", activity.Conversation.Id); conversationClient["aspect_cxstepid"] = new EntityReference(cxCurrentStep.LogicalName, cxCurrentStep.Id); conversationClient["aspect_direction"] = false; conversationClient["aspect_name"] = activity.Conversation.Id; service.Create(conversationClient); } //ROUTE TO NEXT QUESTION while (cxCurrentStep != null) { //FIRE ENTRY SEARCHES Dynamics.ExecuteSearch(service, (EntityReference)cxConversationResponse.Results["Target"], new EntityReference(cxCurrentStep.LogicalName, cxCurrentStep.Id), true); //FIRE ENTRY WORKFLOW Dynamics.FireWorkflow(service, cxCurrentStep, false); switch (Dynamics.CXGetType((OptionSetValue)cxCurrentStep["aspect_type"])) { case "MESSAGE": var cxNextStep = await Dynamics.PromptInitialQuestion(activity , connector , service , new Xrm.Sdk.Entity(((EntityReference)cxConversationResponse.Results["Target"]).LogicalName) { Id = ((EntityReference)cxConversationResponse.Results["Target"]).Id } , cxCurrentStep); if (cxNextStep != null) { cxCurrentStep = service.RetrieveMultiple(new FetchExpression(string.Format(@"<fetch mapping='logical' version='1.0' distinct='false' output-format='xml-platform' no-lock='true'> <entity name='aspect_cxstep'> <all-attributes /> <link-entity name='aspect_cxbot' to='aspect_cxbotid' from='aspect_cxbotid' alias='aspect_cxbot'> <all-attributes /> </link-entity> <filter type='and'> <condition value='{0}' attribute='aspect_cxstepid' operator='eq' /> </filter> </entity> </fetch>", cxNextStep.Id))).Entities[0]; } break; case "QUESTION": case "MENU": case "RECORD": case "TRANSFER": if (cxCurrentStep != null) { await Dynamics.PromptInitialQuestion(activity , connector , service , new Xrm.Sdk.Entity(((EntityReference)cxConversationResponse.Results["Target"]).LogicalName) { Id = ((EntityReference)cxConversationResponse.Results["Target"]).Id } , cxCurrentStep); cxCurrentStep = null; } break; } } } } await HandleSystemMessage(activity); } else { await HandleSystemMessage(activity); } return(new HttpResponseMessage(System.Net.HttpStatusCode.Accepted)); }
public async Task MessageReceivedAsync(IDialogContext context, IAwaitable <IMessageActivity> argument) { var message = await argument; IOrganizationService service = Dynamics.GetService(); //Get the current and next step Xrm.Sdk.Entity cxCurrentStep = Dynamics.GetCXCurrentStepEntityByConversationId(service, message.Conversation.Id); EntityReference cxNextStep = cxCurrentStep.Contains("aspect_nextcxstepid") ? (EntityReference)cxCurrentStep["aspect_nextcxstepid"] : null; //Create a conversation message with the users response Xrm.Sdk.Entity conversationClient = new Xrm.Sdk.Entity("aspect_cxconversationmessage"); conversationClient["aspect_cxconversationid"] = new EntityReference("aspect_cxconversation", "aspect_conversationid", message.Conversation.Id); conversationClient["aspect_cxstepid"] = new EntityReference(cxCurrentStep.LogicalName, cxCurrentStep.Id); conversationClient["aspect_direction"] = false; conversationClient["aspect_name"] = message.Id; conversationClient["aspect_message"] = message.Text; service.Create(conversationClient); //TODO: Check global utterances Xrm.Sdk.Entity globalUtterance = service.RetrieveMultiple(new FetchExpression(string.Format(@"<fetch mapping='logical' version='1.0' distinct='false' output-format='xml-platform' no-lock='true'> <entity name='aspect_cxglobalutterance'> <attribute name='aspect_cxglobalutteranceid' /> <attribute name='aspect_cxstepid' /> <attribute name='aspect_answers' /> <order descending='false' attribute='aspect_name' /> <filter type='and'> <condition value='%{0}%' attribute='aspect_answers' operator='like' /> </filter> </entity> </fetch>", HttpUtility.UrlEncode(message.Text)))).Entities.FirstOrDefault(); if (globalUtterance != null) { cxNextStep = (EntityReference)globalUtterance["aspect_cxstepid"]; } else { //validate user input string utteranceMatch = UtteranceMatch(message.Text, (string)(cxCurrentStep.Contains("aspect_answers") ? (string)cxCurrentStep["aspect_answers"] : null)); if (Dynamics.CXGetType((OptionSetValue)cxCurrentStep["aspect_type"]) == "MENU") { Xrm.Sdk.EntityCollection cxStepAnswers = service.RetrieveMultiple(new FetchExpression(string.Format(@"<fetch mapping='logical' version='1.0' distinct='false' output-format='xml-platform' no-lock='true'> <entity name='aspect_cxstepanswer'> <all-attributes /> <order descending='false' attribute='aspect_name' /> <filter type='and'> <condition value='{0}' attribute='aspect_cxstepid' operator='eq' /> </filter> </entity> </fetch>", cxCurrentStep.Id))); foreach (Xrm.Sdk.Entity e in cxStepAnswers.Entities) { utteranceMatch = UtteranceMatch(message.Text, e.Contains("aspect_answers") ? (string)e["aspect_answers"] : null); if (!string.IsNullOrEmpty(utteranceMatch)) { cxNextStep = e.Contains("aspect_nextcxstepid") ? (EntityReference)e["aspect_nextcxstepid"] : null; break; } } } if (utteranceMatch == null) { string noMatchMessage = string.Format("I'm sorry, I didn't understand '{0}'.", message.Text); //TODO make this message come from CX Bot Xrm.Sdk.Entity noMatchResponse = new Xrm.Sdk.Entity("aspect_cxconversationmessage"); conversationClient["aspect_cxconversationid"] = new EntityReference("aspect_cxconversation", "aspect_conversationid", message.Conversation.Id); conversationClient["aspect_cxstepid"] = new EntityReference(cxCurrentStep.LogicalName, cxCurrentStep.Id); conversationClient["aspect_direction"] = true; conversationClient["aspect_name"] = message.Id; conversationClient["aspect_message"] = noMatchMessage; service.Create(conversationClient); IMessageActivity responseNoMatchMessage = context.MakeMessage(); responseNoMatchMessage.Text = string.Format(noMatchMessage); responseNoMatchMessage.Value = message.Value; await context.PostAsync(responseNoMatchMessage); context.Wait(MessageReceivedAsync); return; } } //Update the last answer in the conversation Microsoft.Xrm.Sdk.Entity upsConversation2 = new Microsoft.Xrm.Sdk.Entity("aspect_cxconversation", "aspect_conversationid", message.Conversation.Id); upsConversation2["aspect_lastanswer"] = message.Text; UpsertResponse cxConversationResponse = (UpsertResponse)service.Execute(new UpsertRequest() { Target = upsConversation2 }); int maxLoopCount = 10; int currentLoopCount = 0; //EXECUTE EXIT SEARCH Dynamics.ExecuteSearch(service, (EntityReference)cxConversationResponse.Results["Target"], new EntityReference(cxCurrentStep.LogicalName, cxCurrentStep.Id), false); //FIRE EXIT WORKFLOW Dynamics.FireWorkflow(service, cxCurrentStep, false); //REFRESH THE NEXT CX STEP IN CASE A SEARCH/WORKFLOW ALTERED IT Xrm.Sdk.Entity rerouteCXStep = Dynamics.GetCXNextStepEntityByConversationId(service, message.Conversation.Id, cxNextStep); if (rerouteCXStep != null) { cxNextStep = new EntityReference(rerouteCXStep.LogicalName, rerouteCXStep.Id); } while (cxNextStep != null && currentLoopCount <= maxLoopCount) { if (currentLoopCount > 0) { //EXECUTE EXIT SEARCH Dynamics.ExecuteSearch(service, (EntityReference)cxConversationResponse.Results["Target"], new EntityReference(cxCurrentStep.LogicalName, cxCurrentStep.Id), false); //FIRE EXIT WORKFLOW Dynamics.FireWorkflow(service, cxCurrentStep, false); //REFRESH THE NEXT CX STEP IN CASE A SEARCH/WORKFLOW ALTERED IT rerouteCXStep = Dynamics.GetCXNextStepEntityByConversationId(service, message.Conversation.Id, cxNextStep); } //EXIT IF THERE IS NO NEXT STEP if (cxNextStep == null) { return; } //FIRE ENTRY WORKFLOW Dynamics.FireWorkflow(service, rerouteCXStep, true); //EXECUTE ENTRY SEARCH Dynamics.ExecuteSearch(service, (EntityReference)cxConversationResponse.Results["Target"], new EntityReference(rerouteCXStep.LogicalName, rerouteCXStep.Id), true); //process question switch (Dynamics.CXGetType((OptionSetValue)rerouteCXStep["aspect_type"])) { case "MESSAGE": await Dynamics.PromptNextQuestion(context, service, cxCurrentStep, rerouteCXStep, message); cxCurrentStep = Dynamics.GetCXCurrentStepEntityByConversationId(service, message.Conversation.Id); cxNextStep = cxCurrentStep.Contains("aspect_nextcxstepid") ? (EntityReference)cxCurrentStep["aspect_nextcxstepid"] : null; if (cxNextStep == null) { //if the path ended with a search but no default next step execute the exit workflows //EXECUTE EXIT SEARCH Dynamics.ExecuteSearch(service, (EntityReference)cxConversationResponse.Results["Target"], new EntityReference(cxCurrentStep.LogicalName, cxCurrentStep.Id), false); //REFRESH THE NEXT CX STEP IN CASE A SEARCH/WORKFLOW ALTERED IT rerouteCXStep = Dynamics.GetCXNextStepEntityByConversationId(service, message.Conversation.Id, cxNextStep); if (rerouteCXStep != null && rerouteCXStep.Id != cxCurrentStep.Id) { cxNextStep = new EntityReference(rerouteCXStep.LogicalName, rerouteCXStep.Id); } } currentLoopCount++; break; case "QUESTION": case "MENU": case "RECORD": case "TRANSFER": await Dynamics.PromptNextQuestion(context, service, cxCurrentStep, rerouteCXStep, message); cxNextStep = null; break; } } context.Wait(MessageReceivedAsync); }