Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web API binding immutable models

In our codebase DTOs are immutable types with readonly fields, getters for the state and a constructor that accepts the values, so a hypothetical person type looks like this:

public class Person
    {
        private readonly String _firstName;
        private readonly String _secondName;

        public Person(String firstName, String secondName)
        {
            _firstName = firstName;
            _secondName = secondName;
        }

        public String FirstName
        {
            get { return _firstName; }
        }

        public String SecondName
        {
            get { return _secondName; }
        }
    }

With Web API, is it possible to bind a model like this without exposing public setters on the properties?

like image 766
richzilla Avatar asked Apr 13 '15 08:04

richzilla


2 Answers

YES, IT IS POSSIBLE to bind this without public properties. By default, you would need a public setter for this to work. However, if you have a constructor that does the initializing and it is the default one, the framework can construct the objects.

In the example that you have shown, since there is only one constructor which accepts both fields (FirstName and LastName), it uses the default constructor to create the object.

This works because of the de-serialization capabilities of the Json serializer. If you have multiple constructors you can use the JsonConstructor attribute to specify which constructor to use and that can set your readonly fields.

like image 134
Praveen Paulose Avatar answered Oct 02 '22 00:10

Praveen Paulose


You could deal with this by having a model that you bind your WebAPI request to, with an implicit conversion to the immutable type:

public class PersonRequestModel
{
    public String FirstName { get; set; }
    public String SecondName { get; set; }

    public static implicit operator Person(PersonRequestModel request) {
        return new Person(request.FirstName, request.SecondName);
    }
}

public class Person
{
   private readonly String _firstName;
   private readonly String _secondName;

   public Person(String firstName, String secondName)
   {
       _firstName = firstName;
       _secondName = secondName;
   }

   public String FirstName
   {
       get { return _firstName; }
   }

   public String SecondName
   {
       get { return _secondName; }
   }
}
like image 38
Ed Courtenay Avatar answered Oct 01 '22 23:10

Ed Courtenay