On a project I worked with recently we needed a preview of the number of search hits on the page before we submitted the search form. The form included a large amount of search properties so this made it easier for the users to see if there will be any hits or not, also faster than hitting search and waiting for the results to load.
So the first part is the page method, a
static method with the WebMethod and ScriptMethod attributes. This way the method will available ajax calls. The reason I choose to use a page method and not a web service (
asmx or wcf) is that I only needed this on one page and having an web service felt like overkill. In this example the method takes a string as input (named ids) and returns 2 integers using a
tuple.
public partial class Search : Page
{
[WebMethod]
[ScriptMethod]
public static Tuple<int,int> SearchHits(string ids)
{
return new Tuple<int,int>(1,0);
}
}
Second step is to call the method with
jQuery using the Ajax function. The URL in the call should be to the page and then with appended slash and the name of the method you want to call. In this example I've set the timeout to 10000 since the default timeout is 1000ms and my development machine was to slow so I ended up with a lot of failed requests. The function for success receives an object from the server that has one property called d this is due to some XSS protection added by asp.net, the tuple class has 2 properties Item1 and Item2 so to access one of the I use msg.d.Item1. The
json syntax for the data field is quite simple, just a sequence of name:value quoted unless it's numbers or booleans.
$.ajax({
type: 'POST',
url: '/Search.aspx/SearchHits',
data: "{'ids':'" + ids +"}",
contentType: 'application/json; charset=utf-8',
dataType: 'json',
timeout: 10000,
success: function(msg) {
handleSearchResult(msg.d.Item1, msg.d.Item2);
},
error:function(xhr, status, error) {
}
});
One last thing™ to change if you intend to run this on
IIS 7+ is to add the following to your web.config. If it's not present then the ajax request returns the whole page instead of what you would expect.
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<remove name="ScriptModule"/>
<add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</modules>
<handlers>
<remove name="WebServiceHandlerFactory-Integrated"/>
<remove name="ScriptHandlerFactory"/>
<remove name="ScriptHandlerFactoryAppServices"/>
<remove name="ScriptResource"/>
<add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</handlers>
</system.webServer>