Client Side Callbacks (AJAX technique)

After a few SharePoint posts I decided I should post some interesting things in .net. Client Side Callbacks have been something I have been using for years and I have always wondered why they don’t get more press. Client Side Callbacks are basically .nets way of wrapping the XmlHttpRequest object. As any good web developer knows (who implements Ajax) – all Ajax is is a buzzword for Asynchronous javascript and xml. However, all “real” Ajax technologies use the XmlHttpRequest to asynchrounously call the server. In fact, one of my big pet-pieves is when people use the word Ajax incorrectly (however, that is for another discussion).

So, to implement Ajax you don’t really need any of these “toolkits” like Ajax.net (formerly Atlas) or Ajax pro. These are just “toolkits” to help you implement Ajax technologies. I have found that these toolkits can produce bloatted javascript and can actually slow down an application if not used correctly. Thus, whenever I have a simple Ajax need I try to use .nets Client Side Callbacks instead of an Ajax toolkit. With that said, there are good uses for these toolkits if your business requirements meet some of their features. It is up to a good architect to determine when these should be used.

The Client Side Callback feature is available in .net 1.1 and 2.0 forward. However, the version in 1.1 is a little lacking, so I will concentrate this blog on the 2.0 version forward.

The simplest need for Ajax is to call the server asynchrounously, allow it to process information, make a call back to the client and allow the client to show the information on the screen (using javascript). The following example will show how to call the server (to get the datetime from the server) and have that datetime show up on the screen without any postbacks.

  1. First create your website and go to the code behind of your default.aspx.
  2. Implement the System.Web.UI.ICallbackEventHandler on the class.
  3. This interface will produce two methods (RaiseCallbackEvent and GetCallbackResult). Make sure both of these methods get implemented.
  4. The RaiseCallbackEvent method will be the first method called when the Callback starts. This method takes in an argument, which you can store as a member variable on your class to use in the GetCallbackResult. The GetCallbackResult method is the method in which you will build the arguments to pass back to the client side javascript.
  5. Implement the code within the RaiseCallbackEvent and GetCallbackResult methods:
  6. 
    private string _argument = string.Empty;
    
    /// The RasieCallbackEvent is the first place to receive the callback from the client's browswer when 'CallServer'
    /// is triggered.parameter passed from the Javascript's call 'CallServer'
    public void RaiseCallbackEvent(string eventArgument)
    {
        //store the argument in a local variable so we can use it in the "GetCallbackResult" method
        //later on if necessary.
        _argument = eventArgument;
    }
    
    /// The GetCallbackResult method is the second call triggered by the 'CallServer()'
    /// on the client side. This is the place to prepare a string that can be placed as
    /// html on the page.
    public string GetCallbackResult()
    {
        //run the code to add the html to the javascript callback method
        if (_argument == "getServerTimeUserControl")
        {
            //return the html
            return System.DateTime.Now.ToString();
        }
        else
        {
            return string.Empty;
        }
    }
    
  7. Next implement the page_load method like this:   
  8.   
    protected void Page_Load(object sender, EventArgs e)
    {   
           //only need to register once, so don't register when a callback is being performed
            if (!Page.IsCallback)
            {
                //Register the Ajax client script to the client's broswer
                string eventReference = Page.ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context");
                string callbackScript = "function CallServer(arg, context)" + "{ " + eventReference + "} ;";
                Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "CallServer", callbackScript, true);
            }
    }
    
  9. The page_load is registering client side scripts, so next we have to go to the default.aspx webpage and build those javascript methods:
  10. 
    function GetServerTime(argument)
    {
       //Send the request to server
       CallServer(argument, "");
    }
    
    function ReceiveServerData(argument)
    {
       document.getElementById("serverTimeUserControlArea").innerHTML = argument;
    }
    
    The ReceiveServerData is the javascript method we registerd in the page_load of the code behind, so that is the method that the client side callback will eventually write back to. The GetServerTime is our javascript method we are going to call to kick off the client side callback functionality.
  11. Build the html. This will just consist of a button to start the client side callback and a div to fill in when the information is retrieved from the server:
  12. <input type=”button” onclick=”javascript:GetServerTime(‘getServerTimeUserControl’);” id=”Button1″ />
    <div runat=”server” id=”serverTimeUserControlArea”></div>

    Thats it!
    It is that easy to implement your own, custom, Ajax solution in .net. You don’t need to implement any third party Ajax solutions to get this to work. Now that you have seen the simplest example you can use your imagination to do more complicated things. For example: You could load up user controls and render their html out to the client side with these techniques. Just be careful because the post-back never occurs, which means certain server side things never happen. You will have to play around with the technique to see what you get.

    Attached is my default.aspx and default.aspx.cs files from the example:
    Default page
    default page code behind

Debugging SharePoint

While building custom SharePoint webparts one of the hardest things is usually debugging (unless you know how to set it up correctly).

At first I would just attach to the IIS worker process in Visual Studio to do all my debugging. To do this all you have to do is click Debug/Attach to Process… in Visual Studio. Then find the SharePoint process, it is usually the w3wp.exe process that is running under your SharePoint admin account. After doing that SharePoint will pick up breakpoints in your code.

While this is good, it can take a little bit of time and it doesn’t help to get errors from your testing team or environments you don’t have debug authority over. However, SharePoint does have a way to show errors (including call stacks) right on the SharePoint page. Usually, when there is a bug in SharePoint it redirects you to a generic error page without any information on what happened. And, if your lucky, you might get some error information in your logs(but not always :) .

But, with a few web.config modifications you can get this error information to show up, on your webpage. First change the “CallStack” property to “true” in the “SafeMode” tag. Next change the “customErrors” tag “mode” to “off”. Now your SharePoint error page will show debug information.

Custom SharePoint Edit Forms with Validation

Recently I had to put extra validation on my edit form, for a list within SharePoint, and I couldn’t find one place that showed me how to do it.
I found multiple articles on how to do certain parts of creating a custom edit form, but I couldn’t find one article that put all the pieces together, thus I decided to blog my findings.

IMPORTANT NOTE: SharePoint edit/new forms dynaically create fields for themselves when new columns are added to the list. They do this with the use of a webpart called the ListFormWebpart. However, in order to make custom modifications to the edit/new form we are going to delete the ListFormWebpart and create custom HTML. Thus, after you do this the columns will not be dynamically added to the edit/new forms when the list is modified. Thus, please way the cost/benefits of using this technique.

  1.  First open your site in SharePoint designer and navigate to the list that you want to modify your edit and new forms.
    You will notice the list already has an Edit and New Form associated to it.
    Open up the form you wish to put the validation on. Eventually you should follow these steps for both the forms.
  2. Delete the ListFormWebpart that is already on the form.

    The ListFormWebpart dynamically creates the adding/editing of a form based on the items in the list, however it does not give you much in the way of modifications. So, unless you have specific requirements about customizing the edit or new forms (i.e.: custom validations), I would not recommend doing this.


     Note: some people told me in the comments they had trouble if they deleted this existing ListFormWebpart. There is a workaround if you have this issue – just hide the ListFormWebPart instead of deleting it. Thank you to Rajan for this response. Here is the workaround: Right click on the ListForm webpart in the sharepoint designer and click web part properties and then under layout, check the hidden check box

  3. Click Insert – SharePoint Controls – Custom List Form
    A Wizard will popup – choose the list this should be associated to and whether or not you are dealing with a new or add.
  4. Find the control you want to place the validation on, right click on it in the designer, and click Show Common Control Tasks
  5. Change the “Format As” dropdown from “List Form Field” to the type of control it should be (i.e. TextBox).

    The “List Form Field” can figure out the type based on the type in the SharePoint list it is bound to. However, you can’t do server side validations against it. Thus, we have to set it to a type of control we can have server side validations against.


  6. In the toolbox drag the server side validation you want on the form and set its properties. Note: to get the property for the “ControlToValidate” just copy the id from the control you are validation (that way you get the dynamically bound id) 

Thats it! You now have custom validation on your form.

Also, now you can modify the html of your edit/new form however you want. For example I have removed the SharePoint:SaveButton and replaced it with an asp.net button that calls some custom javascript and the javascript to do the save. I am mentioning this because now that you have complete control over the html in your edit/new forms you can completely modify it to meet whatever requirements you have.

Removing menu items from SharePoint list

When removing menu items from a SharePoint action research will lead you to believe that you can create a new feature called HideCustomAction. However, this will only work for top level actions such as Site Actions.
So, what do you do when you need to remove a menu item from the list item.
On a SharePoint list the user can do things like Edit Items, Delete Items, Manage Permissions, Alert Me, etc. However, what if you don’t want something like the Edit Items link.

To do this you must modify javascript.
1. Locate the Core.js

2. Find the javascript method that creates the menu. You can do this by searching for the text, such as “Edit Item”. The first place you will find this text is in a variable such as “L_EditItem”. Then if you do a search on that variable you should find the method where the menu item is added. For example: Edit Item is added in AddSharedNamespaceMenuItems.

3. Lastly, modify the javascript to not show the menu item. For the Edit Item example:


function AddSharedNamespaceMenuItems(m, ctx)
{
   if(ctx.listTemplate != 105)
   {
       ….
   }
   AddManagePermsMenuItem(m, ctx, ctx.listName, currentItemID);
}

Now the Edit items wont show up for any list template number 105 (105 is the Contact List). If you want to do this for another type of list just find that list number in the feature of that list.

Note: I would not recommend changing the default Core.js to do this funcitonality. I would create a new custom javascript file and reference that from a custom master page file for the page. Thus, you can just use the custom master page for all pages that you want this functionality.