Skip to content

Optimizing network calls

padzikm edited this page Dec 12, 2015 · 7 revisions

Examples of this you can find in PubSubCache controller

When rendering different widgets you probably won't do it at server side when handling request, but rather you will return layout with javascript from each widget that will call its service when page is loaded to get desired content. With many widgets on page this may lead to many server requests. We may solve this easily using integration all services into one process - during page loading each widget's javascript code will register its need for data in javascript object provided by main application. At the end when page loads and all widgets will register themselves for data, one ajax call will be make to main application public api, that will gather data from all services and send it back. After ajax call completes successfully, callback for each data request will be invoked, passing data returned from application. Because each service knows what it wants to get, it will gather its data from whole response.
Example of making one call for data on page loads:
Main application javascript code:

<script type="text/javascript">
    var ajaxRequests = []; //each service registers its querystring and callback
    $(document).ready(function() {
        $(window).load(function () { //invoking as the last onpageload handler
            var ajaxData = "";
            for (var i = 0, len = ajaxRequests.length; i < len; ++i) {
                ajaxData += ajaxRequests[i].queryString;
                if (i < len - 1)
                    ajaxData += "&";
            }
            $.ajax({
                method: "GET",
                url: "@Url.Action("GetDataForThisPageAction")",
                data: ajaxData,
                success: function (data) {
                    for (var i = 0, len = ajaxRequests.length; i < len; ++i)
                        ajaxRequests[i].callback(data); //each service's callback is invoked passing returned data
                }
            });
        });
    });
</script>

Main application action method gathering data:

[HttpGet]
public ActionResult GetDataForThisPageAction()
{
    var vms = await GenerateJsonViewModels();
    return Json(vms, JsonRequestBehavior.AllowGet);
}

Service action returning data for its widgets:

[HttpGet]
[InternalAction]
public ActionResult GetDataForThisPageAction(parameters_from_query_string)
{
    var data = //gather data for all widgets from this service
    return JsonViewModel(data);
}

Because this request goes to main application public api and therefore it is published to all services, each service has to provide data for all its widgets. This isn't a problem, because when we render view models from one service we may define data that is returned as one common object as we want - for example it will be one object, that will have many objects inside, each of them will be named the same as widgetId for which it carries data. Because main app only gathers objects from all interested services, it has to have a way to combine them into one object and farther each service must know how to unpack this data and find its response. To solve this each object returned from service is packed into object with two properties - Object which is returned data, and Name which is by default servicename because it is unique and there won't be in response two objects with the same name. As a result, when data returned from ajax is passed to service handler, it looks for object with name property that matches its servicename and unpacks it knowing what to get from it.
Because JsonViewModel only returns data and is not executed, we can't cache it directly and we also can only return objects, therefore some widgets will have to directly ask for their conent to their services. In this way we can balance between caching content and optimizing network calls - for widgets that can be cached, or need to be rendered server-side we make direct ajax calls to service and for those that only need data we make one common ajax call.

Clone this wiki locally