2

I have a long db networking call and I want to populate my model in chunks. We are talking about asp.net MVC. I have a vague idea that each time a new chunk is available I should trigger the model.Bind() but I don't know how to do the plumbing between

a) the service which is providing the data in chunks- it's implemented using the event pattern- each time a new chunk is available an event is triggered, but which event ? It should hold a reference to the model?

b) the data which will be bound to the model ( i suppose it should not be an bind(), but an addition to some collection)

c) if everything is ok in steps a and b, then the changes will be propagated to the view without further a do?

Elena
  • 829
  • 1
  • 10
  • 26

2 Answers2

3

You could use long polling with a hidden iframe and chunked transfer encoding from the server which will spit <script> tags as data becomes available. In this script tag you could invoke a custom callback javascript function that will take care to format the results.


UPDATE:

As requested in the comments section here's a sample implementation of a long polling technique using a hidden iframe.

Let's suppose that you have some model:

public class MyViewModel
{
    public string Foo { get; set; }
}

and that you have a service that returns this model in chunks and notifies the caller that a chunk is available using events:

public class MyService
{
    public void GetModels(Action<MyViewModel, object> onModelAvailable, object state, Action onComplete)
    {
        Task.Factory.StartNew(x =>
        {
            try
            {
                for (int i = 0; i < 10; i++)
                {
                    onModelAvailable(new MyViewModel
                    {
                        Foo = "foo " + i
                    }, x);
                    Thread.Sleep(1000);
                }
            }
            finally
            {
                onComplete();
            }
        }, state);
    }
}

Now, we could have the following controller:

public class HomeController : AsyncController
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult LongPoll()
    {
        var service = new MyService();
        return new MyActionResult(service);
    }
}

and the following view:

<script type="text/javascript">
    // we define a callback function which will be invoked
    // when a chunk is available from the server
    var callback = function (model) {
        // the model variable passed here will represent the chunk
        $($('<div/>', {
            html: model.Foo
        })).appendTo('#result');
    };
</script>

<iframe style="display:none;" src="@Url.Action("longpoll")"></iframe>
<div id="result"></div>

Now the last part of course is the implementation of the custom action result which will do the chunked transfer:

public class MyActionResult : ActionResult
{
    private readonly MyService _service;
    public MyActionResult(MyService service)
    {
        _service = service;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        var response = context.HttpContext.Response;
        response.BufferOutput = true;
        response.ContentType = "text/html";
        var wait = new ManualResetEvent(false);
        _service.GetModels((model, state) =>
        {
            var httpResponse = (HttpResponseBase)state;
            httpResponse.BufferOutput = true;
            httpResponse.ContentType = "text/html";
            var serializer = new JavaScriptSerializer();
            var script = string.Format(
                "<script type=\"text/javascript\">window.parent.callback({0});</script>",
                serializer.Serialize(model)
            );
            httpResponse.Write(script);
            httpResponse.Flush();
        },
        response,
        () =>
        {
            wait.Set();
        });
        wait.WaitOne();
    }
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • I don't think that solves my issue. Because I want my model to be updated in chunks, not when an operation is completed. The behaviour would be : 5 items appear on the UI, then 10 and so on.. – Elena Jan 17 '12 at 15:15
  • So you want the UI to be updated when new data of the model becomes available? – Darin Dimitrov Jan 17 '12 at 15:16
  • exactly and not loosing the previous received data – Elena Jan 17 '12 at 15:16
  • This is not going to be an easy task. Event models are not adapted to ASP.NET MVC. You could use a long polling technique. One possible implementation is with a hidden iframe: http://en.wikipedia.org/wiki/Comet_(programming)#Hidden_iframe – Darin Dimitrov Jan 17 '12 at 15:17
  • could you elaborate on the long polling technique? In this case, the UI update is quite important, as they want to have to data to play with as soon as possible. – Elena Jan 17 '12 at 15:19
  • @Elena, sure I have updated my answer to show an example of implementing long polling using a hidden iframe. – Darin Dimitrov Jan 17 '12 at 16:03
1

The simplest solution is to use polling, just some ajax call every n-seconds to check if new data is available. Downsides to this approach: latency, server load. Advantages: rather simple to implement. A better but much more involved solution is to use something like long-polling, web-sockets, etc.. If this feature is worth the trouble then take a look at Signal-R, which is an async signaling library for ASP.NET to help you build real-time, multi-user interactive web applications. Adding it to an ASP.NET MVC 3 web application is very straightforward. This is a good intro to the library: Asynchronous Scalable Web Applications With Realtime Persistent Long running Connections With SignalR

santiagoIT
  • 9,411
  • 6
  • 46
  • 57