Why is my DataContractJsonSerializer failing on the call to ReadObject()? - asp.net

I am trying to deserialize some json received from a Web API method being called from a .NET 3.5 Winforms app based on this code: http://msdn.microsoft.com/en-us/library/bb412179(v=vs.90).aspx
The json is being returned, but upon deserialization, it is failing to grab root and therefore growling:
Here is the client code in question:
try
{
var client = new RestClient();
client.BaseUrl = "http://localhost:48614/"; // <-- this works
var request = new RestRequest();
request.Resource = "api/departments/"; // can replace this with other data, such as redemptions, etc.
RestResponse response = client.Execute(request) as RestResponse;
if ((response.StatusCode == HttpStatusCode.OK) && (response.ResponseStatus == ResponseStatus.Completed)) // Both are probably not necessary
{
MessageBox.Show(string.Format("Content is {0}", response.Content));
// from http://msdn.microsoft.com/en-us/library/bb412179(v=vs.90).aspx
MemoryStream deptStream = new MemoryStream();
DataContractJsonSerializer cereal = new DataContractJsonSerializer(typeof(Department));
deptStream.Position = 0;
Department dept = (Department)cereal.ReadObject(deptStream);
MessageBox.Show(string.Format("accountId is {0}, deptName is {1}", dept.AccountId, dept.DeptName));
}
else
{
MessageBox.Show(string.Format("Status code is {0} ({1}); response status is {2}",
response.StatusCode, response.StatusDescription, response.ResponseStatus));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
The response.Content line is doing just fine, displaying the json data in the dialog.
The Department data is defined this way in the .NET 4 ASP.NET / Web API app:
namespace DuckbilledPlatypusServerWebAPI.Models
{
public class Department
{
[Key]
public int Id { get; set; }
[Required]
public string AccountId { get; set; }
[Required]
public string DeptName { get; set; }
}
}
...and this way in the .NET 3.5 Winforms app that receives the data:
[DataContract]
public class Department
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string AccountId { get; set; }
[DataMember]
public string DeptName { get; set; }
}
So what does it yet need to work? How am I to supply it with a 'root' element, as it seems to be demanding?
UPDATE
Badri's answer solves the err msg, but I'm still not getting any data to work with the DataContractJsonSerializer, or I'm accessing it wrong. Here is my code now:
MessageBox.Show(string.Format("Content is {0}", response.Content));
byte[] bytes = Encoding.UTF8.GetBytes(response.Content);
MemoryStream deptStream = new MemoryStream(bytes);
deptStream.Position = 0;
DataContractJsonSerializer jasonCereal = new DataContractJsonSerializer(typeof(Department));
Department dept = (Department)jasonCereal.ReadObject(deptStream);
MessageBox.Show(string.Format("accountId is {0}, deptName is {1}", dept.AccountId, dept.DeptName));
...and, although the first message box shows the jsonarray:
...the second one says accountId and deptName are empty strings. In what way am I maltrreating DataContractJsonSerializer?

deptStream is newed up but where do you load the JSON response returned into the MemoryStream, before the deserialization. You should do something like this.
byte[] bytes = Encoding.UTF8.GetBytes(response.Content);
MemoryStream deptStream = new MemoryStream(bytes);
deptStream.Position = 0;
// Deserialize now
UPDATE
Your JSON corresponds to a list of Department objects not a single Department object. Try something like this.
var jasonCereal = new DataContractJsonSerializer(typeof(List<Department>));
var depts = (List<Department>)jasonCereal.ReadObject(deptStream);
foreach(var dept in depts)
MessageBox.Show(
String.Format("accountId is {0}, deptName is {1}",
dept.AccountId, dept.DeptName));

Related

Xamarin forms: How to parse local JSON data file stored in the project?

I have a local JSON file. I need to parse data from that file and need a list with date,color and message details.
Data format in JSON file:
{"01-01-2017":{"color":"white","message":"The Octave Day of Christmas Solemnity of the Blessed Virgin Mary, the Mother of God Lectionary: 18"},"02-01-2017":{"color":"white","message":"Memorial of Saints Basil the Great and Gregory Nazianzen, Bishops and Doctors of the Church Lectionary: 205",.......}}
Model Class
public class JsonContent
{
public string date { get; set; }
public string color { get; set; }
public string message { get; set; }
}
I tried the below code:
string jsonString;
string jsonFileName = "Files.prayers.json";
var assembly = typeof(HomePage1).GetTypeInfo().Assembly;
Stream stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{jsonFileName}");
using (var reader = new System.IO.StreamReader(stream))
{
jsonString = reader.ReadToEnd();
}
List <JsonContent> newList = new List<JsonContent>();
//I need to add all the items into the above list
How can I get the list with date,color and message details? After this I need to show the dates with color on a XamForms.Enhanced.Calendar. I know how to show special dates in calendar, but stuck on this data parsing.
docs
I'd try something like this
Dictionary<string, JsonContent> jsonData = JsonConvert.DeserializeObject<Dictionary<string, JsonContent>>(jsonString);
foreach (var item in jsonData)
{
Debug.WriteLine("Date:>>" + item.Key);
Debug.WriteLine("color:>>" + item.Value.color);
Debug.WriteLine("message:>>" + item.Value.message);
}

How to use tempdata to return error message

I am trying to use temp data to return messages but it gives an error :
InvalidOperationException: The 'Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.TempDataSerializer' cannot serialize an object of type
I am already using
services.AddMvc().AddSessionStateTempDataProvider();
app.UseSession()
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
});
Here is my shared
FlashMessages.cshtml :
#using EnduroMotors.ViewModels
#{
var errorMessages = TempData["_error_messages"] as List<FlashMessageModel>
?? new List<FlashMessageModel>();
var warningMessages = TempData["_warning_messages"] as
List<FlashMessageModel> ?? new List<FlashMessageModel>();
var successMessages = TempData["_success_messages"] as
List<FlashMessageModel> ?? new List<FlashMessageModel>();
var infoMessages = TempData["_info_messages"] as List<FlashMessageModel> ??
new List<FlashMessageModel>();
}
Here is my viewmodel :
FlashMessageModel
public class FlashMessageModel
{
public string Title { get; set; }
public string Message { get; set; }
}
And here is use in controller :
Controller
protected void ShowSuccessMessage(string message, string title =
"Success!")
{
var messages =
(List<FlashMessageModel>)TempData["_success_messages"] ?? new
List<FlashMessageModel>();
messages.Add(new FlashMessageModel
{
Title = title,
Message = message
});
TempData["_success_messages"] = messages;
}
using this with return
ShowSuccessMessage("You have completed.");
it should show success message in index with #{Html.RenderPartial("FlashMessages");} but instead it gives
InvalidOperationException: The 'Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.TempDataSerializer' cannot serialize an object of type 'EnduroMotors.ViewModels.FlashMessageModel'.
Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.TempDataSerializer.EnsureObjectCanBeSerialized(object item)
TempData serialises objects to strings for storage. It supports string, int and boolean types natively. If you want to store more complex types, you have to serialise (and deserialise) them yourself. JSON is the recommended format. The following extension methods use the JSON.NET JsonConvert static methods to do this:
public static class TempDataExtensions
{
public static void Set<T>(this ITempDataDictionary tempData, string key, T value) where T : class
{
tempData[key] = JsonConvert.SerializeObject(value);
}
public static T Get<T>(this ITempDataDictionary tempData, string key) where T : class
{
tempData.TryGetValue(key, out object o);
return o ?? JsonConvert.DeserializeObject<T>((string)o);
}
}
You can read more about this here: https://www.learnrazorpages.com/razor-pages/tempdata#limitations

Asp.net web api json interraction

Hi there i am developing an azure web api and my put method is below
public string[] Put(SampleRequest request)
{
//Getting Request initials
string[] filmNames = request.Inputs.FilmIds;
int userAge = request.Inputs.UserAge;
char userGender = request.Inputs.UserGender;
int userId = request.Inputs.UserId;
.
.
. Doesnt matter rest of them...
When i tried to communicate with json the request(which is a SampleRequest object) in my put method is getting null so that i cannot parse it to get the data in it, what would be the problem ? My data model,help page json format and my json request(which is in another app) is below
public class SampleRequest
{
public InputsRequest Inputs { get; set; }
}
public class InputsRequest
{
public int UserId { get; set; }
public int UserAge { get; set; }
public char UserGender { get; set; }
public string[] FilmIds { get; set; }
}
application/json, text/json [ API HELP PAGE ]
Sample:
{
"Inputs": {
"UserId": 1,
"UserAge": 2,
"UserGender": "A",
"FilmIds": [
"sample string 1",
"sample string 2"
]
}
}
my request from other app:
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://localhost:5291/api/values");
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "PUT";
var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream());
string json = "{"+"\"Inputs\""+":"+"{"+ "\"UserId\"" + ":" + "12345" + ","
+ "\"UserAge\"" + ":" + "23" + ","
+ "\"UserGender\"" + ":" + "\"M\"" + ","
+ "\"FilmIds\"" + ":" +
"[\"Kung Fu Panda\",\"I Am Legend\",\"I Am Number Four\"]"+
"}"+"}";
streamWriter.Write(json);
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var responseText = streamReader.ReadToEnd();
}
Quick Note: Yes i know the name is FilmIds but i am getting Film names :D dont worry about it
This problem is coming from async methods , the reason behind getting null from put function is that the test application is not sending all of its messages so that the put method gets nothing , solution is using Putasync method below
using (var htc = new HttpClient())
{
var res = await htc.PutAsync("http://localhost:5291/api/values", new StringContent(serializedObject, Encoding.UTF8, "application/json"));
}

Load ProfileBase without HTTP Context

I'm in the process of converting user profile data that was serialized in the classic ASP.Net Membership Provider for use in SimpleMembership. I cannot figure out how to get the ProfileBase object for every user in the system.
If a specific user is logged in, I can do something like:
MyModel myModel =
(MyModel)HttpContext.Current.Profile.GetPropertyValue("MyKey");
where MyKey refers to a profile key established in web.config like this:
<add name="MyModel" type="MyNS.MyModel" serializeAs="Binary" />
However, without the benefit of an HTTP context (I'm trying to do this for all users in the system, not a logged-in user) I can't figure out how to load the profile and ultimately an instance of MyModel for each user in the system.
I have tried:
ProfileInfoCollection profiles =
ProfileManager.GetAllProfiles(ProfileAuthenticationOption.All);
foreach (var profile in profiles)
{
var pi = (ProfileBase)profile;
// OOPS! Unfortunately GetAllProfiles returns
// ProfileInfo and not ProfileCommon or ProfileBase
}
and
MembershipUserCollection existingUsers = Membership.GetAllUsers();
foreach (MembershipUser mu in existingUsers)
{
mu. // OOPS! No link to the profile from the user...
}
How can I retrieve the ProfileCommon or ProfileBase instance for each profile in the system, and thus ultimately the MyModel associated with each user?
Since I could not find an answer to this question, I opted to just read the profile data directly from SQL.
It turns out that the format is straightforward. In aspnet_Profile:
PropertyNames uses a format NameOfProperty:TypeFlag:Offset:Length (repeat for all properties).
FlagType is "S" for string or "B" for binary
Offset is the offset in the appropriate data field
Length is the length of data in the appropriate data field
PropertyValuesString holds all string properties concatenated without a delimiter.
PropertyValuesBinary holds all binary properties concatenated without a delimiter.
BinaryFormatter is used to serialize binary (non-string) properties
Here's a little code I wrote to parse the data:
private class Migrate_PropNames
{
public string Name { get; set; }
public bool IsString { get; set; }
public int Offset { get; set; }
public int Length { get; set; }
}
....
Dictionary<string, Migrate_PropNames> propInfo = ParsePropInfo(propertyNames);
// Example string property
string firstName = Migrate_GetString(propInfo["FirstName"], propertyValuesString);
// Example binary property
MyType myType =
Migrate_GetBinary<MyType>(propInfo["MyTypeKey"], propertyValuesBinary));
private T Migrate_GetBinary<T>(Migrate_PropNames propNames, byte[] propertyValuesBinary)
{
byte[] data = new byte[propNames.Length];
Array.Copy(propertyValuesBinary, propNames.Offset, data, 0, propNames.Length);
var fmt = new BinaryFormatter();
using (var ms = new MemoryStream(data))
{
T original = (T)fmt.Deserialize(ms);
return original;
}
}
private string Migrate_GetString(Migrate_PropNames propNames, string propertyNames)
{
return propertyNames.Substring(propNames.Offset, propNames.Length);
}
private Dictionary<string, Migrate_PropNames> ParsePropInfo(string propertyNames)
{
Dictionary<string, Migrate_PropNames> result = new Dictionary<string,Migrate_PropNames>();
string[] parts = propertyNames.Split(new string[] { ":"}, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < parts.Length; i += 4)
{
Migrate_PropNames pn = new Migrate_PropNames();
pn.Name = parts[i];
pn.IsString = (parts[i + 1] == "S");
pn.Offset = int.Parse(parts[i + 2]);
pn.Length = int.Parse(parts[i + 3]);
result.Add(pn.Name, pn);
}
return result;
}
I hope this helps someone. I'll gladly accept a different answer that correctly shows how to use the API.
From the ProfileInfo or MemberShipUser object, you should can get a ProfileBase one using ProfileBase.Create(string username).

why is my query not returning 6 items?

Afternoon,
Can any one see why my query is not returning a random 6 items please?
public class GetQuestions
{
public int qId { get; set; }
public string question { get; set; }
public string answer1 { get; set; }
public string answer2 { get; set; }
public string answer3 { get; set; }
}
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public List<GetQuestions> Questions()
{
using (QuizDataContext dc = new QuizDataContext())
{
var query = from q in dc.tblquizs
orderby Guid.NewGuid()
select new GetQuestions
{
qId = q.id,
question = q.q,
answer1 = q.a1,
answer2 = q.a2,
answer3 = q.a3,
};
return query.Take(6).ToList();
}
Updated Add the GetQuestions Class
You can't get random order by using
orderby Guid.NewGuid()
You can test this by doing the following query and seeing the result:
from q in dc.tblquizs
select Guid.NewGuid()
Entity Framework 4.3.1 will translate the Guid.NewGuid() call to newid() - this would definitely be the preferred methodology if your DAL supports it. It may be, however, that whatever DAL you're using doesn't translate the call properly (in which case it may get translated to a GUID before it's sent to the database server, resulting in a static value for ordering). You should use a database profiler to see what your DAL is doing.
If the Guid.NewGuid call is not translating to newid() properly, you have two other options:
Use a sproc
Use something like the LINQ below (as a last resort)
var context = new ScratchContext();
var products = new List<Product>();
for (int i = 0; i < num; i++)
{
Product product = null;
while (product == null)
{
int randomId = r.Next(context.Products.Count());
product = context.Products.FirstOrDefault(p => p.ID == randomId);
}
products.Add(product);
}
return products.AsQueryable();
I used the following code to resolve this issue.
var qry = from q in dc.tblwhiskysprintquizs.AsEnumerable()
orderby Guid.NewGuid()
select new GetQuestions
{
qId = q.id,
question = q.q,
answer1 = q.a1,
answer2 = q.a2,
answer3 = q.a3,
};
return qry.Take(6).ToList();
It was as simple as adding .AsEnumerable to the look up.
orderby Guid.NewGuid()
generates random numbers that may not exist in your db

Resources