Search with autocomplete and Ajax - c#

I want to make a search like them from google.
I've made it this far, that I can show all data from the database in my textbox with using a webservice. Thats my code:
Webform.aspx
<%--**Start Search**--%>
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services><asp:ServiceReference Path="~/WebService.asmx" /></Services>
</asp:ScriptManager>
<%--Search-Textbox--%>
<asp:TextBox runat="server" ID="txtSearchInput" Width="100%" />
<asp:Button ID="btnSearch" runat="server" Text="Suche" onclick="btnSearch_Click" />
<%--Autocomplete (Ajax)--%>
<asp:AutoCompleteExtender ID="AutoComplete1" runat="server" TargetControlID="txtSearchInput"
ServiceMethod="GetNames" ServicePath="~/WebService.asmx" MinimumPrefixLength="1"
EnableCaching="true" CompletionInterval="1000" CompletionSetCount="20">
</asp:AutoCompleteExtender>
<%--**End Search**--%>
Webservice.asmx
[WebMethod]
public string[] GetNames(string prefixText, int count)
{
List<string> items = new List<string>(count);
DataSet ds = new DataSet();
string cs = ConfigurationManager.ConnectionStrings["CSLinker"].ConnectionString;
using (SqlConnection connection = new SqlConnection(cs))
{
string sql = "SELECT Name FROM tabProjects WHERE Name LIKE '" + prefixText + "%' UNION all SELECT Name FROM tabLinks WHERE Name LIKE '" + prefixText + "%'";
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand(sql, connection);
adapter.Fill(ds);
}
foreach (DataRow dr in ds.Tables[0].Rows)
{
items.Add(dr["Name"].ToString());
}
return items.ToArray();
}
My problem now is, that i only have the name from the database. But for the search I need also the ID. Can somebody say me, how I can also query the ID without showing it in the textform?
I hope you can understand my problem. My english isnt' so good...
Thanks for helping!

Why not just pass the project name as the parameter rather than the probject ID? If you are using Response.Redirect I am assuming the user selects a project from the list of selections and the code behind handles somekind of event:
public void onProjectSelected()
{
string cs = ConfigurationManager.ConnectionStrings["CSLinker"].ConnectionString;
string projectName = txtSearchInput.Text;
int projectID = 0;
using (SqlConnection connection = new SqlConnection(cs))
{
using (SqlCommand command = new SqlCommand("SELECT ProjectID FROM TabProjects WHERE Name = #Name", connection))
{
command.Parameters.Add(new SqlParameter("#Name", SqlDbType.VarChar, 50)).Value = projectName;
connection.Open();
if (int.TryParse(command.ExecuteScalar().ToString(), out projectID))
{
Response.Redirect(string.Format("?ProjectID={0}", projectID));
}
connection.Close();
}
}
//Handle project not found events here
}
Also USE PARAMATERISED QUERIES otherwise SQL Injection could ruin your day!
If I were to type "It's a test" into your text box you would end up with an invalid SQL statement as the apostrophe I have used will result in the following SQL.
SELECT Name FROM tabProjects WHERE Name LIKE 'It's a test%'
Which clearly won't run and will not be a great user experience for anyone using your website. More seriously though, if I were to type into the text box on your page '; DROP TABLE TabProjects -- you may find, depednding on the permissions assigned to the CSLinker connection string, that you no longer have an tabProjects table as this is the SQL that is run:
SELECT Name FROM tabProjects WHERE Name LIKE ''; DROP TABLE tabProjects -- %'
You should use something like this for your web method:
[WebMethod]
public string[] GetNames(string prefixText, int count)
{
List<string> items = new List<string>();
string cs = ConfigurationManager.ConnectionStrings["CSLinker"].ConnectionString;
using (SqlConnection connection = new SqlConnection(cs))
{
using (SqlCommand command = new SqlCommand("SET ROWCOUNT #Count SELECT Name FROM TabProjects WHERE Name LIKE #Name + '%'", connection))
{
command.Parameters.Add(new SqlParameter("#Name", SqlDbType.VarChar, 50)).Value = prefixText;
command.Parameters.Add(new SqlParameter("#Count", SqlDbType.Int, 8)).Value = count;
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
items.Add(reader.GetString(0));
}
}
connection.Close();
}
}
return items.ToArray();
}

Related

Prevent Duplicate E-mail Address Submissions c#

I have the following c# code below that I am trying to include additional functionality to prevent duplicate e-mail addresses from being entered into the database using an asp.net form. Below is the code, currently it is inserting all entries, duplicate or not, into the database.
using System.Data.OleDb;
using System.Configuration;
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
OleDbConnection con = new OleDbConnection();
con.ConnectionString = ConfigurationManager.ConnectionStrings["northwind"].ToString();
con.Open();
string query = "SELECT COUNT(ID) FROM Table1 WHERE pEmail=' " + TextBox2.Text + "'";
OleDbCommand cmd = new OleDbCommand(query, con);
int count = (int)cmd.ExecuteScalar();
if (count > 0)
{
Label1.Text = "email is already in use";
}
else {
cmd.CommandText = "insert into[Table1](pName, pEmail)values(#nm,#em)";
cmd.Parameters.AddWithValue("#nm", TextBox1.Text);
cmd.Parameters.AddWithValue("#em", TextBox2.Text);
cmd.Connection = con;
int a = cmd.ExecuteNonQuery();
if (a>0)
{
Label1.Text = "Inserted Sucessfully!";
}
}
}
}
Asp.net form code
<form id="form1" runat="server">
<div style="height: 138px">
Enter Name:<asp:TextBox ID="TextBox1" runat="server" style="margin-left: 12px"></asp:TextBox>
<asp:RequiredFieldValidator
id="reqName"
ControlToValidate="TextBox1"
Style="color:Red"
ErrorMessage="Please enter your name!"
runat="server" />
<br />
Enter Email:
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
<asp:RegularExpressionValidator
id="ValidEmail"
ControlToValidate="TextBox2"
Style="color:Red"
ValidationExpression="^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"
ErrorMessage="Invalid Email Entry"
runat="server" />
<br />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Submit" />
<br />
<asp:Label ID="Label1" runat="server"></asp:Label>
</div>
</form>
As you are a doing a SELECT statement, you need to the ExecuteScalar method on OleDbCommand to get the results. As per the MSDN documentation, ExecuteScalar returns:
The first column of the first row in the result set, or a null
reference if the result set is empty.
In your case, the return will be the value of COUNT(ID) from your query.
ExecuteNonQuery is for operations which modify data and will return the number of rows affected by the query. As per the MSDN documentation:
You can use the ExecuteNonQuery to perform catalog operations, for
example, to query the structure of a database or to create database
objects such as tables, or to change the data in a database without
using a DataSet by executing UPDATE, INSERT, or DELETE statements.
Although the ExecuteNonQuery returns no rows, any output parameters or
return values mapped to parameters are populated with data. For
UPDATE, INSERT, and DELETE statements, the return value is the number
of rows affected by the command. For all other types of statements,
the return value is -1. If a rollback occurs, the return value is also
-1.
So change you code as follows:
string query = "SELECT COUNT(ID) FROM Table1 WHERE pEmail='" + TextBox2.Text + "'"; // note: vulnerable to SQLInjection.
OleDbCommand cmd = new OleDbCommand(query, conn);
int count = (int)cmd.ExecuteScalar();
if (count > 0)
{
// etc.
Update: I would also recommend using a Transaction on your operation to make sure that a duplicate email address is not added in between your checking for duplicates and you doing the actual insert.
Update 2:
Based on the updated code that switches to using ExecuteScalar, this line:
string query = "SELECT COUNT(ID) FROM Table1 WHERE pEmail=' " + TextBox2.Text + "'";
Should be:
string query = "SELECT COUNT(ID) FROM Table1 WHERE pEmail='" + TextBox2.Text + "'";
(Extra whitespace character between pEmail=' and " removed.
I think it may be the way you're instantiating the command object, but I'm not in a place to set up a test project to confirm. I think you actually want the ExecuteReader method, or at least that's what I've used in the past for SELECT on the fly like this.
This is what I'm basing it on: OleDbCommand.ExecuteReader
Can you try something like
protected void Button1_Click(object sender, EventArgs e) {
OleDbConnection con = new OleDbConnection();
con.ConnectionString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString2"].ToString();
con.Open();
string query = "SELECT COUNT(ID) FROM Table1 WHERE pEmail= " + TextBox2.Text;
OleDbCommand cmd = new OleDbCommand(query, con);
OleDbDataReader reader = command.ExecuteReader();
int count = 0;
while (reader.Read()) {
count = Convert.ToInt32(reader[0].ToString());
}
reader.Close();
if (count > 0) {
Label1.Text = "email is already in use";
} else {
//re-instantiate the command obj
cmd = new OleDbCommand(); //empty constructor should work, I think
cmd.CommandText = "insert into[Table1](pName)values(#nm)";
cmd.Parameters.AddWithValue("#nm", TextBox1.Text);
cmd.CommandText = "insert into[Table1](pEmail)values(#nm)";
cmd.Parameters.AddWithValue("#nm", TextBox2.Text);
cmd.Connection = con;
int a = cmd.ExecuteNonQuery();
if (a > 0) {
Label1.Text = "Inserted Sucessfully!";
}
}
}
You are trying to check if the email exist with these lines:
string query = "SELECT COUNT(ID) FROM Table1 WHERE pEmail= #TextBox2";
int count = cmd.ExecuteNonQuery(query);
but you don't use ExecuteNonQuery to get data from the database, you use ExecuteReader.
Hope this help you with yout issue.
ExecuteNonQuery does not take an argument. Try this:
string query = "SELECT COUNT(ID) FROM Table1 WHERE pEmail= #TextBox2";
OleDbCommand cmd = new OleDbCommand(query);
int count = cmd.ExecuteNonQuery();
Also, you are trying to check the return value of ExecuteNonQuery which actually returns the number of rows affected. But that is not the value returned by you SQL statement. If you would like to get the value returned by your SQL statement, you should use ExecuteReader or ExecuteScalar.
And I am not sure if your query is correct either. Shouldn't it be something like:
string query = "SELECT COUNT(ID) FROM Table1 WHERE pEmail= " + TextBox2.Text;

Asp.net C# Mysql Fetch data form data base using store procedure

I am trying fetch data from MySQL data base using store procedure in C#, To be more precise am following tri layer architecture am not sure where am wrong in the following below code i have tried in all the possibilities small help would be appreciated alot.
DataServices Layer
public DataSet FetchLoginDetails(string SchoolID)
{
object[] objparam = new object[1];
objparam[0] = new MySqlParameter
{
ParameterName = "#SchoolID",
DbType = System.Data.DbType.String,
Value =SchoolID
};
DataSet dsdataRes = ExecuteQuery("Storeprociduer", objparam);
return dsdataRes;
}
BusinessServices
private ITimeTableRepository ObjTimeTable
{
get { return UnityManager.Resolve<ITimeTableRepository>(); }
}
public DataSet FetchLoginDetails(string SchoolID)
{
return ObjTimeTable.FetchLoginDetails(SchoolID);
}
BusnessServices.Interfaces
public interface ITimeTableBO
{
DataSet FetchLoginDetails(string SchoolID);
}
UI .cs
public void LoadLoginDetails(DataSet ds)
{
if (ds.Tables.Count > 0)
{
if (ds.Tables[0].Rows.Count > 0)
{
ddlSubject.Items.Clear();
ListItem item1 = new ListItem();
item1.Text = "Choose a Subject";
item1.Value = "-1";
ddlSubject.Items.Add(item1);
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
ListItem item = new ListItem();
item.Text = ds.Tables[0].Rows[i]["UserName"].ToString();
item.Value = ds.Tables[0].Rows[i]["UserName"].ToString();
ddlSubject.Items.Add(item);
}
}
Aspx code
<asp:DropDownList ID="ddlSubject" runat="server" Width="150px"
Height="27px" ClientIDMode="Static"
AutoPostBack="true" >
<asp:ListItem Value="-1" Text="Choose a Subject"></asp:ListItem>
</asp:DropDownList>
Store Procidure
CREATE DEFINER=`root`#`localhost` PROCEDURE `Storeprociduer`(
SchoolID
VARCHAR(255)
)
BEGIN
select UserName from scoolage_login where SchoolID =
SchoolID ;
END
Without looking at the other details of your code, I am assuming you are unable to connect and retrieve data from your MySQL database. Take a look at the MySqlCommand Object. There are code examples as well:
https://dev.mysql.com/doc/connector-net/en/connector-net-tutorials-sql-command.html
Try something like this:
using (MySqlConnection con = new MySqlConnection(yourConnectionString))
{
using (MySqlCommand cmd = new MySqlCommand("Storeprociduer", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#SchoolID", SchoolID);
using (MySqlDataAdapter sda = new MySqlDataAdapter(cmd))
{
DataTable dt = new DataTable();
sda.Fill(dt);
// Do something with results
}
}
}
See this SO question as well:
calling mysql storedprocedure from c#?

How to select multiple items using Autocomplete extender in c#?

In my project I am using autocomplete extender.using this I am selecting only one item.But I want to select multiple items.what I should I do.please help me. below is my code:
aspx page:
<asp:TextBox ID="TextBox1" runat="server" CssClass="autosuggest ui-timepicker-input" Width="300px"></asp:TextBox>
<ajaxToolkit:AutoCompleteExtender ID="TextBox1_AutoCompleteExtender" runat="server" DelimiterCharacters=""
Enabled="True" ServiceMethod="GetListofCountries" MinimumPrefixLength="2" EnableCaching="true" CompletionSetCount="10" CompletionInterval="10" FirstRowSelected="false"
TargetControlID="TextBox1">
</ajaxToolkit:AutoCompleteExtender>
aspx.cs page:
[System.Web.Script.Services.ScriptMethod()]
[System.Web.Services.WebMethod]
public static List<string> GetListofCountries(string prefixText, int count)
{
//using (SqlConnection sqlconn = new SqlConnection(ConfigurationManager.ConnectionStrings["con2"].ConnectionString))
//{
// sqlconn.Open();
// SqlCommand cmd = new SqlCommand("select UserEmail from [User] where Useremail like '%" + prefixText + "%'", sqlconn);
// cmd.Parameters.AddWithValue("#prefixText", prefixText);
// SqlDataAdapter da = new SqlDataAdapter(cmd);
// DataTable dt = new DataTable();
// da.Fill(dt);
// List<string> Emailid = new List<string>();
// for (int i = 0; i < dt.Rows.Count; i++)
// {
// Emailid.Add(dt.Rows[i]["UserEmail"].ToString());
// }
// return Emailid;
//}
List<string> customers = new List<string>();
using (SqlConnection conn = new SqlConnection())
{
List<string> terms = prefixText.Split(',').ToList();
terms = terms.Select(s => s.Trim()).ToList();
//Extract the term to be searched from the list
string searchTerm = terms.LastOrDefault().ToString().Trim();
//Return if Search Term is empty
if (string.IsNullOrEmpty(searchTerm))
{
// return
}
//Populate the terms that need to be filtered out
List<string> excludeTerms = new List<string>();
if (terms.Count > 1)
{
terms.RemoveAt(terms.Count - 1);
excludeTerms = terms;
}
conn.ConnectionString = ConfigurationManager
.ConnectionStrings["con2"].ConnectionString;
using (SqlCommand cmd = new SqlCommand())
{
string query = "select UserEmail from [User] where Useremail like '%" + prefixText + "%'";
//Filter out the existing searched items
if (excludeTerms.Count > 0)
{
query += string.Format(" and UserEmail not in ({0})", string.Join(",", excludeTerms.Select(s => "'" + s + "'").ToArray()));
}
cmd.CommandText = query;
cmd.Parameters.AddWithValue("#prefixText", prefixText);
cmd.Connection = conn;
conn.Open();
using (SqlDataReader sdr = cmd.ExecuteReader())
{
while (sdr.Read())
{
//customers.Add(string.Format("{0}-{1}", sdr["Userid"], sdr["CustomerId"]));
customers.Add(string.Format("{0}", sdr["UserEmail"]));
}
}
conn.Close();
}
return customers;
}
but it gives only one value.I want to select multiple items.please help me.
finally I got an answer for the above question.in the AutoCompleteExtender add DelimiterCharacters="," and ShowOnlyCurrentWordInCompletionListItem="true" . add this two items for the AutoCompleteExtender. It will work for me.if any one want this type of question, I hope this answer is help you,thats why I posted here.thank you.

how to show a image for HTML type?

I create an autocomplete search box and I get product name and I want to get product photo but I did not do it. There is my code:
<asp:TextBox ID="txtContactsSearch" runat="server" Width="261"></asp:TextBox>
<cc1:AutoCompleteExtender ServiceMethod="Search11"
MinimumPrefixLength="1"
CompletionInterval="10"
EnableCaching="false"
CompletionSetCount="10"
TargetControlID="txtContactsSearch"
ID="AutoCompleteExtender1" runat="server" FirstRowSelected = "true">
</cc1:AutoCompleteExtender>
Web Service Code:
[System.Web.Script.Services.ScriptMethod()]
[System.Web.Services.WebMethod]
public static List<string> Search11(string prefixText, int count)
{
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = ConfigurationManager.AppSettings["U"].ToString();
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "select Top(10) * from S WITH (NOLOCK) where KeySentences like #SearchText + '%' ";
cmd.Parameters.AddWithValue("#SearchText", prefixText);
cmd.Connection = conn;
conn.Open();
List<string> Search = new List<string>();
using (SqlDataReader sdr = cmd.ExecuteReader())
{
while (sdr.Read())
{
//"<img src='st4.abc.com.tr/img/urun/p_" + sdr["RecID"].ToString()+"_01_01.jpg' />" + " "
Search.Add( sdr["KeySentences "].ToString().Substring(0, 30));
Search.Add("<img style = 'height:30px;width:30px' src = 'st4.abc.com.tr/img/urun/p_"+sdr["RecID"].ToString()+"_01_01.jpg'");
}
}
conn.Close();
return Search;
}
}
}
I can get product name but image is not. It seems:
I want to show only picture not HTML text.I think I use script or something like but I dont know What can I do for this? Thanks for your answers
the required functionality can be achieved by referring the following article
http://www.aspsnippets.com/Articles/Render-images-in-autocomplete-list-of-ASP.Net-AJAX-AutoCompleteExtender.aspx

AutoCompleteExtender AJAX Question

Ok I am using the code below in file called autocomplete.asmx (web service file) my main question is do I need to create a different web service for every field I want my auto complete to work for? IE maybe I would like to have the Company Name pulled out instead of country, but another time maybe name, now I know this just involves changing the select statement but How could I go about doing this so that depending on what field it is, it knows what select statement to use?
Thanks
public class AutoComplete : System.Web.Services.WebService
{
[WebMethod]
public string[] GetCountriesList(string prefixText)
{
DataSet dtst = new DataSet();
SqlConnection sqlCon = new SqlConnection(ConfigurationManager.AppSettings["ConnectionString"]);
string strSql = "SELECT CountryName FROM Tbl_ooo WHERE CountryName LIKE '" + prefixText + "%' ";
SqlCommand sqlComd = new SqlCommand(strSql, sqlCon);
sqlCon.Open();
SqlDataAdapter sqlAdpt = new SqlDataAdapter();
sqlAdpt.SelectCommand = sqlComd;
sqlAdpt.Fill(dtst);
string[] cntName = new string[dtst.Tables[0].Rows.Count];
int i = 0;
try
{
foreach (DataRow rdr in dtst.Tables[0].Rows)
{
cntName.SetValue(rdr["CountryName"].ToString(), i);
i++;
}
}
catch { }
finally
{
sqlCon.Close();
}
return cntName;
}
}
Yes, you can use same webservice webmethod to populate country and company.
For that you want to use ContextKey property in ajax AutoCompleteExtender control
Below is the sample Code
Markup :
Search
<asp:TextBox ID="txtSearch" CssClass="textBlackBold" runat="server" Width="350px"></asp:TextBox>
<asp:DropDownList ID="ddlType" runat="server" AutoPostBack="True" onselectedindexchanged="ddlType_SelectedIndexChanged">
<asp:ListItem Value="0">Country</asp:ListItem>
<asp:ListItem Value="1">Companies</asp:ListItem>
</asp:DropDownList>
<asp:AutoCompleteExtender ID="AutoCompleteExtender1" runat="server"
CompletionListCssClass="autocomplete_completionListElement"
CompletionListItemCssClass="autocomplete_listItem"
CompletionListHighlightedItemCssClass="autocomplete_highlightedListItem"
EnableCaching="true" ContextKey="Products" UseContextKey="true"
TargetControlID="txtSearch" MinimumPrefixLength="1"
ServiceMethod="GetInfo" ServicePath="~/WebService.asmx" >
</asp:AutoCompleteExtender>
Code Behind C# Code :
protected void ddlType_SelectedIndexChanged(object sender, EventArgs e)
{
string strContextKey = "";
if(ddlType.SelectedValue.ToString() == "0")
strContextKey = "Country";
else
strContextKey = "Companies";
AutoCompleteExtender1.ContextKey = ddlType.SelectedItem.Text;
}
WebService Code :
[WebMethod]
public string[] GetInfo(string prefixText, string contextKey)
{
DataSet dtst = new DataSet();
SqlConnection sqlCon = new SqlConnection(ConfigurationManager.AppSettings["ConnectionString"]);
string strSql = "";
if (contextKey == "Country")
{
strSql = "SELECT CountryName FROM Tbl_ooo WHERE CountryName LIKE '" + prefixText + "%' ";
}
else if(contextKey == "Companies")
{
strSql = //Other SQL Query
}
SqlCommand sqlComd = new SqlCommand(strSql, sqlCon);
sqlCon.Open();
SqlDataAdapter sqlAdpt = new SqlDataAdapter();
sqlAdpt.SelectCommand = sqlComd;
sqlAdpt.Fill(dtst);
string[] cntName = new string[dtst.Tables[0].Rows.Count];
int i = 0;
try
{
foreach (DataRow rdr in dtst.Tables[0].Rows)
{
cntName.SetValue(rdr[0].ToString(),i);
i++;
}
}
catch { }
finally
{
sqlCon.Close();
}
return cntName;
}

Categories

Resources