c# - Deserialize dynamic property name to c# class - json.net

Json can be any of following and i would not know the master list how do i covert to c# class
{"title": {"fr-FR": "L'Auberge Espagnole"}}
{"title": {"en-GB": "Van Wilder 2: The Rise of Taj"}}
{"title": {"fr-CA": "Crooklyn"}}
{"title": {"es-ES": "Julieta"} }
{"title":{"en":"In Ice Cold Blood"}}
{"title":{"fr":"spiderman"}}
{"title":{"es":"robot"}}
I tried below and it did not work
public class RootObject
{
public Title title { get; set; }
}
public class Title
{
public Dictionary<object, string> items { get; set; }
}

Related

How to get class name in nested fluentvalidation validators

I am trying to implement a complex nested validator using FluentValidation in .Net Core. Suppose there's a failure in one of the nested validators and the error messages are available at validationResult.Errors. I was wondering if is there a way that I can access the name of the object that has the error.
Entities
Constituent
public class Constituent : BaseAuditedEntity
{
[Required]
[MaxLength(50)]
public string ClientProspectID { get; set; }
[InverseProperty("Client")]
public virtual ICollection<Solicit> Solicits { get; set; }
}
Solicit
public class Solicit: BaseAuditedEntity
{
[Required]
[ForeignKey("Client")]
public long ClientId { get; set; }
public StudyType StudyType { get; set; }
public virtual Constituent Client { get; set; }
}
Validators
ConstituentValidator and its nested SolicitValidator
public class ConstituentValidator : AbstractValidator<Constituent>
{
public ConstituentValidator()
{
RuleFor(x => x.ClientProspectID).NotEmpty().WithMessage("Invalid ClientProspectID");
RuleForEach(x => x.Solicits).SetValidator(new SolicitValidator());
}
class SolicitValidator : AbstractValidator<Solicit>
{
public SolicitValidator()
{
RuleFor(x => x.StudyType).NotEqual(StudyType.Invalid).WithMessage("Invalid StudyType");
}
}
}
Just to highlight the question, in the case of failing the validation rule, is there a way that I can find which main or nested validator has failed.
var validationResult = validator.Validate(item);
if (!validationResult.IsValid)
{
invalidData.AddRange(validationResult.Errors.Select(q => new DataImportValidationResult
{
DataImportId = dataImportData.Id,
ClientProspectID = item.ClientProspectID,
ValidationResult = q.ErrorMessage,
AttemptedValue = q.AttemptedValue.ToString(),
Field = q.PropertyName,
Category = "", //Here I need a way to find which object has failed.
}));
}
If it is not possible to access the failed object, is there a way that we can set a property in the validations rule that can be accessible in the validationResult errors?

Castle Dynamic Proxy MixinInstance behaviour

I was struggling with non virtual members in my POCO classes using Castle's DynamicProxy generator and hit upon a way to make this happen using the ProxyGenerationOptions.AddMixinInstance() using the below code.
The question I have is why, if the mixin can send non-virtual members to the interceptor, can't the standard proxy when based on my actual type???
Below is the code.
void Main()
{
var generator = new ProxyGenerator();
Console.WriteLine(Environment.NewLine + "============ Proxy - With Target ===============");
var person = new Person { Name = "Freddy FudPucker", Age = 62 };
var personProxy = CreateProxyWithTarget(generator, person);
Console.WriteLine(((IPerson)personProxy).Name);
Console.WriteLine(((IPerson)personProxy).Age);
((IPerson)personProxy).Name = "Speedy";
((IPerson)personProxy).Age = 64;
Console.WriteLine(((IPerson)personProxy).Name);
Console.WriteLine(((IPerson)personProxy).Age);
Console.WriteLine(((ITracking)personProxy).State);
((ITracking)personProxy).State = 1;
Console.WriteLine(((ITracking)personProxy).State);
}
public object CreateProxyWithTarget(ProxyGenerator generator, Person person)
{
var options = new ProxyGenerationOptions();
options.AddMixinInstance(person);
options.AddMixinInstance(new Tracking());
return generator.CreateClassProxyWithTarget(typeof(ProxyBase), new[] { typeof(ITracking) }, new ProxyBase(), options, new PersonInterceptor());
}
Which gives the following output
Person System.String get_Name()
Freddy FudPucker
62
Person Void set_Name(System.String)
Person Void set_Age(Int32)
Person System.String get_Name()
Speedy
Person Int32 get_Age()
64
Person Int32 get_State()
0
Person Void set_State(Int32)
Person Int32 get_State()
1
Below are the supporting classes and interfaces
public class ProxyBase
{
public ProxyBase()
{
}
}
public interface ITracking
{
int State { get; set; }
}
public class Tracking : ITracking
{
public int State { get; set; }
}
public class Person : IPerson
{
public string Name { get; set; }
public int Age { get; set; }
}
public interface IPerson
{
string Name { get; set; }
int Age { get; set; }
}
public interface IPersonAge
{
int Age { get; set; }
}
class PersonInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine($"Person {invocation.Method}");
invocation.Proceed();
}
}
Your class proxy with target inherits from your ProxyBase class so requires virtual members, while DynamicProxy mixins implement members of the mixin class's interfaces on that proxy class so are implicitly virtual. Effectively mixins work like interface proxies with targets.
// You can do this (from your example):
Console.WriteLine(((IPerson)personProxy).Name);
// ... but not this (because the proxy isn't a Person but is an IPerson):
Console.WriteLine(((Person)personProxy).Name);
The XML documentation for AddMixinInstance has some more detail: https://github.com/castleproject/Core/blob/e2dfb57020d9dbb4b31f3ce548b34cb35ffa3307/src/Castle.Core/DynamicProxy/ProxyGenerationOptions.cs#L208-L225

.NET Core get array in array from config.json

I have an issue where an array object in my config.json is coming back as empty. In the following code, gridFields will come back as empty.
{"grids": [{
"name": "Grid1"
"gridFields": [
{
"Name": "Something",
"Label": "Something"
},
{
"Name": "SomethingElse",
"Label": "SomethingElse"
}]
},
{"name": "Grid2"
"gridFields": [
{
"Name": "Something",
"Label": "Something"
}]
}]
}
I have matching POCOs and made sure the names match up as follows.
public class Grid
{
public string name { get; set; }
public gridFields gridFields {get; set;}
}
public class gridFields
{
public List<gridField> GridFields { get; set; } = new List<gridField>();
public int Count => GridFields.Count();
public IEnumerator GetEnumerator()
{
return GridFields.GetEnumerator();
}
}
public class gridField
{
public string Name { get; set; }
public string Label { get; set; }
}
In my startup I have the following
public void ConfigureServices(IServiceCollection services)
{ services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
var config = new List<Grid>();
Configuration.Bind("grids", config);
services.AddSingleton(config);
}
The config.gridFields ends up holding no values. I have values for name, but not gridFields. Even if I make gridFields List it comes back null.
My question is if there is someway following this current code that I can get the data out of this array in array, or do I need to do something completely different. Why isn't .net core able to bind every object it comes across underneath the parent?
The example json misses a , after the name of each grid.
{
"name": "Grid2",
"gridFields":
[{
"Name": "Something",
"Label": "Something"
}]
}
You have a list of gridField directly under the Grid in the Json.
In the Code however you use another object, GridFields.
You should remove the gridfiels class and use a list of gridField in the Grid class:
public class Grid
{
public string name { get; set; }
public List<gridField> gridFields {get; set;}
}

ASP.net REST service with MS SQL base serializing list as null

Running a ASP.net REST service using a MS SQL server as base.
Model
public class Bookings
{
[Key]
public int BookingId { get; set; }
[Required]
public int UserID { get; set; }
public List<string> BookISBN { get; set; }
}
Sample generated documentation showing the format as "correct"
Sending following data over postman
{
"BookingId": 1,
"UserID": 2,
"BookISBN": [
"sample string 1",
"sample string 2",
"sample string 3"
]
}
However the last list "BookISBN" column is not generated, and API returns parameter as NULL / i:nil="true"
<ArrayOfBookings xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/PublisherDataModel">
<Bookings>
<BookISBN xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" i:nil="true"/>
<BookingId>1</BookingId>
<UserID>2</UserID>
</Bookings>
<Bookings>
<BookISBN xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" i:nil="true"/>
<BookingId>2</BookingId>
<UserID>2</UserID>
</Bookings>
</ArrayOfBookings>
POST controller for Bookings.
// POST api/Bookings
[ResponseType(typeof(Bookings))]
public IHttpActionResult PostBooking(Bookings Booking)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Bookings.Add(Booking);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = Booking.BookingId }, Booking);
}
What am i missing?
You should decorate your action with HttpPost;
[HttpPost]
[ResponseType(typeof(Bookings))]
public IHttpActionResult PostBooking(Bookings Booking)
I had to include / reference it specifically
db.Entry(Booking).Reference(b => b.BookISBNList).Load();

Web API error failed to serialize the response body

Im fairly new to ASP.NET MCV 4 as well as Mongo DB and trying to build web API.
I thought I had finally got it right but when I start the app and enter: http://localhost:50491/api/document into my browser I get this error message
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
Here is my code
This is the Document Class
public class Document
{
[BsonId]
public ObjectId DocumentID { get; set; }
public IList<string> allDocs { get; set; }
}
This is where the Connection to the DB is made:
public class MongoConnectionHelper
{
public MongoCollection<BsonDocument> collection { get; private set; }
public MongoConnectionHelper()
{
string connectionString = "mongodb://127.0.0.1";
var server = MongoServer.Create(connectionString);
if (server.State == MongoServerState.Disconnected)
{
server.Connect();
}
var conn = server.GetDatabase("cord");
collection = conn.GetCollection("Mappings");
}
Here is the ApiController Class:
public class DocumentController : ApiController
{
public readonly MongoConnectionHelper docs;
public DocumentController()
{
docs = new MongoConnectionHelper();
}
public IList<BsonDocument> getAllDocs()
{
var alldocs = (docs.collection.FindAll().ToList());
return alldocs;
}
}
I read futher on and the error message suggested:
Type 'MongoDB.Bson.BsonObjectId' with data contract name 'BsonObjectId:http://schemas.datacontract.org/2004/07/MongoDB.Bson' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
That is all good and well but how do I do that?
Either a) don't serialize your document classes over Web API, and create some DTOs meant to be serialized, or b) use something else as ID.
If you want an easy auto-generated ID, and you're OK with the fact that it will consume slightly more space, you can resort to the following "hack":
public class Document
{
public Document()
{
Id = ObjectId.GenerateNewId().ToString();
}
public string Id { get; set; }
}
This way, you'll get MongoIDs, but they'll be stored as a string.
If you need Web API2 responce in XML format , you need to handle the default Id like below
eg: ObjectId("507f191e810c19729de860ea")
Either you need to remove the Id from serialization.
[DataContract]
public class Document
{
[BsonId]
public string Id { get; set; }
[DataMember]
public string Title { get; set; } //other properties you use
}
Or You can change the Type of ID with custom logic
public class GuidIdGenerator : IIdGenerator
{
public object GenerateId(object container, object document)
{
return Guid.NewGuid();
}
public bool IsEmpty(object id)
{
return string.IsNullOrEmpty(id.ToString());
}
}
public class Document
{
[BsonId(IdGenerator = typeof(GuidIdGenerator))]
public string Id { get; set; }
public string Title { get; set; } //other properties you use
}

Resources