Jaa


Oman mukautetun kanavan integroiminen Direct Linen avulla

Customer Servicen monikanavan avulla voit ottaa käyttöön yhdistimen mukautettujen viestintäkanavien integroimiseksi käyttämällä Direct Line API 3.0:aa, joka on osa .NET SDK:ta. Täydellinen mallikoodi havainnollistaa, miten voit luoda oman yhdistimen. Lisätietoja Direct Line API 3.0:sta on kohdassa Direct Line 3.0 -ohjelmointirajapinnan keskeiset käsitteet.

Tässä artikkelissa kerrotaan, miten kanava on yhdistetty Microsoft Direct Line Bot Frameworkiin, joka on sisäisesti liitetty Customer Servicen monikanavaan. Seuraavassa osiossa on koodikatkelmia, jotka käyttävät Direct Line API 3.0:aa Direct Line -asiakasohjelman luomiseen ja käyttöliittymää IChannelAdapter malliliittimen luomiseen.

Huomautus

Lähdekoodi ja dokumentaatio kuvaavat yleistä kulkua, jolla kanava voi muodostaa yhteyden Customer Servicen monikanavaan Direct Linen kautta, eivätkä keskity luotettavuuteen ja skaalautuvuuteen.

Osat

Sovittimen Webhook-ohjelmointirajapintapalvelu

Kun käyttäjä kirjoittaa viestin, sovittimen ohjelmointirajapinta käynnistetään kanavasta. Se käsittelee saapuvan pyynnön ja lähettää vastauksena onnistumisen tai epäonnistumisen tilan. Sovittimen ohjelmointirajapintapalvelun on toteutettava IChannelAdapter liittymä ja lähetettävä saapuva pyyntö vastaavaan kanavasovittimeen pyynnön käsittelyä varten.

/// <summary>
/// Accept an incoming web-hook request from MessageBird Channel
/// </summary>
/// <param name="requestPayload">Inbound request Object</param>
/// <returns>Executes the result operation of the action method asynchronously.</returns>
    [HttpPost("postactivityasync")]
    public async Task<IActionResult> PostActivityAsync(JToken requestPayload)
    {
        if (requestPayload == null)
        {
            return BadRequest("Request payload is invalid.");
        }

        try
        {
            await _messageBirdAdapter.ProcessInboundActivitiesAsync(requestPayload, Request).ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            _logger.LogError($"postactivityasync: {ex}");
            return StatusCode(500, "An error occured while handling your request.");
        }

        return StatusCode(200);
    }

Kanavan sovittimet

Kanavasovitin käsittelee saapuvat ja lähtevät toiminnot, ja sen on toteutettava liittymä.IAdapterBuilder

Saapuvien aktiviteettien käsitteleminen

Kanavasovitin suorittaa seuraavat saapuvat toiminnot:

  1. Vahvista saapuvan viestin pyynnön allekirjoitus.

Kanavan saapuva pyyntö tarkistetaan allekirjoitusavaimen perusteella. Jos pyyntö on virheellinen, näyttöön tulee virheellinen allekirjoitus -poikkeussanoma. Jos pyyntö on pätevä, se toimii seuraavasti:

  /// <summary>
  /// Validate Message Bird Request
  /// </summary>
  /// <param name="content">Request Content</param>
  /// <param name="request">HTTP Request</param>
  /// <param name="messageBirdSigningKey">Message Bird Signing Key</param>
  /// <returns>True if there request is valid, false if there aren't.</returns>
  public static bool ValidateMessageBirdRequest(string content, HttpRequest request, string messageBirdSigningKey)
  {
      if (string.IsNullOrWhiteSpace(messageBirdSigningKey))
      {
          throw new ArgumentNullException(nameof(messageBirdSigningKey));
      }
      if (request == null)
      {
          throw new ArgumentNullException(nameof(request));
      }
      if (string.IsNullOrWhiteSpace(content))
      {
          throw new ArgumentNullException(nameof(content));
      }
      var messageBirdRequest = new MessageBirdRequest(
          request.Headers?["Messagebird-Request-Timestamp"],
          request.QueryString.Value?.Equals("?",
              StringComparison.CurrentCulture) != null
              ? string.Empty
              : request.QueryString.Value,
          GetBytes(content));

      var messageBirdRequestSigner = new MessageBirdRequestSigner(GetBytes(messageBirdSigningKey));
      string expectedSignature = request.Headers?["Messagebird-Signature"];
      return messageBirdRequestSigner.IsMatch(expectedSignature, messageBirdRequest);
  }
  1. Muunna saapuva pyyntö bottitoiminnoksi.

Saapuvan pyynnön tietosisältö muunnetaan toiminnoksi, jonka Bot Framework ymmärtää.

Huomautus

Aktiviteetin tietosisältö ei saa ylittää 28 kt:n sanoman kokorajoitusta.

Tämä Activity-objekti sisältää seuraavat määritteet:

Määrite Kuvaus
alkaen Tallentaa kanavatilin tiedot, jotka koostuvat käyttäjän yksilöllisestä tunnisteesta ja nimestä (etunimen ja sukunimen yhdistelmä välilyönnillä erotettuna).
kanavan tunnus Osoittaa kanavan tunnisteen. Saapuvien pyyntöjen kanavatunnus on directline.
palvelun URL-osoite Ilmaisee palvelun URL-osoitteen. Saapuvien pyyntöjen palvelun URL-osoite on https://directline.botframework.com/.
tyyppi Osoittaa aktiviteetin tyypin. Viestiaktiviteettien tyyppi on message.
Tekstiviesti Tallentaa viestin sisällön.
henkilöllisyystodistus Ilmaisee tunnuksen, jota sovitin käyttää lähteviin viesteihin vastaamiseen.
kanavan tiedot Osoittaa kanavatiedot, jotka koostuvat , channelTypeconversationcontext, ja customercontext.
kanavan tyyppi Ilmaisee kanavan nimen, jonka kautta asiakas lähettää viestejä. Esimerkiksi MessageBird, KakaoTalk, Snapchat
Keskustelun konteksti Viittaa sanasto-objektiin, joka sisältää työnkulussa määritetyt kontekstimuuttujat. Customer Servicen monikanava käyttää näitä tietoja keskustelun reitittämiseen oikealle asiakaspalvelijalle (huoltoedustajalle tai edustajalle). Esimerkkejä:
"conversationcontext" :{ "ProductName" : "Xbox", "Ongelma":"Asennus" }
Tässä esimerkissä konteksti reitittää keskustelun Xbox-asennuksesta vastaavalle edustajalle.
Asiakaskonteksti Viittaa sanakirjaobjektiin, joka sisältää asiakkaan tiedot, kuten puhelinnumeron ja sähköpostiosoitteen. Customer Servicen monikanava käyttää näitä tietoja käyttäjän yhteyshenkilötietueen tunnistamiseen.
"customercontext":{ "email":email@email.com, "puhelinnumero":"1234567890" }
  /// <summary>
  /// Build Bot Activity type from the inbound MessageBird request payload<see cref="Activity"/>
  /// </summary>
  /// <param name = "messagePayload"> Message Bird Activity Payload</param>
  /// <returns>Direct Line Activity</returns>
  public static Activity PayloadToActivity(MessageBirdRequestModel messagePayload)
  {
  if (messagePayload == null)
  {
      throw new ArgumentNullException(nameof(messagePayload));
  }
  if (messagePayload.Message?.Direction == ConversationMessageDirection.Sent ||
  messagePayload.Type == ConversationWebhookMessageType.MessageUpdated)
  {
      return null;
  }
  var channelData = new ActivityExtension
  {
      ChannelType = ChannelType.MessageBird,
      // Add Conversation Context in below dictionary object. Please refer the document for more information.
      ConversationContext = new Dictionary<string, string>(),
      // Add Customer Context in below dictionary object. Please refer the document for more information.
      CustomerContext = new Dictionary<string, string>()
  };
  var activity = new Activity
      {
          From = new ChannelAccount(messagePayload.Message?.From, messagePayload.Contact?.DisplayName),
          Text = messagePayload.Message?.Content?.Text,
          Type = ActivityTypes.Message,
          Id = messagePayload.Message?.ChannelId,
          ServiceUrl = Constant.DirectLineBotServiceUrl,
          ChannelData = channelData
      };

      return activity;
  }

Esimerkki JSON-hyötykuormasta on seuraava:

{
    "type": "message",
    "id": "bf3cc9a2f5de...",    
    "serviceUrl": https://directline.botframework.com/,
    "channelId": "directline",
    "from": {
        "id": "1234abcd",// userid which uniquely identify the user
        "name": "customer name" // customer name as First Name <space> Last Name
    },
    "text": "Hi,how are you today.",
    "channeldata":{
        "channeltype":"messageBird",
        "conversationcontext ":{ // this holds context variables defined in Workstream
            "ProductName" : "XBox",
            "Issue":"Installation"
        },
        "customercontext":{            
            "email":email@email.com,
            "phonenumber":"1234567890"           
        }
    }
}

  1. Lähetä aktiviteetti viestinvälityksen prosessorille.

Kun aktiviteetin tietosisältö on luotu, se kutsuu viestinvälitysprosessorin PostActivityAsync-menetelmää lähettääkseen aktiviteetin Direct Lineen. Kanavasovittimen on myös välitettävä tapahtumakäsittelijä, jonka välitysprosessori kutsuu, kun se vastaanottaa lähtevän viestin Customer Servicen monikanavasta Direct Linen kautta.

Lähtevien aktiviteettien käsittely

Välitysprosessori käynnistää tapahtumankäsittelijän lähettääkseen lähteviä toimintoja vastaavaan kanavasovittimeen, ja sovitin käsittelee sitten lähtevät toiminnot. Kanavasovitin suorittaa seuraavat lähtevät toiminnot:

  1. Muunna lähtevät aktiviteetit kanavan vastausmalliin.

Suoran linjan aktiviteetit muunnetaan kanavakohtaiseksi vastausmalliksi.

  /// <summary>
  /// Creates MessageBird response object from a Bot Framework <see cref="Activity"/>.
  /// </summary>
  /// <param name="activities">The outbound activities.</param>
  /// <param name="replyToId">Reply Id of Message Bird user.</param>
  /// <returns>List of MessageBird Responses.</returns>
  public static List<MessageBirdResponseModel> ActivityToMessageBird(IList<Activity> activities, string replyToId)
  {
      if (string.IsNullOrWhiteSpace(replyToId))
      {
          throw new ArgumentNullException(nameof(replyToId));
      }

      if (activities == null)
      {
          throw new ArgumentNullException(nameof(activities));
      }

      return activities.Select(activity => new MessageBirdResponseModel
      {
          To = replyToId,
          From = activity.ChannelId,
          Type = "text",
          Content = new Content
          {
              Text = activity.Text
          }
      }).ToList();
  }
  1. Lähetä vastaukset kanavan REST API:n kautta.

Kanavasovitin kutsuu REST-ohjelmointirajapintaa lähettääkseen kanavalle lähtevän vastauksen, joka lähetetään sitten käyttäjälle.

  /// <summary>
  /// Send Outbound Messages to Message Bird
  /// </summary>
  /// <param name="messageBirdResponses">Message Bird Response object</param>
  /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
  public async Task SendMessagesToMessageBird(IList<MessageBirdResponseModel> messageBirdResponses)
  {
      if (messageBirdResponses == null)
      {
          throw new ArgumentNullException(nameof(messageBirdResponses));
      }

      foreach (var messageBirdResponse in messageBirdResponses)
      {
          using (var request = new HttpRequestMessage(HttpMethod.Post, $"{MessageBirdDefaultApi}/send"))
          {
              var content = JsonConvert.SerializeObject(messageBirdResponse);
              request.Content = new StringContent(content, Encoding.UTF8, "application/json");
              await _httpClient.SendAsync(request).ConfigureAwait(false);
          }
      }
  }

Viestinvälitysprosessori

Viestinvälitysprosessori vastaanottaa saapuvan toiminnan kanavasovittimesta ja suorittaa aktiviteettimallin vahvistuksen. Ennen kuin lähetät tämän toiminnon Direct Lineen, välitysprosessori tarkistaa, onko keskustelu aktiivinen tietyssä aktiviteetissa.

Jos haluat tarkistaa, onko keskustelu aktiivinen, välitysprosessori ylläpitää aktiivisten keskustelujen kokoelmaa sanakirjassa. Tämä sanasto sisältää avaimen käyttäjätunnuksena, joka yksilöi käyttäjän ja arvon seuraavan luokan olioksi:

 /// <summary>
/// Direct Line Conversation to store as an Active Conversation
/// </summary>
public class DirectLineConversation
{
    /// <summary>
    /// .NET SDK Client to connect to Direct Line Bot
    /// </summary>
    public DirectLineClient DirectLineClient { get; set; }

    /// <summary>
    /// Direct Line response after start a new conversation
    /// </summary>
    public Conversation Conversation { get; set; }

    /// <summary>
    /// Watermark to guarantee that no messages are lost
    /// </summary>
    public string WaterMark { get; set; }
}

Jos keskustelu ei ole aktiivinen välitysprosessorin vastaanottamalle toiminnolle, se suorittaa seuraavat vaiheet:

  1. Aloittaa keskustelun Direct Linen avulla ja tallentaa Direct Linen lähettämän keskusteluobjektin sanakirjassa olevaa käyttäjätunnusta vastaan.
 /// <summary>
 /// Initiate Conversation with Direct Line Bot
 /// </summary>
 /// <param name="inboundActivity">Inbound message from Aggregator/Channel</param>
 /// <param name="adapterCallBackHandler">Call Back to send activities to Messaging API</param>
 /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
 private async Task InitiateConversation(Activity inboundActivity, EventHandler<IList<Activity>> adapterCallBackHandler)
 {
     var directLineConversation = new DirectLineConversation
     {
         DirectLineClient = new DirectLineClient(_relayProcessorConfiguration.Value.DirectLineSecret)
     };
     // Start a conversation with Direct Line Bot
     directLineConversation.Conversation = await directLineConversation.DirectLineClient.Conversations.
         StartConversationAsync().ConfigureAwait(false);

     await directLineConversation.DirectLineClient.Conversations.
         StartConversationAsync().ConfigureAwait(false);
     if (directLineConversation.Conversation == null)
     {
         throw new Exception(
             "An error occurred while starting the Conversation with direct line. Please validate the direct line secret in the configuration file.");
     }

     // Adding the Direct Line Conversation object to the lookup dictionary and starting a thread to poll the activities from the direct line bot.
     if (ActiveConversationCache.ActiveConversations.TryAdd(inboundActivity.From.Id, directLineConversation))
     {
         // Starts a new thread to poll the activities from Direct Line Bot
         new Thread(async () => await PollActivitiesFromBotAsync(
             directLineConversation.Conversation.ConversationId, inboundActivity, adapterCallBackHandler).ConfigureAwait(false))
         .Start();
     }
 }
  1. Käynnistää uuden säikeen, joka tekee kyselyn lähtevistä toiminnoista Direct Line -botista määritystiedostossa määritetyn kyselyvälin perusteella. Kyselyketju on aktiivinen, kunnes keskustelutoiminta on vastaanotettu Direct Linesta.
/// <summary>
/// Polling the activities from BOT for the active conversation
/// </summary>
/// <param name="conversationId">Direct Line Conversation Id</param>
/// <param name="inboundActivity">Inbound Activity from Channel/Aggregator</param>
/// <param name="lineActivitiesReceived">Call Back to send activities to Messaging API</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
private async Task PollActivitiesFromBotAsync(string conversationId, Activity inboundActivity, EventHandler<IList<Activity>> lineActivitiesReceived)
{
    if (!int.TryParse(_relayProcessorConfiguration.Value.PollingIntervalInMilliseconds, out var pollingInterval))
    {
        throw new FormatException($"Invalid Configuration value of PollingIntervalInMilliseconds: {_relayProcessorConfiguration.Value.PollingIntervalInMilliseconds}");
    }
    if (!ActiveConversationCache.ActiveConversations.TryGetValue(inboundActivity.From.Id,
        out var conversationContext))
    {
        throw new KeyNotFoundException($"No active conversation found for {inboundActivity.From.Id}");
    }
    while (true)
    {
        var watermark = conversationContext.WaterMark;
        // Retrieve the activity set from the bot.
        var activitySet = await conversationContext.DirectLineClient.Conversations.
            GetActivitiesAsync(conversationId, watermark).ConfigureAwait(false);
        // Set the watermark to the message received
        watermark = activitySet?.Watermark;

        // Extract the activities sent from our bot.
        if (activitySet != null)
        {
            var activities = (from activity in activitySet.Activities
                              where activity.From.Id == _relayProcessorConfiguration.Value.BotHandle
                              select activity).ToList();
            if (activities.Count > 0)
            {
                SendReplyActivity(activities, inboundActivity, lineActivitiesReceived);
            }
            // Update Watermark
            ActiveConversationCache.ActiveConversations[inboundActivity.From.Id].WaterMark = watermark;
            if (activities.Exists(a => a.Type.Equals("endOfConversation", StringComparison.InvariantCulture)))
            {
                if (ActiveConversationCache.ActiveConversations.TryRemove(inboundActivity.From.Id, out _))
                {
                    Thread.CurrentThread.Abort();
                }
            }
        }
        await Task.Delay(TimeSpan.FromMilliseconds(pollingInterval)).ConfigureAwait(false);
    }
}

Huomautus

Viestin vastaanottavan koodin ytimessä on GetActivitiesAsync-menetelmä, joka ottaa ConversationId ja watermark parametreina. Parametrin watermark tarkoituksena on noutaa viestit, joita Direct Line ei ole vielä toimittanut. Jos vesileimaparametri on määritetty, keskustelu toistetaan vesileimasta, jotta viestejä ei menetetä.

Lähetä aktiviteetti Direct Lineen

 /// <summary>
 /// Send the activity to the bot using Direct Line client
 /// </summary>
 /// <param name="inboundActivity">Inbound message from Aggregator/Channel</param>
 /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
 private static async Task SendActivityToBotAsync(Activity inboundActivity)
 {
     if (!ActiveConversationCache.ActiveConversations.TryGetValue(inboundActivity.From.Id,
         out var conversationContext))
     {
         throw new KeyNotFoundException($"No active conversation found for {inboundActivity.From.Id}");
     }
     await conversationContext.DirectLineClient.Conversations.PostActivityAsync(
         conversationContext.Conversation.ConversationId, inboundActivity).ConfigureAwait(false);
 }

Jos keskustelu on aktiivinen välitysprosessorin vastaanottamalle aktiviteetille, se lähettää aktiviteetin viestinvälityksen prosessorille.

Keskustelun lopettaminen

Jos haluat lopettaa keskustelun, katso Keskustelun lopettaminen Direct Linessa.

Seuraavat vaiheet

Live-keskustelukanavien ja asynkronisten kanavien tuki
Direct Linea käyttävien mukautettujen kanavien Markdown-muodot

Mukautetun viestikanavan määrittäminen
MessageBird-ohjelmointirajapinnan viite
Bottien määrittämisen parhaat käytännöt