MongoDB C# driver and MVC4 webapi. Issue in json serialization - asp.net-web-api

I am using MongoDB database with MVC4 WebAPI using the C# driver provided by MongoDB. I have a an issue with serialization. I get the following error,
"ExceptionMessage=Error getting value from '__emptyInstance' on 'MongoDB.Bson.ObjectId'"
If I change the Content-Type to xml in my HTTP request it just works fine. I would appreciate any help.
I have copied the model below.
public class Subscriber
{
public ObjectId _id;
public long SubscriberId { get; set; }
public Name Name { get; set; }
public Address Address { get; set; }
public string Phone { get; set; }
public ICollection<Subscription> Subscription { get; set; }
public Subscriber()
{
Name = new Name();
Address = new Address();
Subscription = new Collection<Subscription>();
}
}
Solution
Converting _id type string and decorating the field as below did the trick
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string _id;
reference: JSON.NET cast error when serializing Mongo ObjectId

For anyone trying the mentioned "solution" in the answer : It simply doesn't work!
Check the marked answer in this, instead.

Related

"[Required]" Data Annotation Not Enforced on POST Methods

I had the idea to use Data Annotations in order to validate ModelState. This works wonderfully. The problem I am having is that the [Required] Data Annotation is being enforced on [Key] fields on post. Our data layer takes care of setting Id's and we don't want anyone consuming the service to have to worry about Id's. Is there a way around this in WebApi2?
I have looked at this question, and removing the Id field from ModelState in the POST method before checking for valid ModelState would work. The issue with that is that we use a filter for ModelState.
EDIT:
After doing some more research, what I am essentially wanting to do is what the [Bind] attribute does in MVC. After some research, it does not look like this is a feature that has yet been implemented in WebApi. If anyone has any ideas, feel free to post them.
What you can do is to replace your entity with a data transfer object, which is identical to your original entity without the ID field. For example,
The original entity may look like this
public class User
{
[Required]
public Guid UserId { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Username { get; set; }
public string Email { get; set; }
}
and the DTO may look like this
public class UserDto
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Username { get; set; }
public string Email { get; set; }
}
Hope this helps.

Error deserializing JSON to a class with IEnumerable

I need to return a collection with nested optional collections from my WebAPI and convert it back to objects in my Web UI, however I'm getting the following error:
Cannot create and populate list type System.Linq.IQueryable`1[MyNamespace.MyClass].
I'm using Json.Net.
Here is a sample of my code:
public class ClassA
{
public Int64 Id { get; set; }
public String Description { get; set; }
public IEnumerable<ClassB> { get; set; }
}
public class ClassB
{
public Int64 Id { get; set; }
public String Description { get; set; }
}
I've saw some questions here in stackoverflow, but I don't have access to serialization options (it is handled internally by our library).
UPDATE
I've forgot to mention that ClassA is returned as an IQueryable in my Web API.
Changing the return type of my Web API method to IEnumerable instead of IQueryable solved the problem.

Problems with Model binding and validation attributes with asp.net Web API

I am writing a Web API with ASP.NET Web API, and make use of the following View Model.
I seem to be having a problem with the data binding when there are two validation attributes on a particular property (i.e. [Required] and [StringLength(10)]).
When posting a JSON value from a client to a controller action of the form:
// POST api/list
public void Post([FromBody] TaskViewModel taskVM)
I observe the following:
If I remove one of the multiple attributes everything is bound OK;
If I leave in the multiple attributes, the client recieves a 500 internal server error and the body of the Post method is never reached.
Any ideas why this happens?
Cheers
public class TaskViewModel
{
//Default Constructor
public TaskViewModel() { }
public static TaskViewModel MakeTaskViewModel(Task task)
{
return new TaskViewModel(task);
}
//Constructor
private TaskViewModel(Task task)
{
this.TaskId = task.TaskID;
this.Description = task.Description;
this.StartDate = task.StartDate;
this.Status = task.Status;
this.ListID = task.ListID;
}
public Guid TaskId { get; set; }
[Required]
[StringLength(10)]
public string Description { get; set; }
[Required]
[DataType(DataType.DateTime)]
public System.DateTime StartDate { get; set; }
[Required]
public string Status { get; set; }
public System.Guid ListID { get; set; }
}
You need to inspect what is inside in the 500 internal server
make sure that you turn customerror off in your web.config
If you selfhost web.API you need to set GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
use your browser development console's network tab (in IE, Chrome you can get the console with F12) or if you are using FireFox then use FireBug or a thrid party tool like Fiddler.
Then you can see what went wrong on the server and go further to solve your problem.
In your case this is in the response:
"Message":"An error has occurred.","ExceptionMessage":"Property
'StartDate' on type 'MvcApplication3.Controllers.TaskViewModel' is
invalid. Value-typed properties marked as [Required] must also be
marked with [DataMember(IsRequired=true)] to be recognized as
required. Consider attributing the declaring type with [DataContract]
and the property with
[DataMember(IsRequired=true)].","ExceptionType":"System.InvalidOperationException"
So your problem is not that you have two attributes but that you've marked your properties with [Required] to solve this the exception tells you what to do.
You need to add [DataMember(IsRequired=true)] to your required properties where the property type is a value type (e.g int, datatime, etc.):
So change your TaskViewModel to:
[DataContract]
public class TaskViewModel
{
//Default Constructor
public TaskViewModel() { }
[DataMember]
public Guid TaskId { get; set; }
[Required]
[DataMember]
[StringLength(10)]
public string Description { get; set; }
[Required]
[DataMember(IsRequired = true)]
[DataType(DataType.DateTime)]
public System.DateTime StartDate { get; set; }
[Required]
[DataMember]
public string Status { get; set; }
[DataMember]
public System.Guid ListID { get; set; }
}
Some side notes:
You need to reference the System.Runtime.Serialization dll in order to use the DataMemberAttribute
You need to mark your class with [DataContract] and you need to mark all of its properties with [DataMember] not just the required ones.

Json.Net JsonConvert not deserializing properly?

I'm using Json.Net to handle the deserialzing of the response of API calls from the Pipl.com API in my application, and it works fine but for some strange reason it won't deserialize a specific property of the JSON string that I feed to the JsonConvert.DeserializeObject method.
My class is this:
public class Source
{
public string Dsname { get; set; }
public bool IsSponsored { get; set; }
public string Url { get; set; }
public string Domain { get; set; }
public uint ExternalID { get; set; }
public Source()
{
}
}
and everything except the Dsname gets deserialized properly. The Json to be converted is like this:
"source": {
"#is_sponsored": false,
"#ds_name": "Personal Web Space -MySpace",
"url": "http://www.foo.bar"
"domain": "myspace.com"
}
Any idea how to go about this problem? Thank you in advance.
I added a wrapper class and specified the property name as attributes, like this:
public class Source
{
[JsonProperty(PropertyName = "#ds_name")]
public string Dsname { get; set; }
[JsonProperty(PropertyName = "#is_sponsored")]
public bool IsSponsored { get; set; }
public string Url { get; set; }
public string Domain { get; set; }
public uint ExternalID { get; set; }
}
public class RootObject
{
public Source source { get; set; }
}
Then I was able to deserialize fine:
var json = "{\"source\": { \"#is_sponsored\": true, \"#ds_name\": \"Personal Web Space -MySpace\", \"url\": \"http://www.foo.bar\", \"domain\": \"myspace.com\"}}";
var des = JsonConvert.DeserializeObject<RootObject>(json);
Note that I:
- wrapped your sample in a curly braces to make it valid JSON
- added a missing comma
- changed the value of "#is_sponsored" to not be the default value to verify it is desearialized correctly.
Ok I realize, this is a pretty old thread. But I ran into a similar issue earlier and came across this thread.
In my case the class I was trying to se/deserialize had a List<ClassName> public property in it. Which serialized fine, but wont deserialize. I switched it to ClassName[] and the fixed the deserialization problem.
Hope it helps someone else who comes across this thread, or at least gives them something else to look for.

JSON Nullable Deserialization Error

Suppose you have a simple struct, like so:
public struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
And a sample class like so:
public class Map
{
public int ID { get; set; }
public Point? PointA { get; set; }
///...
}
Now, suppose you are passing Map via AJAX as JSON. Question, what value should be passed for the not null scenario?
It may matter that JavaScriptSerializer is being used in a C# 3.5 ASP.NET ASMX web service.
The issue is what I listed in my comment about the question. The automatic properties were the issue. I converted the property and the issue was resolved.

Resources