Calling Generic HTTPHandler from Client side


In my last blog post I explain what an HTTPHandler was, and how to implement it. In this post I will explain to you how to call your HTTPHandler using JavaScript. Please note this solution uses jQuery and assumes this is already being loaded in your page. Please follow my blog inserting jquery into your sharepoint site as a feature, to ensure that jQuery is available within your SharePoint site every time, if you currently don’t load jQuery.

This demo will allow a user to enter a name of a list on the site and return some properties regarding this list. By following the initial steps from the last blog post, create your ashx file and called it ListHandler.ashx.

  • First create a ListDetails.cs class. This class will hold the properties of the SPList we wish to pass back from the handler. Right Click the Project > Add> New Item… and create the class called ListDetails.cs
  • In ListDetails.cs class we will set up 4 properties. Title, DefaultViewURL, Description, ItemCount.

public class ListDetails

    {

        public String Title { get; set; }

        public String DefaultViewURL {get;set;}

        public String Description {get;set;}

        public String ItemCount {get;set;}

    }

  • Save the ListDetails.cs file.
  • Now open the ListHandler.ashx file. From following the last blog post you should have already implemented the IHttpHandler Interface. When implementing the IHttpHandler interface we need both IsReusable and ProcessRequest. Set the IsReusable as the following.

public bool IsReusable

        {

            get

            {

                return true;

            }

        }

 
  • The ProcessRequest method is going to check for query string name called listname. Then get the SPList object, retrieve the details we want in the ListDetails class, then JavaScriptSerialize our class to write back our results out as JavaScript.

  public void ProcessRequest(HttpContext context)

        {

            var listName = string.Empty;

            //Obtain the Query String

            if (context.Request.QueryString["listName"] != null)

            {

                listName = context.Request.QueryString["listName"];

            }

            string results = String.Empty;

            try

            {

                if (!string.IsNullOrEmpty(listName))

                {

                    //Get the SPList object.

                    SPList list = SPContext.Current.Web.Lists.TryGetList(listName);

                    if (list != null)

                        //Pass SPList to get details and convert to JSON string.

                        results = GetJSON(list);

                    else

                    {

                        throw new Exception("List Not Found!");

                    }

                }

            }

            catch (Exception ex)

            {

                throw ex;

            }

            context.Response.Write(results);

        }

        private string GetJSON(SPList list)

        {

            //Initialise the JavaScript initializer

            System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();

            //Get ListDetails Class and obtain values.

            var curList = new ListDetails();

            curList.Title = list.Title;

            curList.Description = list.Description;

            curList.DefaultViewURL = list.DefaultViewUrl;

            curList.ItemCount = list.ItemCount.ToString();

            //Return Class Serialized for JavaScript.

            return serializer.Serialize(curList);

        }

If you save and deploy your project as is, and navigate to <Site>/_layouts/GenericHandler/ListHandler.ashx?listName=<listName>, replacing site and listName with your details you should see some results. For example I have passed in the list name Shared Documents as I’m using a TeamSite for the below results.

To create the front end, we are going to create a simple application page. Create a page called ListCaller.aspx.

  • Within the Content PlaceHolderMain put a Label, TextBox and Button. Below we will display the 4 values Title, Description, DefaultURL and ItemCount.

<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">

    <asp:Label ID="lblInstructions" runat="server" Text="Please enter a name of a list"></asp:Label>

    <asp:TextBox ID="txtName" runat="server"></asp:TextBox>

    <asp:Button ID="btnGetList" runat="server" Text="Get List Details" />

    <div id="listTitle"></div>

    <div id="listDescription"></div>

    <div id="listDefaultURL"></div>

    <div id="listItemCount"></div>

</asp:Content>

  • Create a JavaScript file. I have called mine ListCaller.js, this file is stored in layouts directory too.

  • Open this file. We are going to create a simple ajax call to our handler. On success it will return data from the handler, or it will throw an error. Create a function called getListDetails that is expecting the list name.

function getListDetails(listName) {

       jQuery.ajax({

        url: '/_layouts/GenericHandler/ListHandler.ashx',

        data: 'listName=' + listName,

        dataType: "json",

        contentType: "application/json; charset=utf-8",

        method: 'GET',

        success: function (data) {

            jQuery('#listTitle').html('<b>Title: </b>' + data.Title);

            jQuery('#listDescription').html('<b>Description: </b>' + data.Description);

            jQuery('#listDefaultURL').html('<b>Default URL: </b>' + data.DefaultViewURL);

            jQuery('#listItemCount').html('<b>Item Count: </b>' + data.ItemCount);

        },

        error: function (jqXHR, textStatus, errorThrown) {

            jQuery('#listTitle').text('Failed');

            jQuery('#listDescription').text('');

            jQuery('#listDefaultURL').text('');

            jQuery('#listItemCount').text('');

        }

    });

};

  • Now we need to call this JavaScript method from our aspx page. Open up your aspx page. Within the PlaceHolderAdditionalPageHead we need to add a link to the ListCaller.js file. Also here I’m going to add a JavaScript function that gets the value from within textbox and calls getListDetails().

<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">

<script type="text/javascript" src="/_layouts/GenericHandler/js/ListCaller.js"></script>

    <script>

        function details() {

          getListDetails(jQuery('#' + '<%=txtName.ClientID%>').val())

        };

    </script>

</asp:Content>

  • Lastly add an OnClientClick to your Button. Your <asp:Button will now look like below.

<asp:Button ID="btnGetList" runat="server" Text="Get List Details" OnClientClick="javascript:details();return false;"/>

By navigating to the application page, and type in a name of a library or list can click Get List Details it will return the details of that list.

Creating Generic HTTPHandler in SharePoint


HTTP Handlers are components that implement the System.Web.IHttpHandler interface. It writes some data to the server HTTP response. A file ending with .ashx. In SharePoint they are deployed to the _layouts directory. Generic handlers are a lightweight and quickier way then creating a SharePoint web service layer. I have found them especially useful in getting data from server side to the client side as JSON. They are also useful in AJAX anonymous access scenarios when you cannot use SharePoint .asmx services.

In the recent project I’ve been doing at work, we have created a few Generic HTTPHandlers to call search and return the results as JSON. This has allowed us to have a pure AJAX single page application that can call server side code.

Visual Studio Item Templates for Generic Handlers are not directly supported by Visual Studio SharePoint Projects. When you Add New Item… and search for Installed Templates in a SharePoint project, you will not find Generic Handler anywhere. The ASP.NET handler will require extra work for you making entries in the web.config just to get it to work. There are two solutions to get a Generic Handler in SharePoint:

  • Use CKSDev. By Installing CKSDev there will be a built in handler that will work for you. Just select it when Adding a New Item, and then set the Build Action to Content. Once deployed you will find it at location http://<site>/_layouts/<ProjectName>/myhandler.ashx (Make sure that you add the handler to the feature)
  • Without using CKSDev.
    • Add New Item… and add an Application page, but name the extension .ashx.
    • Delete the ashx.designer.cs file.
    • Open the .ashx file, delete the contents, and replace with the following. (Add your own GUID and ensure all letters are lower case).

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>

<%@ WebHandler Class="$SharePoint.Type.be94b0d0-ca37-4783-b8e9-06ba0477a22f.FullName$" %>

  • Open the ashx.cs file.
  • Add the using statement using System.Web
  • Add the using statement using System.Runtime.IntropServices;
  • Change your namespace if you want.
  • Change the class to inherit from IHttpHandler
  • Implement the IHttpHandler interface. (IsReusable and ProcessRequest)
  • Add [Guid(“BE94B0D0-CA37-4783-B8E9-06BA0477A22F”)] (Guid should match the Guid from the ASHX page, except uppercase)
  • In the Solution Explorer, click the .ashx file and in the Properties pane, set the Build Action to Content.
  • In the Solution Explorer, click the .ashx.cs file and in the Properties pane, set the Build Action to Compile.
  • Now we need to Save and Close the solution.
  • Edit the .csproj file and add the following text to a PropertyGroup, and reload your project in Visual Studio.
  <PropertyGroup>
  <TokenReplacementFileExtensions>ashx</TokenReplacementFileExtensions>
  </PropertyGroup>