views:

34

answers:

1

Hello All,

I have an MVC2 application. Basically, in my Bill view, I want a user to click "Request Bill" and it calls the WCF service. The service then returns back a callback with the amount owed. I am having 2 issues.

  1. The duplex method callback from the client does not execute or does not get called. This happens intermithtently. Sometimes it gets called and sometimes it does not
  2. The second problem is that whether the callback method executes or not, the page or application closes shortly (within 2-3 seconds) after returning the view.

In my view, I have the following:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Bill
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>Bill Summary:</h2>

    <td>
     <%: ViewData["ProcessingMessage"] %>
    </td>
    <table>
        <tr>
            <th>

                Username: 
            </th>
            <th>
                Total Number of Calls: 
            </th>
            <th>
                Amount to be Paid: 
            </th>
            <th>&nbsp;</th>
        </tr>
     <td>
    <%: ViewData["Username"] %>
    </td>
    <td>
    <%: ViewData["CallsCount"] %>
    </td>
     <td>
    <%: ViewData["TotalAmount"] %>
    </td>
    </table>
</asp:Content>

In my controller, I have the following method:

public class TelephoneController : Controller
    {
BillingCallback proxy = new BillingCallback();
 public ActionResult Bill()
        {
            ViewData["ProcessingMessage"] = "Processing Request.....";
            proxy.CallService(User.Identity.Name);
            return View();
        }
}

I created a class for callback:

public class BillController : Controller
    {
        private const double amountPerCall = 0.25;
        public double calcBill()
        {
            double total = amountPerCall;
            Log p = new Log();
            return total;
        }
        public ActionResult Index()
        {
            return View();
        }
    }

Now for the service:

[ServiceContract(CallbackContract = typeof(IBillCallBack))]
    public interface IBill
    {
        [OperationContract(IsOneWay = true)]
        void GetBilling(string username);
    }
    public interface IBillCallBack
    {
        [OperationContract(IsOneWay = true)]
        void CalculateBilling(string message);
    }

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
    class Bill : IBill
    {
        public void GetBilling(string username)
        {
            IBillCallBack callback = OperationContext.Current.GetCallbackChannel<IBillCallBack>();
            ThreadPool.QueueUserWorkItem(new WaitCallback(SendOperationToClient), callback);
        }
        public void SendOperationToClient(object stateinfo)
        {
            IBillCallBack callback;
            callback = stateinfo as IBillCallBack;
            string s = Thread.CurrentThread.ManagedThreadId.ToString();
            callback.CalculateBilling("username");
        }
    }

Any ideas?

A: 

That is race condition and wrong usage of duplex service.

What happens in your code:

  • You have a controller which calls service operation
  • The service operation starts new thread and returns
  • Your controller continues with processing and returns ViewResult
  • In the mean time worker thread on service process code and starts callback
  • Now if the worker is fast enough your callback is called
  • If the worker is not fast enough your View is already rendered and changes from calculation are lost
  • Moreover if worker is really slow controller is released from memory and proxy as well => callback cannot be called which probably results in exception on service

Simply don't use duplex service in web application. It doesn't make sense because you still have to wait on callback - I don't see any differnce in calling your service with request/response pattern and than calling calculation as common method.

Ladislav Mrnka
What if I wanted the user to click on Request Bill and continue working, then gets notified when the bill is ready to be viewed? So duplex arent used in web apps, what is the common use?
Mage
In that case you need AJAX
Ladislav Mrnka
Making an ajax call to the service still causes the same behavior. The browser closes when it is time to call the callback function
Mage
Hard to say what is happening. I don't know your implementation but by mentioning AJAX I meant compleatly rewriting your page. Instead of posting data it should work as partial rendering. When the user send data it will not post the page but instead it will make AJAX call for processing and later on it will modify the page on client side based on AJAX call's response. There is no need for two way communication - moreover this can be handled in ASP.NET MVC without WCF.
Ladislav Mrnka