Feb 12

ASP.NET AJAX and Unknown Web Method

The ASP.NET AJAX toolkit includes controls, such as the DynamicPopulateExtender, which invoke methods on the pages on which they are included to obtain data. This post looks at a common problem and its under-documentated solution.

When you work with open source projects, you get spoiled: sometimes there's good documentation, usually there's a good community, and you always get access to the code. Rarely is life so good when using the proprietary Microsoft stack.

The DynamicPopulateExtender AJAX control (demonstration) is a control which lets you populate a region of the page with a string (probably HTML) in response to another element being clicked. I'm trying to use it to create a control similar to the autocomplete text boxes that one tends to come across these days, only I'd like it to be rendered as a drop-down list - I don't want to post back arbitrary text.

The ListSearch is almost there; but I don't want to always download a 100,000-row dataset to my page to render. I would like the search to take place as I type, and for the server to populate the dropdown on the client with results in real time. I'm hoping that the DynamicPopulateExtender will allow me to squirt a list out to the client dynamically.

The aspx page will look something like this:

<asp:ScriptManager 
runat="server"
ID="_scriptManager"
/>

<ajaxToolkit:DynamicPopulateExtender
TargetControlID="_updateTarget"
runat="server"
ID="_searchExtender"
PopulateTriggerControlID="_searchBox" 
ServiceMethod="Foo"
ServicePath="TestTA.aspx"
/>

<asp:TextBox
ID="_searchBox"
runat="server"
/>               
<asp:Panel ID="_updateTarget" runat="server">
    <em>Enter search phrase...</em>
</asp:Panel>

Pretty simple. The idea here is that when you click on the _searchBox TextBox, the browser invokes the 'Foo' method on the TestTA.aspx page. This method returns a string which is plugged right into the _updateTarget panel.

According to the docs (and all the other blogs that are out there) your code behind should contain something like this:

using System.Web.Services;
using System.Web.Script.Services;

namespace Test
{
    public partial class TestTA : System.Web.UI.Page
    {
        [WebMethod]
        [ScriptMethod]
        public string Foo(string contextKey)
        {
            return "Hello world!";
        }

    }
}

Again - no surprises there. Note that you need to decorate your method with both [WebMethod] and [ScriptMethod].

Except - it doesn't quite work. When you click the element on the page, you'll find an HTTP 500 error returned. Digging into your logs, you'll find something like this:

Exception information: 
    Exception type: ArgumentException
    Exception message: Unknown web method Foo.
Parameter name: methodName

The key missing piece is that the Foo method must be marked as static. This wasn't mentioned explicitly in any how-tos that I found (although the code on an MSDN blog post includes it).

Your final code-behind will therefore look something like this:


using System.Web.Services;
using System.Web.Script.Services;

namespace Test
{
    public partial class TestTA : System.Web.UI.Page
    {
        [WebMethod]
        [ScriptMethod]
        public static string Foo(string contextKey)
        {
            return "Hello world!";
        }

    }
}


I hope that stops someone else tearing their hair out.

Comments

1 Chris Georgakopoulos says...

Tnx Tnx Tnx !!!

Posted at 11:55 a.m. on November 10, 2008

2 Teddy Ruxpin says...

Hi, thanks for your note on using static. I was about to start crying like a baby.

BTW, not sure if [ScriptMethod] is required...I believe adding this does introduce a large surface area for attackers, where if you can get away with just the features of [WebMethod], you should just use that.

Thanks!

Posted at 2:28 p.m. on December 31, 2008

I've disabled comments for now due to spam problems - I'll turn them back on when I've fixed it!

This won't be published anywhere, it's just in case I need to contact you.

You can use Markdown in your comments. Be sensible!

Sorry about this, but I don't want spam comments.