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.