richzilla
richzilla

Reputation: 42062

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?

Upvotes: 8

Views: 3094

Answers (2)

Praveen Paulose
Praveen Paulose

Reputation: 5771

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.

Upvotes: 18

Ed Courtenay
Ed Courtenay

Reputation: 530

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; }
   }
}

Upvotes: 5

Related Questions