Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 months ago.
Improve this question
I am getting this error trying to call a web2.0 api call.
Message : "Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'NG_API_DNET_FRX.Models.mproject'."
Here is the JSON that is being sent in from the webpage. The website uses Angular.
{
"id": "3137",
"clientId": "2",
"Name": "MFAQ project1",
"EstimatedStartDate": "07/01/2022",
"EstimatedEndDate": "07/08/2022",
"ActualStartDate": "07/15/2022",
"ActualEndDate": "07/22/2022",
"EstimatedBudget": "44444.0000",
"ActualBudget": "55555.0000"
}
Here is the JSON representation of what is passed in.
I got this by hovering on the routine parameter and copying from the watch....
Note the double squigly {{...}} surrounding the object. JSONLint complains about this but it seems to be consistent across all the calls and web api deals with it.
?? is this my problem ??
{{
"id": 3137,
"clientId": 2,
"Name": "MFAQ project1",
"EstimatedStartDate": "07/13/2022",
"EstimatedEndDate": "6/8/2022",
"ActualStartDate": "6/15/2022",
"ActualEndDate": "6/22/2022",
"EstimatedBudget": 44444,
"ActualBudget": 55555
}}
Here is the target structure
public class mproject
{
public int id;
public int clientId;
public string Name;
public string EstimatedStartDate;
public string EstimatedEndDate;
public string ActualStartDate;
public string ActualEndDate;
public decimal EstimatedBudget;
public decimal ActualBudget;
public string sbProperties;
public string projectType;
public mprojectRev[] Revisions;
}
[System.Web.Http.HttpPatch]
[Route("{itemId_}")]
public IHttpActionResult PatchItemById([FromUri] int itemId_, [FromBody] mproject webForm_ )
{
//if the parameter is of type mproject webform is null
//If i change the type to dynamic or object, and then try to //it, this is where i get the error
//mproject webForm_;
//try
//{
// webForm_ = (mproject)webForm_1;
//}
//catch (Exception ex)
//{
// return JSONStringResultExtension.JSONString(this, errorAsJSON(ex), HttpStatusCode.InternalServerError);
//
}
}
There is no inner exception.
The value passed in does not include 3 properties defined on mproject.
I do not believe that is the problem because I have had success in that scenario before.
I am working w/ dates today... that is most likely where the problem is.
While I of course would love someone to solve my problem for me, what I really need is to get more information on the exception so I know what is causing the problem.
So the question is : Why is this cast throwing an exception
What would really help is learning where can I find more information about why this cast is throwing an exception.
If someone has troubleshooting techniques, I would love those as well.
these three properties are missing from your json post:
public string sbProperties;
public string projectType;
public mprojectRev[] Revisions;
if they are optional change to:
public string? sbProperties ;
public string? projectType;
public mprojectRev[]? Revisions;
if they are not optional you need to pass those values in too
if you open dev tools with f12 in browser and go to Network, click the request and select the response tab it should show you the full response sent back from the api which would probably detail the issues
Related
I've got following setup: C#, ServiceStack, MariaDB, POCOs with objects and structs, JSON.
The main question is: how to use ServiceStack to store POCOs to MariaDB having complex types (objects and structs) blobbed as JSON and still have working de/serialization of the same POCOs? All of these single tasks are supported, but I had problems when all put together mainly because of structs.
... finally during writing this I found some solution and it may look like I answered my own question, but I still would like to know the answer from more skilled people, because the solution I found is a little bit complicated, I think. Details and two subquestions arise later in the context.
Sorry for the length and for possible misinformation caused by my limited knowledge.
Simple example. This is the final working one I ended with. At the beginning there were no SomeStruct.ToString()/Parse() methods and no JsConfig settings.
using Newtonsoft.Json;
using ServiceStack;
using ServiceStack.DataAnnotations;
using ServiceStack.OrmLite;
using ServiceStack.Text;
using System.Diagnostics;
namespace Test
{
public class MainObject
{
public int Id { get; set; }
public string StringProp { get; set; }
public SomeObject ObjectProp { get; set; }
public SomeStruct StructProp { get; set; }
}
public class SomeObject
{
public string StringProp { get; set; }
}
public struct SomeStruct
{
public string StringProp { get; set; }
public override string ToString()
{
// Unable to use .ToJson() here (ServiceStack does not serialize structs).
// Unable to use ServiceStack's JSON.stringify here because it just takes ToString() => stack overflow.
// => Therefore Newtonsoft.Json used.
var serializedStruct = JsonConvert.SerializeObject(this);
return serializedStruct;
}
public static SomeStruct Parse(string json)
{
// This method behaves differently for just deserialization or when part of Save().
// Details in the text.
// After playing with different options of altering the json input I ended with just taking what comes.
// After all it is not necessary, but maybe useful in other situations.
var structItem = JsonConvert.DeserializeObject<SomeStruct>(json);
return structItem;
}
}
internal class ServiceStackMariaDbStructTest
{
private readonly MainObject _mainObject = new MainObject
{
ObjectProp = new SomeObject { StringProp = "SomeObject's String" },
StringProp = "MainObject's String",
StructProp = new SomeStruct { StringProp = "SomeStruct's String" }
};
public ServiceStackMariaDbStructTest()
{
// This one line is needed to store complex types as blobbed JSON in MariaDB.
MySqlDialect.Provider.StringSerializer = new JsonStringSerializer();
JsConfig<SomeStruct>.RawSerializeFn = someStruct => JsonConvert.SerializeObject(someStruct);
JsConfig<SomeStruct>.RawDeserializeFn = json => JsonConvert.DeserializeObject<SomeStruct>(json);
}
public void Test_Serialization()
{
try
{
var json = _mainObject.ToJson();
if (!string.IsNullOrEmpty(json))
{
var objBack = json.FromJson<MainObject>();
}
}
catch (System.Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
public void Test_Save()
{
var cs = "ConnectionStringToMariaDB";
var dbf = new OrmLiteConnectionFactory(cs, MySqlDialect.Provider);
using var db = dbf.OpenDbConnection();
db.DropAndCreateTable<MainObject>();
try
{
db.Save(_mainObject);
var dbObject = db.SingleById<MainObject>(_mainObject.Id);
}
catch (System.Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}
}
What (I think) I know / have tried but at first didn't help to solve it myself:
ServiceStack stores complex types in DB as blobbed JSV by default (last paragraph of first section: https://github.com/ServiceStack/ServiceStack.OrmLite), so it is necessary to set it the way it is proposed: MySqlDialect.Provider.StringSerializer = new JsonStringSerializer(); (https://github.com/ServiceStack/ServiceStack.OrmLite#pluggable-complex-type-serializers)=> default JSV changed to JSON.
the ServiceStack's serialization does not work with structs, it is necessary to treat them special way:
a) according to https://github.com/ServiceStack/ServiceStack.Text#c-structs-and-value-types and example https://github.com/ServiceStack/ServiceStack.Text/#using-structs-to-customize-json it is necessary to implement TStruct.ToString() and static TStruct.ParseJson()/ParseJsv() methods.
b) according to https://github.com/ServiceStack/ServiceStack.Text/#typeserializer-details-jsv-format and unit tests https://github.com/ServiceStack/ServiceStack.Text/blob/master/tests/ServiceStack.Text.Tests/CustomStructTests.cs it shall be TStruct.ToString() (the same as in a) and static TStruct.Parse().
Subquestion #1: which one is the right one? For me, ParseJson() was never called, Parse() was. Documentation issue or is it used in other situation?
I implemented option b). Results:
IDbConnection.Save(_mainObject) saved the item to MariaDB. Success.
Through the saving process ToString() and Parse() were called. In Parse, incoming JSON looked this way:
"{\"StringProp\":\"SomeStruct's String\"}". Fine.
Serialization worked. Success.
Deserialization failed. I don't know the reason, but JSON incoming to Parse() was "double-escaped":
"{\\\"StringProp\\\":\\\"SomeStruct's String\\\"}"
Subquestion #2: Why the "double-escaping" in Parse on deserialization?
I tried to solve structs with JsConfig (and Newtonsoft.Json to get proper JSON):
JsConfig<SomeStruct>.SerializeFn = someStruct => JsonConvert.SerializeObject(someStruct);
JsConfig<SomeStruct>.DeSerializeFn = json => JsonConvert.DeserializeObject<SomeStruct>(json);
a) at first without ToString() and Parse() defined in the TStruct. Results:
Save failed: the json input in JsonConvert.DeserializeObject(json) that is used during Save was just type name "WinAmbPrototype.SomeStruct".
De/serialization worked.
b) then I implemented ToString() also using Newtonsoft.Json. During Save ToString() was used instead of JsConfig.SerializeFn even the JsConfig.SerializeFn was still set (maybe by design, I do not judge). Results:
Save failed: but the json input of DeserializeFn called during Save changed, now it was JSV-like "{StringProp:SomeStruct's String}", but still not deserializable as JSON.
De/serialization worked.
Then (during writing this I was still without any solution) I found JsConfig.Raw* "overrides" and tried them:
JsConfig<SomeStruct>.RawSerializeFn = someStruct => JsonConvert.SerializeObject(someStruct);
JsConfig<SomeStruct>.RawDeserializeFn = json => JsonConvert.DeserializeObject<SomeStruct>(json);
a) at first without ToString() and Parse() defined in the TStruct. Results are the same as in 2a.
b) then I implemented ToString(). Results:
BOTH WORKED. No Parse() method needed for this task.
But it is very fragile setup:
if I removed ToString(), it failed (now I understand why, default ToString produced JSON with just type name in 2a, 3a).
if I removed RawSerializeFn setting, it failed in RawDeserializeFn ("double-escaped" JSON).
Is there some simpler solution? I would be very glad if someone points me to better direction.
Acceptable would be maybe two (both of them accessible because of different circumstances):
if I am the TStruct owner: with just pure TStruct.ToString() and static TStruct.Parse() to support out of the box de/serialization and DB by ServiceStack (without different input in Parse()).
if I am a consumer of TStruct with no JSON support implemented and I am without access to its code: until now I did not find the way, if the ToString is not implemented: Save to DB did not work. Maybe would be fine to ensure JsConfig serialize functions are enough for both de/serialization and when used during saving to DB.
And the best one would be without employing other dependency (e.g. Newtonsoft.Json) to serialize structs. Maybe some JsConfig.ShallProcessStructs = true; (WARNING: just a tip, not working as of 2021-04-02) would be fine for such situations.
ServiceStack treats structs like a single scalar value type, just like most of the core BCL Value Types (e.g. TimeSpan, DateTime, etc). Overloading the Parse() and ToString() methods and Struct's Constructor let you control the serialization/deserialization of custom structs.
Docs have been corrected. Structs use Parse whilst classes use ParseJson/ParseJsv
If you want to serialize a models properties I'd suggest you use a class instead as the behavior you're looking for is that of a POCO DTO.
If you want to have structs serailized as DTOs in your RDBMS an alternative you can try is to just use JSON.NET for the complex type serialization, e.g:
public class JsonNetStringSerializer : IStringSerializer
{
public To DeserializeFromString<To>(string serializedText) =>
JsonConvert.DeserializeObject<To>(serializedText);
public object DeserializeFromString(string serializedText, Type type) =>
JsonConvert.DeserializeObject(serializedText, type);
public string SerializeToString<TFrom>(TFrom from) =>
JsonConvert.SerializeObject(from);
}
MySqlDialect.Provider.StringSerializer = new JsonNetStringSerializer();
I have the weirdest problem that suddenly occurred:
In some (many) cases, suddently, parsing a DTO that contains long fails, depending on the value of the long. Let's look what happening. I am using ServiceStack and Visual Studio 2017, .NET Framework 4.7.2.
The service
[Tag("Notifications")]
[Route(Misc.BASE_PATH, "PUT")]
public class SetActorNotificationsRead : IReturn<SetActorNotificationsReadResponse>
{
public List<string> NotificationIds { get; set; }
public List<string> Test { get; set; }
public long MyLong { get; set; }
}
and I call this via Postman, like this:
in this case, it works as expected, the DTO is populated correctly:
If I change MyLong to 1234, it fails with a
Could not load file or assembly 'System.Numerics.Vectors
but if I change it to 12345, it works again:
To make matters worse, if I change the NotificationIds to a List<long>, it gets even weirder:
This Postman call fails, since the NotificationIds list is null:
but if I change the request, and add a zero in front of the four 9:s, then it works:
If I do [ 9999, 123 ], the NotificationIds is still null, but if I do [ 09999, 123 ], or [ 99991, 123 ] its not null and both values are in the list.
I'm clueless. Any ideas?
The issue is in the Exception due to a runtime dependency issue where it can't load 'System.Numerics.Vectors' assembly.
You can try adding a manual reference to System.Numerics.Vectors.
From package: https://www.nuget.org/packages/System.Numerics.Vectors
Update: After all day messing with this, I fixed it.
I Changed my mobileserviceclient URL to include https instead of HTTP.
I think this was causing my post to instead be a get request that returned an array of "Comment" and tried to parse it to a single "Comment" therefore the error.
Having trouble debugging this, I have the following table/class:
public class Comment
{
public string Content { get; set; }
public string UserId { get; set; }
public string MenuItemId { get; set; }
}
Using AzureMobileServiceClient I can get data from the Azure Mobile App into my Xamarin App so the JSON returned from the client must be getting deserialized into my Comment type but when I try to add data using the following code:
var comment = new Comment
{
Content = NewComment,
MenuItemId = Item.Id,
UserId = App.CloudService.CurrentUser.UserId
};
await App.CloudService.client.GetTable<Comment>().InsertAsync(comment);
I get the error "Cannot populate JSON array onto type 'Comment'"
I can insert the data fine using postman definitely something wrong on the client-side. I saw one other question on this and they said they fixed it by deleting the project and remaking but I'd rather figure out what is actually happening.
I think this is a case of out of date documentation but I'm unable to find a more recent example.
Using the following code generates an exception on the initialisation of the webjob and it gets stuck in a "pending restart" loop.
public static void GenerateExcelFile(
[QueueTrigger("excel")] JobFile message,
Guid Id,
[Table("JobFile")] IDictionary<Tuple<string, string>, object> table,
{
//More Code
}
Replacing "object" with "JobFile" produces the same error. It's quite a length stacktrace so I've only posted the top of it here. Using ILSpy it looks like this shouldn't work so I'm not sure if this feature has been removed since the tutorial was written.
[09/13/2014 11:07:53 > be5c40: ERR ] Unhandled Exception:
Microsoft.Azure.WebJobs.Host.Indexers.FunctionIndexingException:
Error indexing method 'GenerateExcelFile' --->
System.InvalidOperationException: Can't bind Table to type
'System.Collections.Generic.IDictionary`2[System.Tuple`2[System.String,System.String],System.Object]'.
[09/13/2014 11:07:53 > be5c40: ERR ] at Microsoft.Azure.WebJobs.Host.Tables.TableAttributeBindingProvider.TryCreateAsync(BindingProviderContext context)
[09/13/2014 11:07:53 > be5c40: ERR ] at Microsoft.Azure.WebJobs.Host.Bindings.CompositeBindingProvider.<TryCreateAsync>d__0.MoveNext()
I've tried this on 0.5 beta and 0.6 beta of the SDK.
The documentation that you are pointing to is out of date. IDictionary binding was removed for Tables. You can use ICollector binding for Inserting or replacing, TableEntity/ IQueryable binding for reading and CloudTable binding for modifying an entity.
The following samples demonstrate Tables usage
https://github.com/Azure/azure-webjobs-sdk-samples/tree/master/BasicSamples/TableOperations
https://github.com/bradygaster/siteMonitR
As I had to search a while to find how to use the ICollector binding, I thought I'd share.
It looks like it belongs to a new release in Microsoft.Azure.WebJobs so make sure you are using the version 0.6.0-beta.
In your case it would be something like
public static void GenerateExcelFile(
[QueueTrigger("excel")] JobFile message,
Guid Id,
[Table("JobFile")] ICollector<JobFile> tableBinding
{
//More Code
}
public class JobFile
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public string Name { get; set; }
}
P.S. I have not tested this! :P
See the link for details
http://blogs.msdn.com/b/webdev/archive/2014/09/12/announcing-the-0-6-0-beta-preview-of-microsoft-azure-webjobs-sdk.aspx
I'm sending a json payload in a PUT request to a web API controller action. The action in question has a signature that looks like this:
public IHttpActionResult Post([FromBody]SaveThingRequest request)
SaveThingRequest looks something like this:
public class SaveThingRequest
{
public List<ElementInfo> Elements { get; set; }
public class ElementInfo
{
public List<ElementSettingInfo> Settings { get; set; }
public class ElementSettingInfo
{
public string Name { get; set; }
public string Value { get; set; }
}
}
}
I'm posting json in the body of the request that contains Elements that have Settings. I've confirmed this by manually deserializing in the controller action and confirming that the JSON has a structure that looks something like:
{
Elements: [
{
Settings: [
{
Name: 'Name 1',
Value: 'Value 1'
},
{
Name: 'Name 2',
Value: 'Value 2'
}
]
},
{
Settings: [
{
Name: 'Name 1',
Value: 'Value 1'
},
{
Name: 'Name 2',
Value: 'Value 2'
}
]
}
]
}
However, when .NET deserializes the payload and creates the SaveThingRequest, my Elements are populated but all of them have a null Settings property. I don't know how else to troubleshoot this. Does anyone have any thoughts on what might be going on here?
This question should be deleted. It works as advertised. My problem was that I had an additional property on the JSON called 'settings' (lower-case) that the deserializer was trying to match because NewtonSoft deserialization attempts a non-case sensitive match if a case sensitive one isn't found. I was able to discover what was happening by changing the signiture of the method to:
public IHttpActionResult Post([FromBody]string request)
and then adding this to the method implementation:
var result = JsonConvert.DeserializeObject<SaveThingRequest>(request);
I got a deserialization exception saying:
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type
'System.Collections.Generic.List`1[Noteable.Contracts.ClinicalReports.SaveThingRequest+ElementInfo+ElementSettingInfo]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly. To fix this error either change the JSON to a JSON array
(e.g. [1,2,3]) or change the deserialized type so that it is a normal
.NET type (e.g. not a primitive type like integer, not a collection
type like an array or List) that can be deserialized from a JSON
object. JsonObjectAttribute can also be added to the type to force it
to deserialize from a JSON object. Path
'Elements[0].settings.TextSize', line 11, position 20.
The end of the message showed me what was being deserialized when the deserializer failed and pointed me in the right direction. =[
I was stuck in the same problem. However, the problem was something else.
In my case, the property that was not getting serialize was declared without public access specifier. I declared it to public, and it ran perfectly fine.
Hope this will help someone who got stuck in this situation. It took me 20 mins to reach this solution.
Make sure you didn't do something stupid like I did and sent a partially 'stringified' JSON string from the browser instead of a JSON object.
See the problem? I didn't at first until I tried deserializing it from a string and then I realized that shippingAddress itself was a string instead of being an actual JSON object. The rest of the object was proper JSON, but I accidentally serialized the shippingAddress field.
{
"fspID": 571285,
"foo": 444,
"shippingAddress": "{\"countryCode\":\"US\",\"firstName\":\"Test User\",\"lastName\":null,\"address1\":\"1 Main St4\",\"address2\":null,\"company\":null,\"city\":\"San Jose\",\"stateOrProvince\":\"California\",\"stateCd\":\"CA\",\"zipOrPostal\":\"95131\",\"countryName\":\"United States\",\"countryDesc\":\"United States\",\"phone\":null,\"phone2\":null}"
}
If you are using JSON.NET and the attribute [JsonProperty] to name a property – make sure you haven't accidentally copy pasted the same property twice and forgotten to update the string value.
[JsonProperty("billingAddress")]
public Address BillingAddress { get;set; }
[JsonProperty("billingAddress")]
public Address ShippingAddress { get;set; }
This will throw a Newtonsoft.Json.JsonSerializationException that won't actually be visible to you and will screw up the model.
I had the same problem that the child property was null. However the problem was something else.
I had only a getter on the property, once I added a setter as well, then the property was set as expected.