ASP.NET UserControl in an ASMX Service

In my Photo Gallery project I have been looking for a way to remove all post backs and utilize AJAX calling web services to update content. I was having a difficult time moving a static page method from the page code behind to web service (asmx) page.

The difficulty was occurring because I have a ASP.NET UserControl that requires some data for initialization. My previous implementation was calling a setter method exposed by the UserControl. This worked fine in the code behind for the page, because I could cast the result from the pages LoadControl command to my UserControl type. Then I could access the setter method.

In the web service code, the casting from the generic UserControl type was not allowed (or at least I could not figure out how to do it). After some searching I found an article by Scott Guthrie that described how to overcome this issue using reflection. The following is the code for the web service using this method:

[WebMethod(EnableSession = true)]
public string GetThumbHtml(string relativePath)
{
    // Create the full path.
    //
    string rootDirectory = ConfigData.RootGalleryDirectory;
    string fullPath = Path.Combine(rootDirectory, relativePath);
    fullPath = Path.GetFullPath(fullPath);

    // Create a page object to faciliate the rendering.
    //
    Page page = new Page();

    // Create a place holder to hold the controls
    //
    PlaceHolder placeHolderThumbs = new PlaceHolder();
    page.Controls.Add(placeHolderThumbs);

    // Get all the object contained in this folder.
    //
    List<GalleryObject> allItems = GalleryManager.GetAllObjects(fullPath, CurrentUser);

    // Add each item to the page.
    //
    foreach (GalleryObject item in allItems)
    {
        // Create a user control for this item.
        //
        try
        {
            UserControl imageControl = page.LoadControl("ImageFrame.ascx") as UserControl;
            Type imageControlType = imageControl.GetType();
            FieldInfo field = imageControlType.GetField("Item");
            if (field != null)
            {
                field.SetValue(imageControl, item);
            }
            placeHolderThumbs.Controls.Add(imageControl);
        }
        catch (Exception ex)
        {
        }
    }

    StringWriter output = new StringWriter();
    HttpContext.Current.Server.Execute(page, output, false);

    return output.ToString() + "|" + GetPathHtml(relativePath);
}

The purpose of the web service is to return HTML to an AJAX call that can then be used to update the page content. Towards the top of the method you can see that I am creating a Page object. This object is needed to pass into the ASP.NET rendering engine. In the foreach loop is where I am dynamically creating the UserControl. I then use a little reflection to find the data field and set its value. The trick is the call to the Server.Execute function near the bottom. This method the runs your page through the rendering engine. This causes the UserControl’s load event to be fired. The data field previously set is available for use in the load event.

Leave a Reply

Your email address will not be published. Required fields are marked *

*