Контроллер ASP.Net MVC FromUri to Model — можем ли мы определить порядок?

В моем заявлении я просматриваю URL-адрес, предоставляя параметры через строку запроса. На основе URI запускается соответствующее действие контроллера, а предоставленные параметры автоматически сопоставляются с моей моделью.

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

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

Мой URI: Сотрудник/Добавить?EmployeeCode=Code3&EmployeeId=103

Модель сотрудника

public class EmployeeModel
{
        public Employee()
        {
        }

        public string EmployeeId { get; set; }

        public string EmployeeCode { get; set; }

        //Some more properties here
}

Контроллер сотрудников

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

Хотя все это работает потрясающе, когда я просматриваю, ниже показан порядок, в котором достигаются точки останова,

  1. Добавить метод EmployeeController
  2. Конструктор по умолчанию для EmployeeModel
  3. установить метод свойства EmployeeId модели EmployeeModel
  4. установить метод свойства EmployeeCode модели EmployeeModel

Я подозреваю, что порядок, в котором инициализируются свойства, основан на порядке их объявления в классе.

Но для создания экземпляра и инициализации свойств фреймворк должен использовать отражение. И согласно документации MSDN для Type.GetProperties заказ не гарантируется.

Метод GetProperties не возвращает свойства в определенном порядке, например в алфавитном порядке или в порядке объявления. Ваш код не должен зависеть от порядка, в котором возвращаются свойства, потому что этот порядок может меняться.

Я в основном хочу, чтобы инициализация происходила в определенном порядке, возможно ли это?


person Mukesh Bhojwani    schedule 23.08.2016    source источник
comment
Вероятно, это не то, что вы хотите услышать, но ПОЧЕМУ порядок имеет значение? Обычно это плохо... не могли бы вы исправить свою логику?   -  person Adriano Repetti    schedule 23.08.2016
comment
Я ищу место, где все мои свойства инициализируются. Это должно принять какое-то решение, поэтому я думал сделать это, когда будет инициализировано последнее свойство. Но, если заказ не гарантирован, мой последний не гарантирован.   -  person Mukesh Bhojwani    schedule 23.08.2016
comment
Вы можете отслеживать инициализированные свойства (даже просто считать...), но разве это не то, что вы хотите сделать в другом месте, чтобы не добавлять дополнительную ответственность к классу модели?   -  person Adriano Repetti    schedule 23.08.2016


Ответы (1)


Вы не можете заставить механизм привязки модели выполнять действия в определенном порядке, но вы можете убедиться, что порядок применяется там, где он должен быть.

Предположительно, EmployeeModel — это объект модели предметной области, для которого действительно важен порядок, и теперь вы привязываете модель непосредственно к этому типу. Вместо этого введите модель редактирования1, к которой вы привязываете модель, а затем сопоставьте ее с вашим типом модели:

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 Объяснение того, что такое модель редактирования, см. в заключительных замечаниях на этот мой старый ответ.


Для выполнения сопоставления у вас есть множество альтернатив, некоторые лучше, чем другие. Выберите тот, который вам подходит, однако, поскольку причина, по которой порядок имеет значение, вероятно, связана с объектом модели предметной области, я бы посоветовал вам поместить логику внутри него (например, в конструкторе), чтобы было легче запомнить изменение это если требования изменятся.

  • Карта через конструктор на объекте модели

    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; }
    }
    
  • Карта через метод расширения, который делает все в правильном порядке

    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; }
    }
    
  • Используйте внешнюю структуру, такую ​​как AutoMapper, с пользовательской конфигурацией, чтобы убедиться в правильности порядка.

  • Сделайте что-нибудь еще. Единственная цель — перевести вас из экземпляра EmployeeEditModel в экземпляр EmployeeModel, назначив свойства EmployeeModel в правильном порядке. Поскольку вы сами пишете этот код, вы можете делать все, что хотите.

person Tomas Aschan    schedule 23.08.2016