1

I'm working with the WhatsApp Business Cloud API C# Wrapper Library and SignalR in a project to create a real time chat for a webpage. I've managed to separate the messages sent to the website according to the SignalR connection (such that messages sent from the site's WhatsApp account do not get mixed on different connections, which all share the same WhatsApp number), but I'm stuck regarding the sending of messages from the website to the WhatsApp account. The action that sends the messages is as follows, which is in the HomeController.cs file

/// <summary>
/// This is to handle:
/// 1. Plain Text messgaes
/// 2. Text Templates (NO params)
/// 3. Text Templates with Params
/// </summary>
/// <param name="payload"></param>
/// <returns></returns>
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SendWhatsAppTextMessage(SendTemplateMessageViewModel payload)
{ // Functional using SendMessageController
    try
    {
        SendWhatsAppPayload sendPayload = new();
        sendPayload.SendText = new SendTextPayload()
        { ToNum = payload.RecipientPhoneNumber };
        sendPayload.SendText.PreviewUrl = false;

        if (payload.Message != null)
        {   // This is a normal plain Text Message
            sendPayload.SendText.Message = payload.Message;
        }
        else
        {   // This is a Template Test Message 
            sendPayload.Template = new WhatsappTemplate();
            sendPayload.Template.Name = payload.TemplateName;

            // CJM to add a Params Textbox on the Form                  
            if (payload.TemplateParams != null)
            {
                string strParams = payload.TemplateParams; // "Cornelius#DAFP";
                List<string> listParams = strParams.Split(new string[] { "#" }, StringSplitOptions.None).ToList();
                sendPayload.Template.Params = listParams;
            }
        }

        // Send the message and get the WAMId
        string WAMIds = _sendMessageController.GetWAMId((await _sendMessageController.SendWhatsApp_TextAsync(sendPayload)).Value);


        if (WAMIds != null)
        {
            return RedirectToAction(nameof(Index)).WithSuccess("Success", $"Successfully sent video template message with WAMId '{WAMIds}'");
        }
        else
        {
            return RedirectToAction(nameof(SendWhatsAppTemplateMessage));
        }

    }
    catch (WhatsappBusinessCloudAPIException ex)
    {
        _logger.LogError(ex, ex.Message);
        return RedirectToAction(nameof(SendWhatsAppTemplateMessage)).WithDanger("Error", ex.Message);
    }
}

And here is the view from the SendWhatsAppTextMessage.cshtml file

@model SendTemplateMessageViewModel
@{
    ViewData["Title"] = "Send WhatsApp Text Message Page";
    ViewData["CurrentPage"] = "Send WhatsApp Text Message";
    Layout = "~/Views/Shared/AdminLTE/_AdminLayout.cshtml";
    ViewData["ControllerName"] = nameof(HomeController).Replace("Controller", "");
    ViewData["ActionName"] = nameof(HomeController.SendWhatsAppTextMessage);
}

<section class="content">
    <div class="row">
        <div class="col-12">
            <div class="card card-info">
                <div class="card-header">
                    <h3 class="card-title">Send WhatsApp Text Message</h3>
                </div> <!--/. card-header -->
                <!--Form start -->
                <form asp-action="SendWhatsAppTextMessage">
                    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                    <div class="card-body">
                        <div class="form-group">
                            <label class="control-label">Recipient Phone Number</label>
                            <input asp-for="RecipientPhoneNumber" class="form-control" />
                            <span asp-validation-for="RecipientPhoneNumber" class="form-control" />
                        </div>
                        <div class="form-group">
                            <label class="control-label">Message</label>
                            <input asp-for="Message" class="form-control" />
                            <span asp-validation-for="Message" class="form-control" />
                        </div>
                    </div> <!--/. card-body -->
                    <div class="card-footer">
                        <button type="submit" name="submit" class="btn btn-primary">Send Message</button>
                    </div>
                </form>
            </div> <!-- /.card -->
        </div>
    </div>
</section>

@section Scripts {
    @{
        await Html.RenderPartialAsync("_ValidationScriptsPartial");
    }
    } 

The problem with sending messages with a button this way is that after the action is called, there is postback on the page and the SignalR connection gets reset, so I loose track of the chat on the page. What I'm trying to achieve is just to maintain the SignalR connection while sending messages from the website, so as to see the chat as usual (website user and messages from the other end).

Thanks.

EDIT:

The AJAX request is as follows

$.ajax({
    method: "POST",
    url: '@Url.Action("SendWhatsAppTextMessage", "Home")',
    data: { LinkUrl: '', MediaId: '', Message: $("#Message").val(), RecipientPhoneNumber: $("#RecipientPhoneNumber").val(), TemplateName: '', TemplateParams: '', hdnIdConexion: $("#hdnIdConexion").val() },
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    success: function () {
    },
    error: function () {
        alert("No se ha podido enviar el mensaje.");
    }
});

If I delete the comma at the end of the JSON from data, It will send it correctly, but as it is, the properties of payload are null. I also tried passing the keys as strings to data, but I get the same result.

6
  • 2
    Use an AJAX request to the back end...no page refreshes required - simple. c-sharpcorner.com/blogs/using-ajax-in-asp-net-mvc Commented Apr 17, 2024 at 4:14
  • The page refresh causes the SignalR connection to reset. Commented Apr 17, 2024 at 4:17
  • @Alex I implemented the AJAX method from the link, but now SendWhatsAppTextMessage gets payload with null properties, although I've tried several ways to pass the JSON data. Commented Apr 18, 2024 at 18:15
  • Show us the code from your Ajax request Commented Apr 18, 2024 at 20:06
  • I edited the question to add the AJAX request. Commented Apr 18, 2024 at 20:59

1 Answer 1

1

Your AJAX request is not working because you're not using a JSON model. If you want to work with JSON, then you need to configure your view model to handle JSON serialization.

If not, then alter your AJAX request to the following:

    $.ajax({
        method: "POST",
        url: '@Url.Action("SendWhatsAppTextMessage", "Home")',
        data: { linkUrl: '', mediaId: '', message: $("#Message").val(), recipientPhoneNumber: $("#RecipientPhoneNumber").val(), templateName: '', templateParams: '', hdnIdConexion: $("#hdnIdConexion").val() },
        success: function () {
        },
        error: function () {
            alert("No se ha podido enviar el mensaje.");
        }
    });

Notice the camel case property names instead of pascal. And the lack of JSON data type. I also got rid of the anti forgery attribute, but if you need that then refer to this post: include antiforgerytoken in ajax post ASP.NET MVC

I tested the above using the following model:

// I'm assuming this is similar to what you have. 
public class SendTemplateMessageViewModel
{
    public string LinkUrl {get; set; }
    public string MediaId {get; set; }
    public string Message {get; set; }
    public string RecipientPhoneNumber {get; set; }
    public string TemplateName {get; set; }
    public string TemplateParams {get; set; }
    public string HdnIdConexion {get; set; }
}

And it works as expected. If I were you - I would alter this model to be compatible with JSON serialization. Makes for a cleaner and clearer implementation.

Hopefully this will get you going.

Sign up to request clarification or add additional context in comments.

2 Comments

You're right: I changed the Ajax request to yours and it worked! Quite probably it was because I was not using correct camelCase property names.
@George1917 excellent, good luck with the rest of your implementation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.