Updates from June, 2009 Toggle Comment Threads | Keyboard Shortcuts

  • aftab 5:50 pm on June 2, 2009 Permalink | Reply
    Tags: Ajax, asp.net, callback, clientside, ecmascript, ICallbackEventHandler, javascript   

    Client Callbacks in ASP.Net 

    By Default ASP.Net pages communicate with the server through a mechanism call “PostBack”. Postback is very useful and efficient, except for the cases, where 1) You have a huge page, with a lot of processing required at server, so doing all that processing on every postback is not only waste of resources on the server, but also hurts the user experience. 2) You have client side variable, which will be lost on page refresh(i.e. postback).

    You can avoid both these limitations by introducing Client Callbacks in your application. In a client callback a client side event makes a request to the server, at server the page is initiated, it members are created, however page runs a modified version of its life cycle and only method that is marked for invocation is called; that, then can return a value that can be read using another client side function.

    Through out this process, page is available to the user and results are quick in most of the cases as on a small amount of data is being exchanged between client and the server.

    To implement client callbacks you need to do some work both on server side as well as client side.

    On server side, you need to:

    1. Implement ICallBackEventHandler in the page, that you want to use callbacks in. It have two methods i.e. RaiseCallbackEvent and GetCallbackResults
    2. Provide implementation for RaiseCallBackEvent, this is the method is invoked by the client to perform callbacks. This method accepts string as an argument.
    3. Provide implementation for GetCallbackResults, this method is invoked by the server, to process the request and return the results to the client as a string
    4. Retrieve a reference of a client side function (Using ClientScript.GetCallbackEventReference method), this function will be invoked as the result of server side processing, and it can be used to process any results coming back from server
    5. Register a client side script, using Page.ClientScript.RegisterClientScriptBlock method, that will make a call to the server. 

    On ClientSide, you need to:

    1. Implement the function that you provided as an argument in step 4 above
    2. Call the function you registered in step 5 above, on a client side event.

    Lets look at the code that you will use to implement your client call backs. In our demo project, we have two comboboxes on our asp.net page. One contains a list of departments and other a list of employees in the selected department. What we want to do is, fill employee combobox with the respective department employees, whenever our user changes department in Department combobox, without doing a postback.

    First things First; Implement ICallbackEventHandler interface

    public partial class _Default : System.Web.UI.Page,ICallbackEventHandler

    Implement two methods of ICallbackEventHandler

    #region ICallbackEventHandler Members
        /// <summary>
        /// this method Returns the results of a callback event.
        /// </summary>
        /// <returns></returns>
        public string
    GetCallbackResult()
        {
            //as only strings can be sent back to the client, we are will iterate through the list of
            //employees and convert it into comma delimited string
            string employeelist="";

            foreach (Department dept in departmetList)
            {
                if (dept.Name == deptArg)
                {
                    foreach (Employee emp in dept.Employeelist)
                    {
                        employeelist += emp.Name;
                        employeelist += ",";
                    }
                }
            }

            return employeelist;
        }

        /// <summary>
        /// This method is invoked by the client, this will be used to receive parameter values from the client
        /// </summary>
        /// <param name="eventArgument"></param>
        public void
    RaiseCallbackEvent(string eventArgument)
        {
            //right now all we are doing is to set the class level variable to eventArgument
            //that was sent by the client, recall that it is departments name.
            deptArg = eventArgument;
        }

    In your page_load event handler, first retrieve the reference of client function that will be invoked as the result of call back using ClientScriptManager.GetCallbackEventReference,

    string callbackEventReference = Page.ClientScript.GetCallbackEventReference(this, "arg", "GetResults", "");

    this method has several overloads, the one we have used takes target (in this case “page”), the “argument” that was passed by the client, name of the client side event handler that received the result of callback event and context as arguments. Context is any client script that will be evaluated prior to making a callback request. In this case we have passed an empty string.

    Then you need to build and register a client side script, that will call this CallBackEventReference, this is the script that will make the call to the server.

    string callbackScript;

    callbackScript = "function CallServer(arg){" + callbackEventReference + ";}";

    //register callbackScript with the client using ClientScriptManager.RegisterClientScriptBlock
            Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "CallServer", callbackScript, true);

    So this was all that you need to do in our server side code, and now we will look at the client side code that we need to write to complete our client Callback.

    First we will write the function (using ECMAScript) in script block of our aspx file, GetResults; that we have been referencing in our code above,

        function GetResults(result)
        {
            if(result!="")
            {
            var array=result.split(",");
            for (var i=0;i<array.length;i++) {
            option = new Option(array[i],array[i]);
            var slc_target = document.getElementById("ddlEmployee");
            slc_target.options[i] = option;
            }       

            }
            else
            {
            //do something
            }
        }

    This function is accepting results; which is a string and it is splitting it into an array. Then all it does is, bind “ddlEmployee” a combobox on the page, with this array.

    and finally on a client side event of another combobox, “ddlDept”, we will invoke “CallServer” client side function that we registered using our serverside code and we will pass department as an argument.

    <asp:DropDownList Width="100" ID="ddlDept" runat="server" OnChange="CallServer(ddlDept.value)">

    I have attached the demo VS 2008 sollution here, when you run the project, you can see that, whenever you change any value in the Department Combo box, values in Employees combobox are refereshed without making a postback to the server.

    Download demo project here

    And Happy Programming!

     
    • RRaveen 10:36 am on July 2, 2009 Permalink | Reply

      Dear Friends,

      I hope you are doing well. I have launched a web site http://www.codegain.com and it is basically aimed C#,JAVA,VB.NET,ASP.NET,AJAX,Sql Server,Oracle,WPF,WCF and etc resources, programming help, articles, code snippet, video demonstrations and problems solving support. I would like to invite you as an author and a supporter. Looking forward to hearing from you and hope you will join with us soon.

      Please forward this email to all of your friends who are related IT. Send to us your feed about site also.

      Thank you
      RRaveen
      Founder CodeGain.com

  • aftab 2:43 am on May 29, 2009 Permalink | Reply
    Tags: , , , ConfigurationElementCollection, , ,   

    Writing a complex custom configuration section 

    Technorati Tags: ,

    Here i posted another entry, showing implementation of a simple configuration section, now consider following listing

    <customSection>
        <elements>
          <add name=”FirstAssembly.FirstType” assembly=”FirstAssembly” shouldrun=”true”></add>
        <add name=”SecondAssembly.SecondType” assembly=”SecondAssembly” shouldrun=”true”></add>
        </elements>
      </customSection>

    here we have “n” number of elements in the custom configuration section. To handle this kind of scenario, System.Configuration namespace provides you with ConfigurationPropertyCollection class and ConfigurationPropertyCollectionAttribute class. Your can use ConfigurationPropertyCollection to programmatically write you configuration section and ConfigurationPropertyCollectionAttribute  can be used to do the same job declaratively.

    There are following steps involved in creating a custom configuration section handler with multiple entries.

    1. Define a class (say CustomElement) to represent configuration section by inheriting it from ConfigurationElement class
    2. Define a class to represent your configuration collection (say CustomeElementCollection) by inheriting it from ConfigurationElementCollection, this will hold a collection of the type you defined in step 1.
    3. Define a class to represent your custom section (say CustomSection) by inheriting it from ConfigurationSection and Implement a property of type that you defined in step 2.

    Here is the listing for CustomeElement Class

    public class CustomElement : ConfigurationElement
        {
            public CustomElement()
            {

            }

            [ConfigurationProperty(“name”, IsRequired = true)]
            public string Name
            {
                get { return (string)this[“name”]; }
                set { this[“name”] = value; }
            }

            [ConfigurationProperty(“assembly”, IsRequired = true)]
            public string Assembly
            {
                get { return (string)this[“assembly”]; }
                set { this[“assembly”] = value; }
            }

            [ConfigurationProperty(“shouldrun”, IsRequired = true)]
            public bool ShouldRun
            {
                get { return (bool)this[“shouldrun”]; }
                set { this[“shouldrun”] = value; }
            }
        }

    and here is the listing for CustomElementCollection Class, its implementation is similar to any other Collection class,

    public class CustomeElementCollection : ConfigurationElementCollection
        {
            public CustomeElementCollection()
            {
                CustomElement myElement = (CustomElement)CreateNewElement();
                Add(myElement);
            }
            public void Add(CustomElement customElement)
            {
                BaseAdd(customElement);
            }

            protected override void BaseAdd(ConfigurationElement element)
            {
                base.BaseAdd(element, false);
            }

            public override ConfigurationElementCollectionType CollectionType
            {
                get
                {
                    return ConfigurationElementCollectionType.AddRemoveClearMap;
                }
            }

            protected override ConfigurationElement CreateNewElement()
            {
                return new CustomElement();
            }

            protected override object GetElementKey(ConfigurationElement element)
            {
                return ((CustomElement)element).Name;
            }

            public CustomElement this[int Index]
            {
                get
                {
                    return (CustomElement)BaseGet(Index);
                }
                set
                {
                    if (BaseGet(Index) != null)
                    {
                        BaseRemoveAt(Index);
                    }
                    BaseAdd(Index,value);
                }
            }

            new public CustomElement this[string Name]
            {
                get
                {
                    return (CustomElement)BaseGet(Name);
                }
            }

            public int indexof(CustomElement element)
            {
                return BaseIndexOf(element);
            }

            public void Remove(CustomElement url)
            {
                if (BaseIndexOf(url) >= 0)
                    BaseRemove(url.Name);
            }

            public void RemoveAt(int index)
            {
                BaseRemoveAt(index);
            }

            public void Remove(string name)
            {
                BaseRemove(name);
            }

            public void Clear()
            {
                BaseClear();
            }

        }

    and Finally, here is the listing for CustomSection Class,

    class CustomSection:ConfigurationSection
        {
            CustomElement element;
            public CustomSection()
            {
                element = new CustomElement();
            }

            [ConfigurationProperty(“elements”, IsDefaultCollection = false)]
            [ConfigurationCollection(typeof(CustomeElementCollection),AddItemName=”add”,
                ClearItemsName=”clear”,
                RemoveItemName=”remove”)]
            public CustomeElementCollection Elements
            {
                get {
                    return (CustomeElementCollection)base[“elements”]; }
            }
        }

    Next add following settings to your configuration file

    <configSections>
        <section name=”customSection” type=”ConfigurationDemo.CustomSection, ConfigurationDemo” />
      </configSections>

      <customSection>
        <elements>
          <add name=”FirstAssembly.FirstType” assembly=”FirstAssembly” shouldrun=”true”></add>
        <add name=”SecondAssembly.SecondType” assembly=”SecondAssembly” shouldrun=”true”></add>
        </elements>
      </customSection>

    in the end put this custom section to use like this,

    CustomSection myCustomSection = (CustomSection)ConfigurationManager.GetSection(“customSection2”);

                foreach (CustomElement element in mySecondSectionHandler.Elements)
                {
                    if (element.Name != null && element.Name != “”)
                    {
                        string name = element.Name;
                        string assembly = element.Assembly;
                        bool shouldrun = element.ShouldRun;
                    }
                }

     
    • Raza Ali 11:57 am on May 18, 2011 Permalink | Reply

      Thanks! Alhamdulillah! It solved my problem.

    • Michel Abi Raad 12:56 pm on August 29, 2011 Permalink | Reply

      Thanks for this beautiful and easy way of illustration. However, I have one note and one question.

      Note: I guess there is a bug in the “foreach” in the last listing. There is no “mySecondSectionHandler” defined; you should replace this identifier by “myCustomSection”. That is, the second statement in the last listing should be:

      foreach (CustomElement element in myCustomSection.Elements)

      Question: I tried to write to add new elements at runtime to the file, but they do not get saved, even though I used the Configuration.Save method. May you show that please?

      Thanks

c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel