We have an ASP.NET MVC 5 app that loads an MVC view: Purchase.cshtml. This view loads an iframe in a DIV for a 3rd-party credit card processor: The user enters their credit card details in the iframe and clicks "PAY". When done,

  • The credit card processor calls a Web API method, api/callback, to let us know the payment was successful within a few seconds of the user clicking "PAY". Here we record the payment in our system and use a Progress object to notify the user of the progress of this process.
  • Also, the credit card processor's iframe redirects to one of our MVC pages -- Receipt.cshtml. We use a bit of JavaScript to break out of the iframe on page load. Here, we are still in the same MVC session because we never left our site.

The web API controller is called by the 3rd-party company but it will have the username of the person who initiated the call (which we store in private field _userEmail). In the api/callback method here, we use this to track the progress:

var progress = new Progress<IPaymentProgress>();
progress.ProgressChanged += OnPaymentProgressChanged;

And these handlers:

private async void OnPaymentProgressChanged(object obj, IPaymentProgress e)
{
    await NotifyClientPaymentProgressChanged(e);
}

private async Task NotifyClientPaymentProgressChanged(IPaymentProgress progress)
{
    var context = Microsoft.AspNet.SignalR
        .GlobalHost.ConnectionManager.GetHubContext<PurchaseHub>(); 
    await context.Clients.User(_userEmail).handlePaymentProgressUpdate(progress);
}

In Receipt.cshtml, we have this JavaScript:

$(function () {
    // If page is in iframe, exit it and display fullscreen.
    if (self !== top) {
        top.location.replace(self.location.href);
    }
    $("#progressModal").modal("show");
    var purchaseHubProxy = $.connection.purchaseHub;

    purchaseHubProxy.client.handlePaymentProgressUpdate = function (progress) {
        console.log(progress);
        $('.progress-bar').css("width", progress.Percentage + "%");
        $("#progressMessage").text(progress.Message);
    };

    // Start the connection to get events
    $.connection.hub.start().done(function () {
        console.log("SignalR connected");
    });
});

The above console.log produces the statement SignalR connected after a few seconds. However, we get nothing else.

Is it possible for the Web API method, triggered by a 3rd party app, to communicate with our MVC page via SignalR? Are we dealing with two disconnected sessions between these -- the Web API and MVC -- and we can't send SignalR between them? If not, what is the best way to push the progress to the view after the Web API method gets triggered by the external credit card processing company?

Note: We've used this same code to communicate via SignalR on MVC pages successfully. However, we've never tried doing so from Web API to an MVC view.

Update: Found a solution that avoids this headache altogether: the 3rd party cc processor 1st calls our web API method then redirects the iframe to our MVC method to load the view (it's not async but sync). So in web API we'll write a record to our db indicating successful payment. Then in MVC method, we'll check for that; if it's there, we'll do the progress bar updates via SignalR -- which should be a piece of cake.

0 Answers