Monday, March 26, 2012

ASP.NET AJAX autocomplete with c#

Hey all,

I've been struggling with this AJAX autocomplete textbox in a c# app for the last day or so. I've found an example on these forums about getting the autocomplete control working in aVB app.

I have taken all of the VB suggestions and converted them all to c# but my textbox still doesn't call the web service. The textbox will just accept text and will never load the autocomplete options.

Here is what I have so far:

- AutoCompleteExtender defintion

<ajaxToolkit:AutoCompleteExtenderID="AutoCompleteExtender1"runat="server"Enabled="true"EnableCaching="true"MinimumPrefixLength="1"TargetControlID="txtName"ServiceMethod="GetNames"ServicePath="~/WebServices/AutoComplete.asmx" />

- Web Service

using System;

using System.Web;

using System.Collections;

using System.Web.Services;

using System.Web.Services.Protocols;

using System.Collections.Generic;

using System.Web.Script.Services;

[ScriptService()]

[WebService(Namespace ="http://tempuri.org/")]

[WebServiceBinding(ConformsTo =WsiProfiles.BasicProfile1_1)]

publicclassAutoComplete : System.Web.Services.WebService

{

[WebMethod]

[ScriptMethod()]publicstring[] GetNames(string prefixText,int count){ ArrayList sampleList =newArrayList();
sampleList.Add("ABC");sampleList.Add("Hello");

sampleList.Add("Hi");

sampleList.Add("Hey");

ArrayList filteredList =newArrayList();

foreach (string sin sampleList)

{

if (s.ToLower().StartsWith(prefixText.ToLower()))

filteredList.Add(s);

}

return (string[])filteredList.ToArray(typeof(string));

}

}

- masterpage, ScriptManager definition

<asp:ScriptManagerID="ScriptManager1"EnablePartialRendering="true"runat="server">

<Services>

<asp:ServiceReferencePath="~/WebServices/AutoComplete.asmx"/>

</Services>

</asp:ScriptManager>

Any help would be much appreciated.

TJ

Hi,

Generally, your code should be ok. Here is my sample that works fine, it's made according to your code.

MasterPage:

<%@. Master Language="C#" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><script runat="server"></script><html xmlns="http://www.w3.org/1999/xhtml" ><head runat="server"> <title>Untitled Page</title></head><body> <form id="form1" runat="server"> <div> <asp:ScriptManager ID="ScriptManager1" EnablePartialRendering="true" runat="server"></asp:ScriptManager> <asp:contentplaceholder id="ContentPlaceHolder1" runat="server"> </asp:contentplaceholder> </div> </form></body></html>

Page:

<%@. Page Language="C#" MasterPageFile="~/MasterPage.master" Title="Untitled Page" %><asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> <asp:TextBox ID="txtName" runat="server"></asp:TextBox> <ajaxToolkit:AutoCompleteExtender ID="AutoCompleteExtender1" runat="server" Enabled="true" EnableCaching="true" MinimumPrefixLength="1" TargetControlID="txtName" ServiceMethod="GetNames" ServicePath="AutoComplete.asmx" /> </asp:Content>
Web Service:
 
<%@. WebService Language="C#" Class="AutoComplete" %>using System;using System.Web;using System.Collections;using System.Web.Services;using System.Web.Services.Protocols;using System.Collections.Generic;using System.Web.Script.Services;[ScriptService()][WebService(Namespace = "http://tempuri.org/")][WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]public class AutoComplete : System.Web.Services.WebService{ [WebMethod] [ScriptMethod()] public string[] GetNames(string prefixText, int count) { ArrayList sampleList = new ArrayList(); sampleList.Add("ABC"); sampleList.Add("Hello"); sampleList.Add("Hi"); sampleList.Add("Hey"); ArrayList filteredList = new ArrayList(); foreach (string s in sampleList) { if (s.ToLower().StartsWith(prefixText.ToLower())) filteredList.Add(s); } return (string[])filteredList.ToArray(typeof(string)); }}
  
If it still doesn't work, please make sure there isn't any javascript error on your page. And use a traffic sniffer(e.g.: fiddler) to view the traffic to see if the server returns correct result.

Thanks for the response.

My only issue with the solution above is that it doesn't currently fit 100% in what my site is currently designed to produce. In your example you have the AutoCompleteExtender within an ASPX page that refers to the master page. Our site currently has the AutoCompleteExtender control defined in a nested user control structure AND the AutoCompleteExtender is wanted to be used inside a ModalPopupExtender. The first user control is referred to on a page that references the master page and falls within the asp:content tags that you also used.

PAGE (references User Control 1)

--> User Control 1 (content and refrerence to User Control 2)

--> User Control 2 (content and reference to ModalPopupExtender that includes AutoCompleteExtender)

The end result is:

- the Page contains a reference to User Control 1

- User Control 1 has a reference to User Control 2

- User Control 2 contains a couple of textboxes, and a ModalPopupExtender. There also is a panel defined on this control that will be the contents of the popup extender. Within this panel is were the AutoCompleteExtender is located.

Do you know if this is possible? I know this sounds confusing but if you would like some code examples of what I'm trying to accomplish, please let me know.

In the meantime I'm going to take your example and try to get it working using just the Page example. If I can get to that point I will start adding some user controls and popups into the mix to see if I can find out which piece is causing the issues.

Thanks again,
TJ


Yes, it definitely possible.

I think you've got a idea how to implement it, if it doesn't work, please follow my suggestion in previous post(Use fiddler).


Hey there,

You were right to try to suggest using Fiddler as a debugging tool because when running through the page using the AutoComplete textbox Fiddler returns an error. The error is:

System.InvalidOperationException: Request format is invalid: application/json; charset=utf-8.
at System.Web.Services.Protocols.HttpServerProtocol.ReadParameters()
at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()

It is strange that even though the error is captured by Fiddler, the ASPX page shows no signs of errors.

The web service works as expected when going directly at the ASMX file and the Fiddler results are the following:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
<string>Hello</string>
<string>Hi</string>
<string>Hey</string>
</ArrayOfString>

I'm looking into the error that Fiddler is raising as we speak. If anyone has any information on the error that Fiddler is returning please let me know.

Thanks,

TJ


I've played with the "UseHttpGet=" and the "ResponseFormat=" settings on the ScriptMethod attribute with no luck. I also played with the ContentType of the Response object with no luck.

Anyone have any ideas on this error?

TIA,

TJ


It seems the problem is with the format of the request, you may peek into what's the value of it, still with Fiddler.


From Fiddler...

Request Raw View:

POST /Test.asmx/GetNames HTTP/1.1
Accept: */*
Accept-Language: en-us
Referer:http://localhost/Autocomplete/test.aspx
Content-Type: application/json; charset=utf-8
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)
Host: fin51311
Content-Length: 29
Proxy-Connection: Keep-Alive
Pragma: no-cache
Cookie: ASP.NET_SessionId=qeupjw45zwodqbvjmy4frf55

{"prefixText":"h","count":10}

Response Raw View:

HTTP/1.1 500 Internal Server Error
Server: Microsoft-IIS/5.1
Date: Thu, 16 Aug 2007 22:09:01 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Type: text/plain; charset=utf-8
Content-Length: 244

System.InvalidOperationException: Request format is invalid: application/json; charset=utf-8.
at System.Web.Services.Protocols.HttpServerProtocol.ReadParameters()
at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()

Under the Caching tab of the Response Header section it reads:

HTTP/1.1 Cache-Control Header is present: private
private: This response MUST NOT be cached by a shared cache.

Is this something I should look at further?


Tiimmy,

I had the same and worked for a few hours looking at the problem you have. I found the solution to the problem.

I made a new AJAX enable site and copy the same sample sent to you before. It worked. They only thing that could be is that the handler section in the webconfig file is missing something. Make sure that it matches the section create by the project template.

I hope this helps.

Pablo.


Hey there,

Thanks for your reply. Taking your advice I created an AJAX-enabled web site and then tried to implement an AutoCompleteExtender. I am actually getting the same error as I was before. Nothing happens on the screen when you key in a character in the textbox.

After pressing a key (which should trigger a call to the web service) Fiddler logs a line in red, (error 500), that has private under the Caching column. In Fiddler, the Request Header section is displaying the Cache-Control as Pragma: no-cache, and the Response Headers section is displaying Cache-Control as private. Could this be an issue? Under the Caching tab of the Response header, the message reads:

Cache-Control Header is present: private
- private: This response MUST NOT be cached by a shared cache.

It may help if you can post examples of the files (web.config, *.asmx, *.aspx) that you are using to get it running?

No comments:

Post a Comment