JSON deserialize to LLBL Entity

Posts   
 
    
hotmail
User
Posts: 47
Joined: 06-Feb-2013
# Posted on: 20-May-2014 12:33:53   

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.

http://weblogs.asp.net/fbouma/archive/2012/10/05/how-to-make-asp-net-webapi-serialize-your-llblgen-pro-entities-to-json.aspx

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

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 21-May-2014 03:17:40   

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?

hotmail
User
Posts: 47
Joined: 06-Feb-2013
# Posted on: 21-May-2014 04:07:22   

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

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 22-May-2014 04:49:52   

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.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 22-May-2014 09:58:42   

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.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 22-May-2014 10:04:45   

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 simple_smile 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 wink

Frans Bouma | Lead developer LLBLGen Pro
hotmail
User
Posts: 47
Joined: 06-Feb-2013
# Posted on: 29-May-2014 07:24:12   

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

Attachments
Filename File size Added on Approval
DemoLLBL.zip 309,360 29-May-2014 07:44.30 Approved
Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 29-May-2014 19:02:48   

I think your issue is related to this thread: https://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=22583

Correct?

hotmail
User
Posts: 47
Joined: 06-Feb-2013
# Posted on: 30-May-2014 06:20:42   

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

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 30-May-2014 09:26:27   

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);

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 30-May-2014 16:26:25   

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. simple_smile

If it still doesn't work, I'll rework your demo tomorrow

Frans Bouma | Lead developer LLBLGen Pro
hotmail
User
Posts: 47
Joined: 06-Feb-2013
# Posted on: 03-Jun-2014 19:39:49   

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

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 04-Jun-2014 11:28:00   

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.

Frans Bouma | Lead developer LLBLGen Pro
hotmail
User
Posts: 47
Joined: 06-Feb-2013
# Posted on: 04-Jun-2014 13:05:27   

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

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 05-Jun-2014 10:01:07   

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.

Frans Bouma | Lead developer LLBLGen Pro