ASP.NET WebAPI Creating one-level JSON - c#

There are many related entities in Domain assembly. For example People that has navigation properties (Level1) to FamilyRelations, Houses and Persons. Beside this the Houses has own nav.prop (Level2) to Address and Address (Level3) has to City, Street ... etc.
When I set LazyLoadingEnabled to true then I'm getting JSON (on the left side in screen) with all related entities.
How can I get only one level of nesting (as on the right side in scree) or set other levels to NULL value (because I had setting Newtonsoft.Json.NullValueHandling.Ignore)?
Can I implement it without use .Include to each entity?
My class of People:
public class People : BaseEntity
{
public int PersonID { get; set; }
public int HouseID { get; set; }
public int PeopleNumber { get; set; }
public int? FamilyRelationID { get; set; }
//FK to House
public virtual House Houses { get; set; }
//FK to Person
public virtual Person Persons { get; set; }
//FK to FamilyRelations
public virtual FamilyRelations FamilyRelations { get; set; }
}
WebAPI config:
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling
= Newtonsoft.Json.NullValueHandling.Ignore;
I do not have any solution because I did not have enough experience with it. So, I need your suggestions, advices about it. Sorry for my English and if I have to add more informations, please let me know. Thanks
UPDATE
I've tried to add [JsonIgnore] or ignore those properties in mapping class but when I do request get/House then I need to get field from Address without nav.prop and when request get/People then I do not nedd Address. As a result I can't ingnore it.

Never return tracked objects to the controller. Your business logic code (which should not exist in the controller) should map your database aware objects to POCOs. This can be as simple as using
var poco = AutoMapper.Map<People>(livePerson)
And you setup in your mapping profile to ignore those properties so they're not copied.
Note my automapper-fu is rusty that syntax is rough code.
You want to be very careful with any blind mapping as it opens you up to the Mass Assignment vulnerability. This is equally true for going straight to your live tracked objects. If a user sees in their data IsAdmin: false, they might get crafty and post IsAdmin: true. This can be saved to your database with blind assignments.

If you are look for a way to ignore navigation properties in json serialization, this answer can help and you can ignore navigation properties in json serialization by it.

Related

Creating C# objects via MySQL

I would like to get help from you, please :-)
I'm thinking about good way for programmatically creating of classes in C# via MySQL database.
In my app I'm creating composite classes. For example Student, Classroom, Room (dormitory) and so on. Class Student contains properties Classroom and Room. ClassRoom is also related to another entities in database...
public class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Classroom Classroom { get; set; }
public Room Room { get; set; }
}
public class Classroom
{
public int Id { get; set; }
public string Title { get; set; }
public byte Level { get; set; }
public Teacher Teacher { get; set; }
}
...etc
Usually when I need create object of some class, I must create also another classes' objects (sometime a part of database :-) ).
I think this way is not good optimalized, BUT there are great OOP benefits. When I load all students in a DataGridView, I can manage lots of related parts... for example:
Student student = ...
string currentTeacher = student.Classroom.Teacher.LastName //... and so on.
Is OK to create all related classes' objects immediately or is better create only necessary data of current created object and another data load / create "on demand"?
Or absolutely different way? :-)
See, the idea is for you to make a query exactly like what you need an Ingress for a structural database like sql, talking a lot about the EntityFrame mappings where it is possible to query only the student object/table only by its id, however, if no process you will need the Classroom in which it belongs to you use a .Include() no entity and you would only be able to fetch the objects you will need in your request no problem mapping all entities as a bank into objects, the problem is to retrieve all of them from the relation since it only has a feature in some articles
https://learn.microsoft.com/pt-br/ef/ef6/querying/related-data
https://www.entityframeworktutorial.net/code-first/configure-entity-mappings-using-fluent-api.aspx
But if your purpose is performance, mount only the data you need in an object, just an example StudentInfo with the information you need grouped, use a Dapper to make the optimized query and make it do this mapping to your object, gaining performance
this is clear speaking of relational databases like Sql if your case is a NoSql database like MongoDb there is no problem in your mappings since it will return everything in a single document it is structured for this type of information there will be no InnerJoin cost between tables

How to restrict some properties to modified from Web API in .net core?

I am working on .net core Web API project. I have two classes:
public class CategoryMasterDto : CommonInfoDto
{
public int CategoryId { get; set; }
[StringLength(50)]
public string CategoryName { get; set; }
public string CategoryImage { get; set; }
}
public class CommonInfoDto
{
public Guid CreatedBy { get; set; }
public DateTime CreatedDate { get; set; }
public Guid ModifiedBy { get; set; }
public DateTime ModifiedDate { get; set; }
public short Status { get; set; }
}
Now, I want to restrict users to specify values for certain properties from Web API like CategoryId and all properties of CommonInfoDto as I will specify all these properties from my side before inserting data in the database.
I tried using JsonIgnore using which properties will not be visible in the tools like swagger. But again if the user manually specified those properties, the values will be received on the server-side.
For e.g. if I apply JsonIgnore to CategoryId, it will no be visible in swagger but if the user adds the property CategoryId and pass some value, it will be received on the server-side.
I want to achieve two things:
Restrict the users to pass values for certain properties or even if it is passed, those should not be bind to the properties on the server-side during the POST and PUT request.
I want to pass all properties when user requests for GET request.
I already have one solution i.e. to create one DTO for GET and another for POST/PUT. Is there any better solution through which I can use the same DTO for both and achieve what I want.?
You need just one DTO class for GET, POST/PUT. And, you could use AutoMapper tool to configure mapping from model domain class to DTO class, and back. And then, while configuring mapping from DTO to domain model class, you could ignore certain parameters.
CreateMap<CommonInfoDto, CommonInfo>().ForMember(x => x.Guid, opt => opt.Ignore());
It means that you would read data from database (your domain model class), pass it to DTO class with all the parameters; but when you would recieve data from from user (DTO class), while saving you will not use its Guid (because it will be ignored during mapping).
As what everybody is suggesting. This can only be Achieve using 2 classes. Input.Model and Domain.Model, then use Automapper to automatically map properties to your actual Domain.Model during input process (POST/PUT) while you return you Domain.Model in your GET endpoints.

Entity Framework doesn't populate collection properties

I'm having a problem very similar to the ones mentioned in these questions:
Why is Entity Framework navigation property null?
Why EF navigation property return null?
The plot twist in my case is that the navigation collection properties are populated by EF, but only after I've queried DbSet<T> properties of the dependent types in the DbContext. To make my situation clearer, here's how my model is set up:
[Table(nameof(Composer))]
internal class ComposerRelationalDto : RelationdalDtoBase
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public virtual ICollection<NameRelationalDto> LocalizedNames { get; set; } = new HashSet<NameRelationalDto>();
public virtual ICollection<ArticleRelationalDto> Articles { get; set; } = new HashSet<ArticleRelationalDto>();
}
[Table(nameof(ComposerName))]
internal class NameRelationalDto : RelationdalDtoBase
{
[Key]
public long Id { get; set; }
[Required]
[ForeignKey(nameof(Composer))]
public Guid Composer_Id { get; set; }
public ComposerRelationalDto Composer { get; set; }
}
[Table(nameof(ComposerArticle))]
internal class ArticleRelationalDto : RelationdalDtoBase
{
[Key]
public long Id { get; set; }
[Index]
public Guid StorageId { get; set; }
[Required]
[ForeignKey(nameof(Composer))]
public Guid Composer_Id { get; set; }
public ComposerRelationalDto Composer { get; set; }
[Required]
[MaxLength(5)]
public string Language { get; set; }
}
In the corresponding repository I filter ComposerRelationalDto objects by their name:
DbContext.Set<NameRelationalDto>().Where(nameWhereClause).GroupBy(n => n.Composer_Id).Select(group => group.FirstOrDefault().Composer)
The set of ComposerRelationalDtos has empty collections for the Articles and LocalizedNames properties, even though the data has been correctly persisted in the database. However, if I load all DTOs of type ArticleRelationalDto and NameRelationalDto in a QuickWatch while debugging, then the same filter no longer returns empty collections and all relevant objects are present in the collection properties.
What I've tried so far was to
enable lazy loading and the creation of proxies explicitly
configure the one-to many-relationships manually:
modelBuilder.Entity<ComposerRelationalDto>().HasMany(c => c.LocalizedNames).WithRequired(n => n.Composer).HasForeignKey(n => n.Composer_Id);
modelBuilder.Entity<ComposerRelationalDto>().HasMany(c => c.Articles).WithRequired(a => a.Composer).HasForeignKey(a => a.Composer_Id);
and finally I just tried fiddling with the DbQuery<T>.Include() method DbContext.Set<ComposerRelationalDto>().Include(c => c.Articles) which unfortunately throws an ArgumentNullException from one of the internal methods it calls.
Basically, whatever fixes or workarounds I've tried haven't helped, so I must ask for more help.
Edit:
I modified the dependent types' Composer property to be virtual. However, the problem persists.
After using .Select(group => group.FirstOrDefault().Composer).Include(c => c.Articles).Include(c => c.LocalizedNames) I now no longer get an ArgumentNullException (maybe I was getting the ArgumentNullException because I was initially using .Include() in a QuickWatch?), but rather a MySqlException: Unknown column 'Join2.Id' in 'field list'; the Data dictionary contains Key: "Server Error Code" Value: 1054. Also the generated SQL is ridiculously large and barely legible.
I figured it out. It was the internal access modifier on class declarations. A shame, because I really wanted to make the rest of the solution entirely database-agnostic (hence the unusual use of DTOs for code first, instead of the actual entities, as was already pointed out in the comments) and I wanted to enforce this in a strict manner.
Anyway, I played around some more with access modifiers and I could only manage restricting the DB object's visibility by making them public with internal protected constructors. Any other combination of class and ctor visibility involving internal caused the problem to reappear. No luck with InternalsVisibleTo, either.
This question - Entity Framework Code First internal class - is it possible? - seems to suggest that using an internal class shouldn't be a problem for EF, but it appears it is, after all, somewhat of a problem. If it wasn't then (Julie Lerman's answer dates back to 2011), it is now. I'm using EF 6.2.0 at the moment.

N-tier Repository POCOs - Aggregates?

Assume the following simple POCOs, Country and State:
public partial class Country
{
public Country()
{
States = new List<State>();
}
public virtual int CountryId { get; set; }
public virtual string Name { get; set; }
public virtual string CountryCode { get; set; }
public virtual ICollection<State> States { get; set; }
}
public partial class State
{
public virtual int StateId { get; set; }
public virtual int CountryId { get; set; }
public virtual Country Country { get; set; }
public virtual string Name { get; set; }
public virtual string Abbreviation { get; set; }
}
Now assume I have a simple respository that looks something like this:
public partial class CountryRepository : IDisposable
{
protected internal IDatabase _db;
public CountryRepository()
{
_db = new Database(System.Configuration.ConfigurationManager.AppSettings["DbConnName"]);
}
public IEnumerable<Country> GetAll()
{
return _db.Query<Country>("SELECT * FROM Countries ORDER BY Name", null);
}
public Country Get(object id)
{
return _db.SingleById(id);
}
public void Add(Country c)
{
_db.Insert(c);
}
/* ...And So On... */
}
Typically in my UI I do not display all of the children (states), but I do display an aggregate count. So my country list view model might look like this:
public partial class CountryListVM
{
[Key]
public int CountryId { get; set; }
public string Name { get; set; }
public string CountryCode { get; set; }
public int StateCount { get; set; }
}
When I'm using the underlying data provider (Entity Framework, NHibernate, PetaPoco, etc) directly in my UI layer, I can easily do something like this:
IList<CountryListVM> list = db.Countries
.OrderBy(c => c.Name)
.Select(c => new CountryListVM() {
CountryId = c.CountryId,
Name = c.Name,
CountryCode = c.CountryCode,
StateCount = c.States.Count
})
.ToList();
But when I'm using a repository or service pattern, I abstract away direct access to the data layer. It seems as though my options are to:
Return the Country with a populated States collection, then map over in the UI layer. The downside to this approach is that I'm returning a lot more data than is actually needed.
-or-
Put all my view models into my Common dll library (as opposed to having them in the Models directory in my MVC app) and expand my repository to return specific view models instead of just the domain pocos. The downside to this approach is that I'm leaking UI specific stuff (MVC data validation annotations) into my previously clean POCOs.
-or-
Are there other options?
How are you handling these types of things?
It really depends on the projects architecture for what we do. Usually though.. we have services above the repositories that handle this logic for you. The service decides what repositories to use to load what data. The flow is UI -> Controller -> Service -> Repositories -> DB. The UI and/or Controllers have no knowledge of the repositories or their implementation.
Also, StateCount = c.States.Count would no doubt populate the States list anyway.. wouldn't it? I'm pretty sure it will in NHibernate (with LazyLoading causing an extra select to be sent to the DB).
One option is to separate your queries from your existing infrastructure entirely. This would be an implementation of a CQRS design. In this case, you can issue a query directly to the database using a "Thin Read Layer", bypassing your domain objects. Your existing objects and ORM are actually getting in your way, and CQRS allows you to have a "command side" that is separate and possibly a totally different set of tech to your "query side", where each is designed to do it's own job without being compromised by the requirements of the other.
Yes, I'm quite literally suggesting leaving your existing architecture alone, and perhaps using something like Dapper to do this (beware of untested code sample) directly from your MVC controllers, for example:
int count =
connection.Query<int>(
"select count(*) from state where countryid = #countryid",
new { countryid = 123 } );
Honestly, your question has gave me a food for thought for a couple of days. More and more I tend to think that denormalization is the correct solution.
Look, the main point of domain driven design is to let the problem domain drive your modeling decisions. Consider the country entity in the real world. A country has a list of states. However, when you want to know how many states a certain country has, you are not going over the list of the states in the encyclopedia and count them. You are more likely to look at the country's statistics and check the number of states there.
IMHO, the same behavior should be reflected in your domain model. You can have this information in the country's property, or introduce a kind of CountryStatistics object. Whatever approach you choose, it must be a part of the country aggregate. Being in the consistency boundary of the aggregate will ensure that it holds a consistent data in case of adding or removing a state.
Some other approaches:
If the states collection is not expected to change a lot, you can
allow a bit of denormalization - add "NumberOfStates" property to the
Country object. It will optimise the query, but you'll have to make
sure the extra field holds the correct information.
If you are using NHibernate, you can use ExtraLazyLoading - it will
issue another select, but won't populate the whole collection when
Count is called. More info here:
nHibernate Collection Count

Elegant way to map an DTO object graph back to an Entity Framework object graph in a Client/Server app

I have a client/server application where the server uses Entity Framework as the ORM.
Every entity that is to be sent to the client is represented by a DTO-class.
The mapping between the Entity Framework and DTO-classes is handled using AutoMapper.
Let's say we have the following Tables:
Person (string Name, int CountryID)
Country (int CountryID, int Population, string Name)
They are represented by the following EF classes:
class Person
{
public string Name { get; set; }
public int CountryID { get; set; }
public Country Country { get; set;}
}
class Country
{
public int CountryID { get; set; }
public int Population { get; set; }
public string Name { get; set;}
}
Which in turn are represented by the following DTOs:
class PersonDTO
{
public string Name { get; set; }
public CountryDTO Country { get; set;}
}
class CountryDTO
{
public int CountryID { get; set; }
public int Population { get; set; }
public string Name { get; set;}
}
The initial state of the database represents an empty Person-Table and a Country-table that has one entry: (1, 123, 'CountryXYZ')
The clients' app task is to create a new Person Entity and attach its Country-Reference to the available 'CountryXYZ' Country-Entity.
In order to do so, the client app first requests the available CountryDTOs.
It then creates a new PersonDTO instance and sets its Country Property to the only CountryDTO that it has received from the server.
This PersonDTO-instance is then being sent back to the server.
The server in turn maps the PersonDTO-instance back to a Person-instance.
The last servers step is now to store the Person-instance in the ObjectContext and call ObjectContext.SaveChanges().
The problem I have with this approach is that as soon as I call ObjectContext.SaveChanges(), a new Country-row is created in the database instead of just using the available Country-row.
What am I missing here?
I am new to EF and I think this use case is pretty common... so I hope there is an easy fix to this.
In case the problem description is not clear enough please let me know.
Thanks!
If you know that client will always use country it already received from your server (it is existing one) you can simply modify your saving logic to use:
objectContext.PersonSet.AddObject(personToSave);
objectContext.ObjectStateManager
.ChangeObjectState(personToSave.Country, EntityState.Unchanged);
objectContext.SaveChanges();
If you use AddObject method the entity and all its relations are marked as added and will be inserted to the database as new objects unless you reconfigure their state.
Your entity also exposes FK property so you can use FK property when you map your DTO back to entity instead of creating country instance. In such case you will not need to deal with changing the state of relation because that relation will be represented only through integer column.
If client can create both Person and Country in single call you will need some flag in your DTO to differ between existing or new entity or you will have to query database to verify if such Country already exists.
This is an instance where using the Self Tracking Entities would probably be useful to you.
It uses a T4 template to generate your entity classes, and they can be round-tripped across the wire using WCF. However, you need to share the assembly that contains the entities on the client and the server.
If you are in control of both, and you are using .Net for both, I would go that route.

Categories