0

In my applicantion, I browse to the URL by supplying the parameters through query string. Based on the URI, the respective controller's action is triggered, and the parameters supplied are auto-mapped to my model.

URL: http://{host}:{port}/{website}/{controller}/{action}?{querystring}

URI: /{controller}/{Action}?{QueryString}

My URI: Employee/Add?EmployeeCode=Code3&EmployeeId=103

EmployeeModel

public class EmployeeModel
{
        public Employee()
        {
        }

        public string EmployeeId { get; set; }

        public string EmployeeCode { get; set; }

        //Some more properties here
}

EmployeeController

[HttpGet]
[Route("Add")]
public IActionResult Add([FromUri] EmployeeModel model)
{
        //Some code here
}

While this all works fabulous, when I browse through, below is the order in which break-points hit,

  1. Add method of EmployeeController
  2. Default constructor of EmployeeModel
  3. set method of EmployeeId property of EmployeeModel
  4. set method of EmployeeCode property of EmployeeModel

I suspect the order in which the properties get initialized is based on the order they are declared in the class.

But, to create an instance and initialize the properties the framework must be using reflection. And as per the MSDN documentation for Type.GetProperties the order is not guarateed.

The GetProperties method does not return properties in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which properties are returned, because that order varies.

I basically want the initialization to take place in a specific order, is this possible?

Community
  • 1
  • 1
Mukesh Bhojwani
  • 2,014
  • 4
  • 20
  • 35
  • 1
    Probably not what you want to hear but WHY order matters? It's usually a bad thing...can't you fix your logic there? – Adriano Repetti Aug 23 '16 at 06:33
  • I am looking for a place when all my properties get initialized. This is to take some decision, so was thinking to do it when the last property gets initialized. But, if the order isn't guaranteed, my last isn't guaranteed. – Mukesh Bhojwani Aug 23 '16 at 08:41
  • You can _track_ initialized properties (even just counting...) but isn't it something you want to do elsewhere to do not add an extra responsibility to model class? – Adriano Repetti Aug 23 '16 at 09:54

1 Answers1

2

You can't get the model binding mechanism to do things in a specific order, but you can make sure that the order is applied where it has to be.

Presumably, EmployeeModel is a domain model object on which the order actually matters, and you're now model binding directly to this type. Instead, introduce an edit model1 which you model bind to, and then map that to your model type:

public class EmployeeEditModel
{
    public string EmployeeId { get; set; }
    public string EmployeeCode { get; set; }
}

// and change your action signature to this:
[HttpGet]
[Route("Add")]
public IActionResult Add([FromUri] EmployeeEditModel model)

1 For an explanation of what an edit model is, see the final remarks on this old answer of mine.


To perform the mapping you have numerous alternatives, some better than others. Pick one that suits you - however, since the reason the order matters is probably something inherent in the domain model object, I'd advice you to put the logic inside it (e.g. in a constructor), to make it easier to remember to change it if the requirements change.

  • Map via a constructor on the model object

    public class EmployeeModel
    {
        public EmployeeModel(string employeeId, string employeeCode /* , ... */)
        {
            // do stuff in whatever order you need
            EmployeeId = employeeId;
            EmployeeCode = employeeCode;
        }
    
        // Now your properties can be get-only
        public string EmployeeId { get; }
        public string EmployeeCode { get; }
    }
    
  • Map via an extension method that does everything in the right order

    public static class EmployeeEditModelExtensions
    {
        public EmployeeModel AsDomainModel(this EmployeeEditModel editModel)
        {
            // do stuff in whatever order you need
            var model = new EmployeeModel();
            model.EmployeeId = editModel.EmployeeId;
            model.EmployeeCode = editModel.EmployeeCode;
            // ...
        }
    
        // Now your properties can be get-only
        public string EmployeeId { get; }
        public string EmployeeCode { get; }
    }
    
  • Use an external framework such as AutoMapper, with custom configuration to make sure that the ordering is correct

  • Do something else. The only purpose is to get you from an EmployeeEditModel instance to an EmployeeModel instance, assigning to the properties of the EmployeeModel in the correct order. Since you write this code yourself, you can do what you want.

Community
  • 1
  • 1
Tomas Aschan
  • 58,548
  • 56
  • 243
  • 402