I have tried to solve this but i get a crazy error when i do this?
Here's my first method --> Which holds the SQLQUERY
[WebMethod]
public ArrayList getAllaEgenskaperforenmall(string mall_id)
{
ArrayList dbFetch;
// string parameter1 = "mall_namn";
string sqlReadQuery = "SELECT DISTINCT d.egenskaper_namn FROM(SELECT egen.egenskaper_id, egen.egenskaper_namn, kopp.mall_id, kopp.egenskap_id, emall.mall_id as egenskapensmallid, emall.mall_namn FROM t_egenskaper as egen, t_kopplingmallegenskaper as kopp, t_egenskapsmall as emall WHERE kopp.mall_id = 1 AND kopp.egenskap_id = egen.egenskaper_id) as d";
dbFetch = executeReadSqlQueryArray(sqlReadQuery);
return dbFetch;
}
Then I have tried to set up a general webmethod that could fetch data for me.
public ArrayList executeReadSqlQueryArray(string sqlToFetchData, string parameter1 = "", string parameter2 = "", string parameter3 = "")
{
SqlConnection conn = new SqlConnection(mConnectionstring);
SqlCommand command = new SqlCommand();
SqlDataReader sqlReader;
ArrayList dataReadFromDatabase = new ArrayList();
command.Connection = conn;
command.Connection.Open();
command.CommandText = sqlToFetchData;
sqlReader = command.ExecuteReader();
while(sqlReader.Read())
{
object[] values = new object[sqlReader.FieldCount];
sqlReader.GetValues(values);
dataReadFromDatabase.Add(values);
}
command.Connection.Close();
return dataReadFromDatabase;
}
The error i get is this? Funny thing is that yesterday I think I managed to get it to do as I wanted!
System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type System.Object[] may not be used in this context.
at System.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(String name, String ns, Object o, Boolean xsiType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write1_Object(String n, String ns, Object o, Boolean isNullable, Boolean needType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write8_ArrayOfAnyType(Object o)
at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayListSerializer2.Serialize(Object objectToSerialize, XmlSerializationWriter writer)
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces)
at System.Web.Services.Protocols.XmlReturnWriter.Write(HttpResponse response, Stream outputStream, Object returnValue)
at System.Web.Services.Protocols.HttpServerProtocol.WriteReturns(Object[] returnValues, Stream outputStream)
at System.Web.Services.Protocols.WebServiceHandler.WriteReturns(Object[] returnValues)
at System.Web.Services.Protocols.WebServiceHandler.Invoke()
The problem isn't with your code from getting from the DB as such, its that the WebMethod is trying to turn it into a string but it doesn't know what datatype it is. Currently its cast as Object (which can mean one of a million types).
If the datatype is of a simple singular data typeTry swapping away from ArrayList and making it a generic array, for example
List<String>
The problem is your array list contains a list of objects currently and the serialization processor doesn't know what to do with them. You could hard cast them from objects to a serializable format though to help or switch to a class (and make that implement serializable).
For example
[Serializable]
public class ProfileBasics
{
/// <summary>
/// Gets or sets the about me section
/// </summary>
[XmlElement("AboutMe")]
public string AboutMe {get; set;}
/// <summary>
/// Gets or sets the city name for the zip code
/// </summary>
[XmlElement("City")]
public string City {get; set;}
}
Then you could do List<ProfileBasics> and your web service should still work.
Related
I'm using Dapper to read data from SQL Server. I have a SQL statement that returns a long Json result but the issue is this result being split into 3 rows with 2033 characters max per row, then Dapper can't parse the returned result because it's invalid Json.
How to prevent this splitting or how to make Dapper deal with it?
This is my code:
SqlMapper.ResetTypeHandlers();
SqlMapper.AddTypeHandler(new JsonTypeHandler<List<Product>>());
const string sql = #"SELECT
*,
(SELECT * FROM Balance b
WHERE p.SKU = b.SKU
FOR JSON PATH) AS [Balances]
FROM Product p
WHERE SKU IN #SKUs
FOR JSON PATH";
var connection = new SqlConnection("myconnection");
return connection.QuerySingleAsync<List<Product>>(sql, new{SKUs = new[] {"foo", "bar"}} });
And the code of TypeHandler:
public class JsonTypeHandler<T> : SqlMapper.TypeHandler<T>
{
public override T Parse(object value)
{
return JsonConvert.DeserializeObject<T>(value.ToString());
}
public override void SetValue(IDbDataParameter parameter, T value)
{
parameter.Value = JsonConvert.SerializeObject(value);
}
}
And here is how I run this SQL in DataGrip
Edit:
Here is the error message:
Newtonsoft.Json.JsonSerializationException : Unexpected end when deserializing object. Path '[0].Balances[4].WarehouseId', line 1, position 2033.
My solution is writing another extension method that wraps Query<string> method likes below:
public static T QueryJson<T>(this IDbConnection cnn, string sql, object param = null,
IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null,
CommandType? commandType = null) where T: class
{
var result = cnn.Query<string>(sql, param, transaction, buffered, commandTimeout, commandType).ToList();
if (!result.Any())
return default(T);
// Concats
var sb = new StringBuilder();
foreach (var jsonPart in result)
sb.Append(jsonPart);
var settings = new JsonSerializerSettings
{
// https://github.com/danielwertheim/jsonnet-contractresolvers
// I use this Contract Resolver to set data to private setter properties
ContractResolver = new PrivateSetterContractResolver()
};
// Using Json.Net to de-serialize objects
return JsonConvert.DeserializeObject<T>(sb.ToString(), settings);
}
This solution works quite well and slower then multiple mapping method when query large data (1000 objects took 2.7 seconds in compare to 1.3 seconds).
I have a method which returns large number of rows from a database. (Please see following)
public static ACollection GetListFromDatabase(string customername)
{
DBFactory factory = DBFactory.Instance;
ACollection custcol = new ACollection();
//This is a collection class extended from System.Collections.CollectionBase
System.Data.IDataReader reader = null;
try
{
reader = factory.GPDb.ExecuteReader("spGetCustomerInfo", customernumber);
while (reader.Read())
{
ACollection cust = ACollection.ListFromReader(reader); // returns info and assign it to ACollection object.
custcol.InnerList.Add(cust);
}
}
catch (Exception e)
{
String error = e.Message;
}
finally
{
if (reader != null)
reader.Close();
}
return custcol;
}
When I run this method, I realized that count of custcol.InnerList is 32767 where it supposed to be around 34000. Then I saw that it gets into exception.
The error message says that "Value was either too large or too small for an Int16."
I believe, the capacity of this arraylist gets assigned as int16 in somehow. Can somebody help me to increase the capacity ?
Thanks
Edit:
here is the full stack trace
at System.Convert.ToInt16(Int64 value)
at System.Int64.System.IConvertible.ToInt16(IFormatProvider provider)
at System.Convert.ToInt16(Object value)
at Quest___Shared.CustomerCrossReference.ListFromReader(IDataReader reader) in C:\vsproject\CustomerCrossReference.cs:line 105
at Quest___Shared.ACollection.GetListFromDatabase(String customernumber) in C:\vsproject\ACollection.cs:line 88
Change the type of the variable that is giving you problems to Int32 or Int64, then you will be able to insert bigger or smaller numbers.
i have following code please help me how to get values from object
APIKarho objapi = new APIKarho();
object obje = objapi.GetBookingFromAPI();
string ss = obje.booking_id;
You should cast the object to the class it originally is (what class is the object returned by GetBookingFromAPI()) before you could access its field/property/method. Example:
public MyClass { // suppose this is the original class of the object returned by GetBookingFromAPI
public int booking_id;
}
APIKarho objapi = new APIKarho();
object obje = objapi.GetBookingFromAPI();
string ss = ((MyClass)obje).booking_id; //note the casting to MyClass here
You need to find out what type GetBookingFromAPI() returns, and change the type of obje. Just move your mouse over GetBookingFromAPI().
GetBookingFromAPIType obje = objapi.GetBookingFromAPI();
string ss = obje.booking_id;
If your api returns an object of an unknown type or a type that you cannot cast to you could use the dynamic keyword.
dynamic obj = api.GetBookingFromAPI();
string ss = obj.booking_id;
Note that this works only if booking_id is actually a string.
I've found a Serializeable Dictionary which works quite fine: http://www.jankowskimichal.pl/en/2010/10/serializabledictionary/
But I'm getting an exception whenever one of the objects in the dictionary is simply a list of strings. .NET is telling me it can't serialize it:
Serialize 'C:\bin\Debug\Settings\Default.xml' : System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] may not be used in this context.
at System.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(String name, String ns, Object o, Boolean xsiType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterObject.Write1_Object(String n, String ns, Object o, Boolean isNullable, Boolean needType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterObject.Write2_anyType(Object o)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o)
at ShadowBot.Classes.SerializableDictionary`2.WriteXml(XmlWriter writer) in c:\Classes\SerializableDictionary.cs:line 114
at System.Xml.Serialization.XmlSerializationWriter.WriteSerializable(IXmlSerializable serializable, String name, String ns, Boolean isNullable, Boolean wrapped)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterShadowSettings.Write2_ShadowSettings(String n, String ns, ShadowSettings o, Boolean isNullable, Boolean needType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterShadowSettings.Write3_ShadowSettings(Object o)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
at System.Xml.Serialization.XmlSerializer.Serialize(Stream stream, Object o, XmlSerializerNamespaces namespaces)
at System.Xml.Serialization.XmlSerializer.Serialize(Stream stream, Object o)
at Classes.XmlSerializer.Serialize(String Path, Object Object) in c:\Classes\XmlSerializer.cs:line 29
Is this even possible? I'd like this capability and just assumed you could nest objects like this. If this isn't possible, is there a way I can just write the dictionary to disk (doesn't have to be XML) and then re-load it without me having to write custom wrappers for this? I was originally a mac developer and this type of serialization was quite simple, so maybe I'm missing something on .NET.
Edit: When trying odyss' example i get:
System.Runtime.Serialization.SerializationException: Type 'System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' with data contract name 'ArrayOfstring:http://schemas.microsoft.com/2003/10/Serialization/Arrays' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
I've had similar issues with serializing generic lists. Try changing the list into an string array string[] before serializing and then back to a List<string> after deserializing. This is very easy to do and may solve your problem:
//List<string> to string[]
string[] sArray = sList.ToArray();
//string[] to List<string>
List<string> sList = sArray.ToList();
As an alternative, you might have better luck with System.Runtime.Serialization.DataContractSerializer. Example:
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();
dict.Add("test", new List<string>() { "t", "b" });
StringBuilder xmlString = new StringBuilder();
using (XmlWriter writer = XmlWriter.Create(xmlString))
{
DataContractSerializer serializer = new DataContractSerializer(typeof(Dictionary<string, List<string>>));
serializer.WriteObject(writer, dict);
}
This generates:
<?xml version="1.0" encoding="utf-16"?><ArrayOfKeyValueOfstringArrayOfstringty7Ep6D1 xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"><KeyValueOfstringArrayOfstringty7Ep6D1><Key>test</Key><Value><string>t</string><string>b</string></Value></KeyValueOfstringArrayOfstringty7Ep6D1></ArrayOfKeyValueOfstringArrayOfstringty7Ep6D1>
I'm dynamically calling web services in my program using the WSProxy class here, and I need to parse the returned object to XML, or at least access the members inside the returned web service result.
For example, if I receive an Array of StateCodes, I need to do:
public object RunService(string webServiceAsmxUrl, string serviceName, string methodName, string jsonArgs)
{
WSDLRuntime.WsProxy wsp = new WSDLRuntime.WsProxy();
// Convert JSON to C# object.
JavaScriptSerializer jser = new JavaScriptSerializer();
var dict = jser.Deserialize<Dictionary<string,object>>(jsonArgs);
// uses mi.Invoke() from the WSProxy class, returns an object.
var result = wsp.CallWebService(webServiceAsmxUrl, serviceName, methodName, dict);
I've tried various methods to get to array members, but I'm hitting a dead end.
// THIS WON'T WORK.
// "Cannot apply indexing with [] to an expression of type 'object'"
var firstResult = result[0];
// THIS WON'T WORK.
// "foreach statement cannot operate on variables of type 'object' because 'object' does not contain a public definition for 'GetEnumerator'"
foreach (var i in result)
{
}
return object
//At the end of the class, if I try to return the object for XML parsing, I'll get this:
//System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type StateCodes[] may not be used in this context.
//at System.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(String name, String ns, Object o, Boolean xsiType)
Since I won't know the type of the array which is returned beforehand, I can't do early binding. I'm using C# 3.5, which I've just started learning. I keep hearing "reflection" coming up, but the examples I've read don't seem to apply to this question.
If this question is confusing, it's because I'm very confused.
Try casting it to IEnumerable
var list = result as IEnumerable;
if(list != null)
{
foreach (var i in list)
{
// Do stuff
}
}
Try casting it to IEnumerable.
var goodResult = result as IEnumerable;
if (goodResult != null) // use it