How to work with DTOs in Controller of WebAPI?

ado.net-entity-data-model asp.net-web-api c# dto entity-framework-6

Question

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?

1
3
11/12/2016 2:15:36 PM

Popular Answer

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.

6
11/12/2016 4:30:55 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow