Creating ASP.NET AJAX control with the ability to exchange data with the server

    Hello, Habr!

    I want to share my experience in solving a problem, the answer to which I can hardly find on the Internet (Russian-speaking - for sure).

    I recently encountered the fact that I was instructed to write ASP.NET AJAX control of the server side. This is such a control that is available when editing an ASP.NET page in the designer (toolbox), part of its logic is on the server, and part on the client, the interaction is ajax. The essence of my control is a simple ComboBox, which would receive data dynamically from the server (it is assumed that there is so much data that it is impossible to load all at once), and also filter the list based on the characters entered in the text field. This is almost implemented in the AJAX Control Toolkit, only the whole list is loaded there.
    On the Internet there are a lot of various articles and blogs on the topic of creating your own controls, however, oddly enough, they are all limited to simple examples, which completely lack a description of the mechanism of interaction between the client and server. Most sources quote from standard Microsoft textbooks, where the ajax is that when you mouse over a button, it changes its image (kindergarten). I had to get the data from the list that was stored on the server to the list on the client (it could just be a list, some kind of ORM, and in general everything that happens IEnumerable).

    I want to say right away that here you will not find a manual for creating your own control from scratch, since there is enough information on this part of the documentation. I will describe how to make sure that the client part and its server half can freely exchange information in asynchronous mode.

    I will pass to the point. There are several ways in ASP.NET that the client can request data from the server asynchronously. The most convenient of them is interaction through a web service. This approach allows you to transfer data back and forth in any form convenient for you, starting from the line, ending with full-fledged objects (including composite ones). ASP.NET does all the serialization for you. However, for all its attractiveness, this approach could not be applied to my task, since control with all the functionality of “out of the box” was required. That is, he added it to the page, indicated the data source, and that’s all - he will do the rest for you. A web service cannot be included in the component assembly, and, accordingly, on subsequent pages that use it.

    The second method is to implement the ICallbackEventHandler interface . This interface serves to indicate that the control that implements it can be the target of the client side callback event (MSDN). This interface provides two methods: RaiseCallbackEvent , which receives event data from the browser in a string parameter, and GetCallbackResult , which is responsible for returning the result back.
    This approach was the most acceptable for me, since ajax functionality will always be under control, no matter where it is. I will now give the code of the server and client sides to clarify the situation.

    Server side:
    1. #region ICallbackEventHandler implementation
    2.  
    3. public void RaiseCallbackEvent(string eventArg)
    4. {
    5.   m_callbackEventArg = eventArg;
    6. }
    7.  
    8. public string GetCallbackResult()
    9. {
    10.   string result = "";
    11.  
    12.   if(DataSource != null)
    13.   foreach (object o in DataSource)
    14.   {
    15.     string item = o.ToString();
    16.  
    17.     if (item.StartsWith(m_callbackEventArg))
    18.       result += item + "||";
    19.   }
    20.  
    21.   if (result.Length > 2)
    22.     return result.Substring(0, result.Length - 2);
    23.   else
    24.     return "";
    25. }
    26.  
    27. #endregion

    The RaiseCallbackEvent method only remembers the string that came from the client. It stores the text that the user entered on the site in the input field of our control. Sample results will be filtered by this value.
    The GetCallbackResult method is endowed with a bit more logic. Here we go through the list by elements (stored in a DataSource), each line in it is compared with the filter value, and if everything is fine, it is entered into the result. Yes, it is worth noting that the drawback of this approach is that both the query and the result must be a string. That is, it is our concern how to serialize data. In my case, it was enough to separate different lines with the substring ||, however, for more serious projects, it would be necessary to get confused.

    Now let's take a look at the client code:
    1. _populateListBegin: function() {
    2.   if (this.get_loadDynamically() == false) {
    3.     this._filterList(this._textFilter);
    4.     this._displayList();
    5.   }
    6.   else {
    7.     WebForm_DoCallback(this.get_element().id, this._textFilter, this._onPopulateListComplete, this.get_element().id, null, true);
    8.   }
    9. },
    10.  
    11. _onPopulateListComplete: function(result, context) {
    12.   var rscb = $find(context);
    13.   rscb._processCallbackResult(result);
    14. }

    This code is part of a prototype list object implemented in JavaScript on the client. The first function is called when the user clicks on the “expand” button on the list (event registration and button code are omitted, as it relates to another topic). An interesting point for us is the call to the WebForm_DoCallback function , which starts the process of accessing the server side. As parameters, it takes the ID of the object that caused the callback request, the request parameter (string), the delegate to the response handler function, the context that can be used to process the response, the delegate to the error handler function (we do not need it here simplicity of control), and a Boolean parameter, which means sending asynchronously or not. Actually this is all the magic of ajax request.
    Function_onPopulateListComplete will be called when a response is received from the server. It should be noted that it is not executed in the context of the object, so accessing this may give the wrong result. That is why I passed the object id in the context.

    Here is all the little that needs to be done when implementing server control with full AJAX exchange. Do not hit hard, this is my first post. If you have any questions on the content (I'm sure they will) - I will answer in the comments with pleasure.

    Also popular now: