web service page System.IndexOutOfRangeException - asp.net

public class GetAreaFromCity : System.Web.Services.WebService
{
[WebMethod]
public GetAreaByCityId ClassForGetCIty(int City_Id)
{
string CS =ConfigurationManager.ConnectionStrings["FOODINNConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("spGetCityById",con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter parameter = new SqlParameter("#ID", City_Id);
//To assiate this parameter object with cmd object
cmd.Parameters.Add(parameter);
GetAreaByCityId GETAreaByCityId =new GetAreaByCityId();
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
//as WeakReference read data wewant ToString retrive Column value & then polute this property City_Id values
while (reader.Read()){
GETAreaByCityId.City_Id = Convert.ToInt32(reader["City_Id"]);
GETAreaByCityId.Area_Id = Convert.ToInt32(reader["Area_Id"]);
}
return GETAreaByCityId;
//ToString return sql
}
}
}
that's my codes for service page
public class GetAreaByCityId
{
public int Ca_Id {get;set; }
public int City_Id { get; set; }
public int Area_Id { get; set; }
}
that's the class for getting the Area by city
Create Proc [dbo].[spGetCityById]
#ID int
as
Begin
Select Area_Id from
CITIES_AREA where City_Id = #ID
End
GO
and above the database procedure which is data can be retrieve
System.IndexOutOfRangeException: City_Id
at System.Data.ProviderBase.FieldNameLookup.GetOrdinal(String fieldName)
at System.Data.SqlClient.SqlDataReader.GetOrdinal(String name)
at System.Data.SqlClient.SqlDataReader.get_Item(String name)
at WebApplication1.GetAreaFromCity.ClassForGetCIty(Int32 City_Id) in c:\Users\Mudassir\Documents\Visual Studio 2013\Projects\WebApplication1\WebAppli
the above error i dont know whats the problem

Your stored procedure is returning only Area_Id. Your code in the "while loop" while (reader.Read()){ is attempting to read data from two columns:
City_Id
Area_Id
You could add the column City_Id to the result set for your stored procedure query, BUT you already have that value because you are passing it to the stored procedure as a parameter.
Easiest fix is probably to just change this line:
GETAreaByCityId.City_Id = Convert.ToInt32(reader["City_Id"]);
to this:
GETAreaByCityId.City_Id = City_Id;

Related

Sqllite SQLiteDataReader returns enpty reader while SQLiteDataAdapter returns the right result

I have trouble with Sqllite SQLiteDataReader. Using the same connection string and the same sql statement SQLiteDataReader returns empty reader while SQLiteDataAdapter returns suspected record.
I this case I try to get the record with the highest value in the Id field.
The database contains several records with unique values in the Id field, but the reader return is empty when using SQLiteDataReader. When I use the same connection string and sql statement with SQLiteDataAdapter suspected results appears. I supply a part of the static class I use for communication with the database. The method SenasteBokning using SQLiteDataReader isn’t working. The method SenasteBokning2 using SQLiteDataAdapter works perfect.
What’s wrong with the method SenasteBokning?
I use:
Windows 10
Visual Studio 2017
.net framework 4.5.2 (Was default at creation of Windows Forms application)
Nuget package System.Data.SQLite.Core 1.0.108
static class Databas
{
private static string appPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
private static string dbPath = #"\BokningarConvention.db";
private static string connectionString = "Data Source= " + appPath + dbPath;
private static SQLiteConnection con;
private static SQLiteCommand cmd;
private static SQLiteDataReader reader;
private static SQLiteDataAdapter adapter;
private static SQLiteCommandBuilder commandBuilder;
private static DataTable table;
private static string senaste = "SELECT Nummer, NrSammaDag, Datum FROM Bekraftelser WHERE Id = (SELECT MAX (Id) FROM Bekraftelser)";
// This don't work
public static Bokning SenasteBokning()
{
Bokning bokning = new Bokning();
using (SQLiteConnection con2 = new SQLiteConnection(connectionString))
{
con2.Open();
SQLiteCommand cmd2 = new SQLiteCommand(senaste, con2);
SQLiteDataReader reader2 = cmd2.ExecuteReader();
// Here the reader is empty
while (reader2.Read())
{
// Error at first read
// should handle results the same way as in SenasteBokning2
// removed during testing
}
}
return bokning;
}
//This works perfekt
public static Bokning SenasteBokning2()
{
Bokning bokning = new Bokning();
using (SQLiteConnection db = new SQLiteConnection(connectionString))
{
adapter = new SQLiteDataAdapter(senaste, connectionString);
commandBuilder = new SQLiteCommandBuilder(adapter);
table = new DataTable();
db.Open();
adapter.Fill(table);
foreach (DataRow row in table.Rows)
{
int nummer;
int samma;
DateTime datum;
nummer = (int)((long)row["Nummer"]);
datum = Verktyg.FromDateInteger((int)((long)row["Datum"]));
if (!row.IsNull("NrSammaDag"))
{
samma = (int)((long)row["NrSammaDag"]);
bokning = new Bokning(nummer, samma, datum);
}
else
{
bokning = new Bokning(nummer, datum);
}
}
}
return bokning;
}
}

.NET run stored procedure, get output

I am running this stored procedure with .NET like so:
public List<showWhatClass> showWhatMethod(string deviceWhat, int tagWhat, Decimal latit, Decimal longit, int Process, string CallNext, int CallNextVar)
{
showWhatCell = new List<showWhatClass>();
try
{
using (connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand("iosShowWhat", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#DeviceId", deviceWhat);
command.Parameters.AddWithValue("#TagId", tagWhat);
command.Parameters.AddWithValue("#Latitude", latit);
command.Parameters.AddWithValue("#Longitude", longit);
command.Parameters.AddWithValue("#Process", Process);
command.Parameters.AddWithValue("#CallNext", CallNext);
command.Parameters.AddWithValue("#CallNextVar", CallNextVar);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
showWhatClass item = new showWhatClass();
item.CallNext = reader.GetValue(0).ToString();
item.CallNextVar = (int)reader.GetValue(1);
showWhatCell.Add(item);
}
}
}
}
finally
{
connection.Close();
}
return showWhatCell;
}
The stored procedure returns the following message:
When I run this I get the following returned:
<ArrayOfshowWhatClass xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/WebServiceAPI.Models"/>
which is empty
my question is what am I doing wrong, how come nothing is returning when I run this with .NET but does return the message in SQL Server.
Here is my showWhatClass
public class showWhatClass
{
public string CallNext { get; set; }
public int CallNextVar { get; set; }
}
Try to change your parameters:
command.Parameters.AddWithValue("#DeviceId", deviceWhat);
to the following:
command.Parameters.Add("#DeviceId", SqlDbType.Int).Value = deviceWhat;

Manually converting result dataset to JSON

I have DataReader that holds the results from a stored procedure caal. The results consist of two fields ...
UserID
UserName
Normally I bind these results to an ASP.NET dropdownlist control ...
ddlUserList.DataSource = rdr // rdr is the DataReader
ddlUserList.DataTextField = "UserName"
ddlUserList.DataValueField = "UserID"
ddlUserList.DataBind()
However I am now trying to accomplish the same thing using jQuery AJAX. What I am stuck on is how to manually convert the dataset held in the DataReader to JSON. How are multiples values separated? Does this look correct?
{{"UserID":1, "UserName":"Bob"}, {"UserID":2, "UserName":"Sally"},{"UserID":3, "UserName":"Fred"}}
I realize there are libraries out there such as JSON.NET to handle the serialization but I am in the learning stage now and want to make sure I understand everything from the bottom up.
Was wondering if you have tried using System.Web.Script.Serialization.JavaScriptSerializer library?
You can look at Rick Stahl's blog on this:
http://www.west-wind.com/weblog/posts/737584.aspx
Or you could also do something like create a method that will pull out data from the datareader and place it in a list of objects. (See code below). These list of object will be serialized using the JavaScriptSerializer library.
Hope this helps!
public class User
{
public int UserId { get; set; }
public string UserName { get; set;}
}
public class DataLayer
{
public string GetUsers(string connString)
{
string result = null;
List<User> users = null;
// get data using SqlReader
using(var conn = new SqlConnection(connString))
{
using(var cmd = new SqlCommand{ Connection = conn, CommandText = "SELECT * FROM Users", CommandType = CommandType.Text })
{
conn.Open();
var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
if(!reader.HasRows)
return null;
//convert data reader to a list of user objects
users = (List<User>)ConvertToList<User>(ref reader);
conn.Close();
}
}
//convert list of objects in list to json objects
var jsonSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
result = jsonSerializer.Serialize(users);
return result;
}
public static IList<T> ConvertToList<T>(ref SqlDataReader reader)
{
IList<T> result = null;
if (reader.IsClosed)
return result;
result = new List<T>();
T item = default(T);
while (reader.Read())
{
//create item instance
item = (T)Activator.CreateInstance<T>();
//get class property members
var propertyItems = item.GetType().GetProperties();
//populate class property members with data from data reader
for (int ctr = 0; ctr < reader.FieldCount; ctr++)
{
if(reader.GetName(ctr) == propertyItems[ctr].Name)
propertyItems[ctr].SetValue(item, UtilsHelper.GetValue<string>(reader[ctr]), null);
}
//add item to list
result.Add(item);
}
reader.Close();
reader.Dispose();
return result;
}
}

System.OutOfMemoryException being thrown

I am getting a system.outofmemory exception in my code:
While r1.Read()
menu1id = r1("id")
db.AddInParameter(command2, "#menu1id", DbType.Int32, menu1id)
r2 = db.ExecuteReader(command2)
command2.Parameters.Clear()
menu1heading = r1("Heading")
If r1("url") IsNot Nothing And r1("moduleid") = 0 Then
url = r1("url").ToString
If InStr(url, "file:///") > 0 Then
Dim builder As New StringBuilder
builder.Append("<a href=")
builder.Append(r1("url"))
builder.Append(" target=")
builder.Append(r1("urltarget"))
builder.Append(">")
builder.Append(menu1heading)
builder.Append("</a>")
level1.Add(builder.ToString)
Else
Dim builder As New StringBuilder
builder.Append("<a href=http://")
builder.Append(r1("url"))
builder.Append(" target=")
builder.Append(r1("urltarget"))
builder.Append(">")
builder.Append(menu1heading)
builder.Append("</a>")
level1.Add(builder.ToString)
End If
Else
Dim builder As New StringBuilder
builder.Append("<a href=~/Default.aspx?id=")
builder.Append(r1("id"))
builder.Append(">")
builder.Append(menu1heading)
builder.Append("</a>")
level1.Add(builder.ToString)
End If
While r2.Read
menu2id = r2("id")
db.AddInParameter(command3, "#menu2id", DbType.Int32, menu2id)
r3 = db.ExecuteReader(command3)
command3.Parameters.Clear()
menu2heading = r2("Heading")
If r2("url") IsNot Nothing And r2("moduleid") = 0 Then
Dim builder As New StringBuilder
builder.Append("<a href=http://")
builder.Append(r2("url"))
builder.Append(" target=")
builder.Append(r2("urltarget"))
builder.Append(menu2heading)
builder.Append("</a>")
level2.Add(builder.ToString)
Else
Dim builder As New StringBuilder
builder.Append("<a href=~/Default.aspx?id=")
builder.Append(r2("id"))
builder.Append(">")
builder.Append(menu2heading)
builder.Append("</a>")
level2.Add(builder.ToString)
End If
While r3.Read
menu3heading = r3("Heading")
menu3id = r3("id")
If r3("url") IsNot Nothing And r3("moduleid") = 0 Then
Dim builder As New StringBuilder
builder.Append("<a href=http://")
builder.Append(r3("url"))
builder.Append(" target=")
builder.Append(r3("urltarget"))
builder.Append(">")
builder.Append(menu3heading)
builder.Append("</a>")
level3.Add(builder.ToString)
Else
Dim builder As New StringBuilder
builder.Append("<a href=~/Default.aspx?id=")
builder.Append(r3("id"))
builder.Append(">")
builder.Append(menu3heading)
builder.Append("</a>")
level3.Add(builder.ToString)
End If
End While
r3.Close()
End While
r2.Close()
End While
r1.Close()
End While
r0.Close()
Please can you tell me how I go about diagnosing and fixing this exception? thanks a lot.
You would be a lot better off changing your logic to a single sql query that returns all of your menu items in one go and then iterating this dataset to build your menu.
You could just try
SELECT id, DepartmentID, GroupingID, Heading, OrderID,
Publish, moduleid, url, urltarget
FROM Grouping
WHERE (DepartmentID = 0 AND Publish <> 0)
ORDER BY OrderID
This returns all of the data that the above queries return, including the GroupingID which determines the tree structure. You should be able to load up the results into a collection of objects and then query them using LINQ to build your menu.
Copy your data into the following class annd then use LINQ on a list of them:
public class DataClass
{
public string Id { get; set; }
public string DepartmentID { get; set; }
public string GroupingID { get; set; }
public string Heading { get; set; }
public string OrderID { get; set; }
public string Publish { get; set; }
public string Moduleid { get; set; }
public string Url { get; set; }
public string Urltarget { get; set; }
public List<DataClass> Children { get; set; }
public DataClass(string id, string departmentID, string groupingID, string heading, string orderID, string publish, string moduleid, string url, string urltarget)
{
Id = id;
DepartmentID = departmentID;
GroupingID = groupingID;
Heading = heading;
OrderID = orderID;
Publish = publish;
Moduleid = moduleid;
Url = url;
Urltarget = urltarget;
}
}
The method uses a lot of string concatenations, each of them creating lots of new temporary string objects which use up your heap space. This can be avoided by using a StringBuilder to create the concatenated string. The StringBuilder works not only more memory-efficient when concatenating lots of strings, it will also be much faster:
Dim builder As New StringBuilder()
builder.Append("<a href=")
builder.Append("r0("url"))
builder.Append("target=")
builder.Append(r0("urltarget"))
builder.Append(menu0heading)
builder.Append("</a>")
Dim str as String
str = builder.ToString()
Note: As pointed out by David Neale in the comments, in this context it would be better to use a TagBuilder (or an XmlWriter) to create the HTML/XML document tree.

Asp.Net: Returning a DataSet from a Class

I've decided to start another thread based on the responses I got in this thread:
Asp.Net: Returning a Reader from a Class
I was returning a reader, but members have suggested I'd be better off returning a Dataset instead and also try to seperate the data access tier from the presentation tier.
This is what I have so far:
//my class methods
public DataSet GetSuppliers()
{
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand("con_spSuppliersList", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#blogid", HttpContext.Current.Request.QueryString["p"]);
return FillDataSet(cmd, "SuppliersList");
}
//my FillDataSet method
private DataSet FillDataSet(SqlCommand cmd, string tableName)
{
SqlConnection conn = new SqlConnection(connectionString);
cmd.Connection = conn;
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
try
{
conn.Open();
adapter.Fill(ds, tableName);
}
finally
{
conn.Close();
}
return ds;
}
// on my ascx page I call the method like so:
protected void Page_Load(object sender, EventArgs e)
{
//instantiate our class
MyClass DB = new MyClass();
// grab the table of data
DataTable dt = DB.GetSuppliers().Tables["SuppliersList"];
//loop through the results
foreach (DataRow row in dt.Rows)
{
this.supplierslist.InnerHtml += Server.HtmlEncode(row["Address"].ToString()) + "<br/>";
this.supplierslist.InnerHtml += "<b>Tel: </b>" + Server.HtmlEncode(row["Telephone"].ToString()) + "<p/>";
}
}
}
Would anyone like to suggest improvements?
Is my loop 'data tier' or 'presentation tier', should the loop be inside the class and I just return a formatted string instaed of a dataset?
Thanks for all the great advice
I also would use a Typed DataSet or create your own class that holds the properties so you are not dealing with strings like row["Address"] you would say object.Address and get compile time checking.
DataSets have a lot of built in functionality that is nice but also caries with it a lot of overhead that might not be needed in something simple. Creating a simple class with properties and passing that out of your data access layer is probably the simplest way to implement what you want.
Something like this on the DAL (Data Access Layer) side:
//Also pass in the blogID dont have the DAL get the value from the UI layer..
//make the UI layer pass it in.
public IList<Supplier> GetSuppliers(string connectionString, int blogID)
{
IList<Supplier> suppliers = new List<Supplier>();
//wrap with the using statements
using (SqlConnection conn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand("con_spSuppliersList", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#blogid", blogID);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
suppliers.Add(new Supplier
{
Address = reader.GetString(0),
Telephone = reader.GetString(1)
});
}
}
}
return suppliers;
}
}
public class Supplier
{
//I would have Address an object....but you have as string
//public Address Address { get; set; }
public string Address { get; set; }
public string Telephone { get; set; }
}
//Example if you went with Address class...
public class Address
{
//Whatever you want in the address
public string StreetName { get; set; }
public string Country { get; set; }
public string Region { get; set; }
public string City { get; set; }
}
One thing you should get in the habit of doing is calling Dispose() on your SqlConnection. The best pattern to do this is to use the using statement, which will automatically dispose of it for you. It looks like this:
private DataSet FillDataSet(SqlCommand cmd, string tableName)
{
using(SqlConnection conn = new SqlConnection(connectionString))
{
cmd.Connection = conn;
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
try
{
conn.Open();
adapter.Fill(ds, tableName);
}
finally
{
conn.Close();
}
return ds;
}
}
What you have in the foreach loop in Page_Load, is presentation logic (layout), and IMO this should not be in the code-behind of your page, but in the markup.
I'd suggest that instead of using a foreach loop to construct the HTML output, you should use a databound control (such as a asp:Repeater, DataList or GridView). Then you can bind the repeater to your dataset or datatable and have all the markup where it belongs (in the ASCX file). See this page for an example.
As a general note: you can find lots of tutorials on www.asp.net, e.g. about data access: http://www.asp.net/%28S%28pdfrohu0ajmwt445fanvj2r3%29%29/learn/data-access/

Resources