I'm a bit confused how to use DTOs in my WebAPI controllers. I'm using the Database first concept of Entity Framework. The following Entity Data Model was generated:
//Generated class by EDM:
public partial class Address
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Address()
{
this.Member = new HashSet<Member>();
}
public int Id { get; set; }
public string Street { get; set; }
public Nullable<short> Street_Number { get; set; }
public Nullable<decimal> Zip { get; set; }
public string City { get; set; }
public string Country { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Member> Member { get; set; }
}
To use Data Annotations I need to define a AddressDTO
because every time when I need to modify the EDM the data model will generated again and the Data Annotations are lost.
So next, I defined the AddressDTO
:
public class AddressDTO
{
public int Id { get; set; }
[Required]
[StringLength(100,ErrorMessage="The max. length of the street name is 100 characters.")]
public string Street { get; set; }
public Nullable<short> Street_Number { get; set; }
[Required]
public Nullable<decimal> Zip { get; set; }
[Required]
[RegularExpression(@"[a-z,A-Z]",ErrorMessage="Only characters are allowed.")]
public string City { get; set; }
[Required]
public string Country { get; set; }
}
And the controller looks like the code below:
[RoutePrefix("api/address")]
public class AddressController : ApiController
{
private PersonEntities db = new PersonEntities();
// GET: api/Address
[HttpGet]
[ResponseType(typeof(AddressDTO))]
public async Task<IHttpActionResult> GetAll()
{
var addressList = await db.Address.ToListAsync();
return Ok(addressList);
}
}
When I'm starting the RestAPI to display the result in browser, I always get the following json result:
[
{
"Member": [ ],
"Id": 1,
"Street": "Example Street",
"Street_Number": 1,
"Zip": 12345.0,
"City": "New York",
"Country": "USA"
},...
]
But I need the following desired result:
[
{
"Street": "Example Street",
"Street_Number": 1,
"Zip": 12345.0,
"City": "New York",
"Country": "USA"
},...
]
Has anyone an idea how could I resolve that?
Your new edit simply means you don't need Id
and Member
properties in your AddressDTO
model. And yo should shape the result to be a List<AddressDTO>
while you are returning List<Address>
.
So just remove unused properties from AddressDTO
and then shape the result by selecting new AddressDTO
and setting properties:
var result = db.Address.Select(x=> new AddressDTO()
{
Street = x.Id,
Street_Number = x.Street_Number,
City = x.City,
Country = x.Country
}).ToListAsync();
If you want to make the linq shorter, you can add such constructor to AddressDTO
:
public AddressDTO(Address x)
{
Street = x.Id;
Street_Number = x.Street_Number;
City = x.City;
Country = x.Country;
}
Then in controller:
var result = db.Address.Select(x=> new AddressDTO(x)).ToListAsync();
Also in a large project, you can rely on some object mappers like auto mapper as mentioned in an answer.
Use a library like Automapper to handle your needs.
Then you just need to modify the following line to this for example:
var addressList = await Mapper.Map<IList<AddressDto>>(db.Address.ToListAsync());
This will convert your Address list to an AddressDto list where you can control what gets converted or not so not to pass Members for example to your view. And Automapper will automatically know what to convert if the field names are the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With