- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
JSON deserialize to LLBL Entity
Joined: 06-Feb-2013
I am just starting a project with SQLServer 2014, LLBL v4.1 final, MS WebApi and MS MVC (.NET 4.5.1) all latest updates.
I am running into an issue with deserializing JSON to LLBL Entity
I have a WebApi Project which returns an entity/ Entity Collection. I followed these links to make this part work.
and
http://llblgen.com/tinyforum/Messages.aspx?ThreadID=22583
Following is the actual code from Web Api
public HttpResponseMessage Get()
{
using (var d = new DataAccessAdapter())
{
var metaData = new EntityCollection<PersonEntity>();
d.FetchEntityCollection(metaData, null);
return Request.CreateResponse(HttpStatusCode.OK,JsonConvert.SerializeObject(metaData,new JsonSerializerSettings()
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new DefaultContractResolver()
{
IgnoreSerializableInterface = true,
IgnoreSerializableAttribute = true
}
}));
}
}
// GET api/values/5
public HttpResponseMessage Get(int id)
{
using (var d = new DataAccessAdapter())
{
var metaData = new EntityCollection<PersonEntity>();
d.FetchEntityCollection(metaData, null);
return Request.CreateResponse(HttpStatusCode.OK, JsonConvert.SerializeObject(metaData[0], new JsonSerializerSettings()
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new DefaultContractResolver()
{
IgnoreSerializableInterface = true,
IgnoreSerializableAttribute = true
}
}));
}
}
Now i have MVC project that references the same DAL project and which is trying to retrieve the data from the WebApi project which then i want to deserialize into LLBL entity and pass it to a view. i am getting the data from the WebApi
"{\"$id\":\"1\",\"Branch\":\"sfo\",\"Name\":\"John\",\"Note\":\"\",Test Note\"Personid\":1}"
Here is the code from MVC project
public ActionResult About()
{
var x= new WebClient().DownloadString("http://localhost:30374/api/Values/5");
PersonEntity pe= JsonConvert.DeserializeObject<PersonEntity>(x);
return View(pe);
}
Here is the error i am getting whtn i try to convert this into PersonEntity.
An exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll but was not handled in user code
Additional information: Error converting value "{"$id":"1","Branch":"sfo","Name":"John","Note":Test Note"","Personid":1}" to type 'WebAPI.DAL.EntityClasses.PersonEntity'. Path '', line 1, position 88.
I also tried the Json Serializer for MVC mentioned in
http://llblgen.com/tinyforum/Messages.aspx?ThreadID=15124
in my MVC project
public ActionResult About()
{
var x= new WebClient().DownloadString("http://localhost:30374/api/Values/5");
PersonEntity pe= LLBLGenWebExtension.FromJson<PersonEntity>(x);
return View(pe);
}
but i get following exception
An exception of type 'System.InvalidOperationException' occurred in System.Web.Extensions.dll but was not handled in user code
Additional information: Cannot convert object of type 'System.String' to type 'WebAPI.DAL.EntityClasses.PersonEntity'
Whats the best way to convert JSON to LLBL entity? Please Help. Also are there any sample project that uses WebApi as service and MVC for the UI?
Thanks
Additional information: Error converting value "{"$id":"1","Branch":"sfo","Name":"John","Note":Test Note"","Personid":1}" to type 'WebAPI.DAL.EntityClasses.PersonEntity'. Path '', line 1, position 88.
Position 88, is that the : Test Note"" ?
Note the position of the quotations, it looks wrong, right?
Joined: 06-Feb-2013
Walaa,
i am getting similar error at different position depending on the data.
I have here attached my project including the sql script for the db, i have removed the package folder to make it smaller.
WebApi folder has the sln.
WebApi>> ValuesController has the GET method to get the values in JSON.
WebUI >> HomeController >>About has the WebApi call.
Let me know what is it that i am missing. Thanks
Whether at different position or not, the JSON returned from the WebAPI seems faulty.
"{\"$id\":\"1\",\"Branch\":\"sfo\",\"Name\":\"John\",\"Note\":\"\",Test Note\"Personid\":1}"
Please debug and check the JSON, and see why it's being returned in a wrong format.
I'm trying your demo app now but I have a hard time testing it as everything is in 1 solution, so I can't run both the webapi and the webui at the same time easily. Will now cut it up in two solutions so I can test something.
Ok, got the api working now, it gives: {"$id":"1","Branch":"sfo","Name":"John","Note":"Test Note","Personid":1}
Seems fine by me. Will now look into why it gives an error on the roundtrip
(edit) The exception I get doesn't make ANY sense at all.
[ArgumentException: Could not cast or convert from System.String to WebAPI.DAL.EntityClasses.PersonEntity.]
Newtonsoft.Json.Utilities.ConvertUtils.EnsureTypeAssignable(Object value, Type initialType, Type targetType) +225
Newtonsoft.Json.Utilities.ConvertUtils.ConvertOrCast(Object initialValue, CultureInfo culture, Type targetType) +123
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType) +348
Looking at the code, it apparently wants to cast some string value to a complete entity... doesn't make any sense at all. If I pass in the settings you used to serialize the data, no change...
But I have the feeling you do something weird. The thing with the json setup is that you configure webapi for it, and you let webapi do the serializing/deserializing, not yourself.
For example, if I change the Get method in ValuesController in the webapi to:
public PersonEntity Get(int id)
{
using(var d = new DataAccessAdapter())
{
return d.FetchNewEntity<PersonEntity>(new RelationPredicateBucket(PersonFields.Personid == id));
}
}
I get the same json WHich is precisely the point: webapi is there to do the work for you, not you.
More importantly, I get:
{"$id":"1","Branch":"sfo","Name":"John","Note":"Test Note","Personid":1}
WITHOUT the xml tags surrounding it. Because your code returns:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">{"$id":"1","Branch":"sfo","Name":"John","Note":"Test Note","Personid":1}</string>
which is why deserialization fails, because it's wrapped inside an XML element. When I click on the about link when I fixed the webapi code, I get a normal about page.
You can thus also fix that webui project by not doing the deserialization yourself, as you don't have to.
Also, it still contains EF cruft, you can remove that too
Joined: 06-Feb-2013
Fran, Thanks for the update. sorry i had been out for a while, just got a chance to read your post.
Ok. i have fixed the WebApi to get the desired JSON result following your post
I have made new solution WebUI to get this JSON result back to LLBL entity but i am simply not able to get it.
You can thus also fix that webui project by not doing the deserialization yourself, as you don't have to.
Can you post the syntax or steps of converting JSON string to LLBL Entity?
I have attached the new .zip. Please look at the HomeController of WebUI.
i have been using LLBL for last 8 years but in desktop environment and we are just in a process of converting it into Web/mobile. So i am fairly new and learning in web space. New developers wants to use EF 6 but i am a big fan of LLBL. i need to prove to them that this is the best.
Also could you update the "Convince your manager" ppt to latest version of LLBLGen vs EF 6 and why its much better?
Thanks
Filename | File size | Added on | Approval |
---|---|---|---|
DemoLLBL.zip | 309,360 | 29-May-2014 07:44.30 | Approved |
I think your issue is related to this thread: https://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=22583
Correct?
Joined: 06-Feb-2013
I tried that too. See the original post i have mentioned this thread and my sample app includes his code.
Even if you read the Comment section from Fran's blog. @Ryan seems to have problem the same problem, so it seems like people are running into this issue for a long time.
http://weblogs.asp.net/fbouma/how-to-make-asp-net-webapi-serialize-your-llblgen-pro-entities-to-json
I think it would be best if LLBLGen provided a simple CRUD .NET MVC /.NET MVC WebAPI application with JSON. I think that's all i am looking for.
Thanks
Ok I got it.
At the client side you need to do the following:
var settings = new Newtonsoft.Json.JsonSerializerSettings();
settings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
settings.ContractResolver = new DefaultContractResolver()
{
IgnoreSerializableInterface = true,
IgnoreSerializableAttribute = true
};
var x = new WebClient().DownloadString("http://localhost:58857/api/home/1");
PersonEntity pe = JsonConvert.DeserializeObject<PersonEntity>(x, settings);
Actually, you don't have to do any of that, just return the entity from the webapi method. WebAPI will then serialize the entity to JSON because you have set that up. On the client, it will be deserialized properly. by simply directly using the object from the webapi method, you don't have to deserialize anything. That's what webapi is for.
If it still doesn't work, I'll rework your demo tomorrow
Joined: 06-Feb-2013
Hi Frans,
i tried various ways but couldn't get it to work without Walaa's method of desalinizing. Could you please take some time to show us the correct way? Could you post a sample for CRUD operation with JSON and LLblEntity?
Thanks
There's a way, using HttpClient, but it always includes a step: configuring the json formatter on the client. The WebUI has to have a configured json formatter like it is configured on the server, otherwise it won't work (not with walaa's method, not with anything).
Example hack:
public async Task<ActionResult> Index()
{
var x = new WebClient().DownloadString("http://localhost:58857/api/home/1");
PersonEntity pe = JsonConvert.DeserializeObject<PersonEntity>(x, ConfigureJSon());
return View();
}
private JsonSerializerSettings ConfigureJSon()
{
var toReturn = new JsonSerializerSettings();
toReturn.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
toReturn.ContractResolver = new DefaultContractResolver()
{
IgnoreSerializableInterface = true,
IgnoreSerializableAttribute = true
};
return toReturn;
}
This will properly deserialize the object.
To get the HttpClient approach, please check: http://stackoverflow.com/questions/22534180/asp-net-web-api-how-to-deserialize-a-json
but the approach you have above does work too. HttpClient looks to me the way to go though, as it provides async fetching. You do need a nuget package: Microsoft.AspNet.WebApi.Client
Also, the WebUI doesn't need to reference the dbspecific project, and neither the WebUI nor the WebApi project needs to reference the sqlserver DQE project.
Joined: 06-Feb-2013
Ok. following the HttpClient route i am now able to deserialize JSON to LLBLEntity . Here is the code
public async Task<ActionResult> Index(int i)
{
var pe = new PersonEntity();
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:58857/api/home/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
try
{
HttpResponseMessage response = await client.GetAsync(i.ToString());
var result = await response.Content.ReadAsStringAsync();
pe = JsonConvert.DeserializeObject<PersonEntity>(result, ConfigureJSon());
}
catch (HttpRequestException e)
{
if (e.Source != null)
{
Console.WriteLine("HttpRequestException source: {0}", e.Source);
}
}
return View(pe);
}
}
private JsonSerializerSettings ConfigureJSon()
{
var toReturn = new JsonSerializerSettings();
toReturn.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
toReturn.ContractResolver = new DefaultContractResolver()
{
IgnoreSerializableInterface = true,
IgnoreSerializableAttribute = true
};
return toReturn;
}
BUT doing the same thing for TypedView gives me error when deserializing. i have added the attribute "DataContract" in TypedView and "DataMember" to TypedViewField.
Following is the code in WebUI project.
public async Task<ActionResult> Index()
{
var pe = new PersonResultTypedView();
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:58857/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
try
{
HttpResponseMessage response = await client.GetAsync("api/home/");
var result = await response.Content.ReadAsStringAsync();
pe = JsonConvert.DeserializeObject<PersonResultTypedView>(result, ConfigureJSon());
}
catch (HttpRequestException e)
{
if (e.Source != null)
{
Console.WriteLine("HttpRequestException source: {0}", e.Source);
}
}
return View(pe);
}
}
private JsonSerializerSettings ConfigureJSon()
{
var toReturn = new JsonSerializerSettings();
toReturn.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
toReturn.ContractResolver = new DefaultContractResolver()
{
IgnoreSerializableInterface = true,
IgnoreSerializableAttribute = true
};
return toReturn;
}
and result from WebApi
[{"Personid":1,"Name":"Johnt","Branch":"sfo588","Note":"Test Note"},{"Personid":2,"Name":"John 2","Branch":"sfo","Note":"Test Note"},{"Personid":3,"Name":"hhhhh","Branch":"fffff","Note":null},{"Personid":33,"Name":"uu","Branch":"yy","Note":null},{"Personid":34,"Name":"tyy","Branch":"tyt","Note":null},{"Personid":35,"Name":"d","Branch":"dr","Note":null},{"Personid":36,"Name":"vip","Branch":"hh","Note":null}]
here is the code from WebApi project
public PersonResultTypedView Get()
{
PersonResultTypedView pt = new PersonResultTypedView();
using (var d = new DataAccessAdapter())
{
RetrievalProcedures.FetchPersonResultTypedView(pt);
}
return pt;
}
but i get the following error.Please help.
Server Error in '/' Application.
Cannot create and populate list type WebApi.DAL.TypedViewClasses.PersonResultTypedView.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Cannot create and populate list type WebApi.DAL.TypedViewClasses.PersonResultTypedView.
Source Error:
Line 31: HttpResponseMessage response = await client.GetAsync("api/home/");
Line 32: var result = await response.Content.ReadAsStringAsync();
Line 33: pe = JsonConvert.DeserializeObject<PersonResultTypedView>(result, ConfigureJSon());
Line 34: }
Line 35: catch (HttpRequestException e)
Source File: c:\TEMP\DemoLLBL\DemoLLBL\WebUI\WebUI\Controllers\HomeController.cs Line: 33
Stack Trace:
[InvalidOperationException: Cannot create and populate list type WebApi.DAL.TypedViewClasses.PersonResultTypedView.]
Newtonsoft.Json.Utilities.CollectionUtils.CreateList(Type listType, Boolean& isReadOnlyOrFixedSize) +1219
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id) +156
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) +233
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) +740
Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) +1143
Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType) +47
Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings) +193
Newtonsoft.Json.JsonConvert.DeserializeObject(String value, JsonSerializerSettings settings) +118
WebUI.Controllers.<Index>d__0.MoveNext() in c:\TEMP\DemoLLBL\DemoLLBL\WebUI\WebUI\Controllers\HomeController.cs:33
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +93
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +52
System.Runtime.CompilerServices.TaskAwaiter.GetResult() +21
lambda_method(Closure , Task ) +64
System.Threading.Tasks.TaskHelpersExtensions.ThrowIfFaulted(Task task) +37
System.Web.Mvc.Async.TaskAsyncActionDescriptor.EndExecute(IAsyncResult asyncResult) +114
System.Web.Mvc.Async.<>c__DisplayClass34.<BeginInvokeAsynchronousActionMethod>b__33(IAsyncResult asyncResult) +65
System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +47
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +135
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +102
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +49
System.Web.Mvc.Async.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3c() +117
System.Web.Mvc.Async.<>c__DisplayClass45.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3e() +323
System.Web.Mvc.Async.<>c__DisplayClass30.<BeginInvokeActionMethodWithFilters>b__2f(IAsyncResult asyncResult) +44
System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +47
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +135
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +102
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +50
System.Web.Mvc.Async.<>c__DisplayClass28.<BeginInvokeAction>b__19() +72
System.Web.Mvc.Async.<>c__DisplayClass1e.<BeginInvokeAction>b__1b(IAsyncResult asyncResult) +185
System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +42
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +132
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +56
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +40
System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +34
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +70
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +138
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +44
System.Web.Mvc.Controller.<BeginExecute>b__15(IAsyncResult asyncResult, Controller controller) +39
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +62
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +138
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +39
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +39
System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__4(IAsyncResult asyncResult, ProcessRequestState innerState) +39
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +70
System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +138
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +40
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +38
System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar) +129
That's perhaps due to the serialization of the datatable the typed view really is. It's an MVC / WebApi problem so I can't help you further. The think I can think of is that you have to serialize the datatable differently (i.e. using the default json.net settings, not the ones set for the entities), but I don't know.
In v4.2 we added the possibility to generate typedviews as POCOs, which will work with the setup for the entities.