При использовании пользовательского связывателя модели связыватель запускается и заполняет структуру, но UpdateModel всегда дает сбой - PullRequest
0 голосов
/ 16 августа 2011

У меня есть веб-страница, на которой мне нужно вернуть список строк и заполнить объект. Мне придется сделать некоторую пользовательскую обработку для дублирования на основе целых чисел без идентификатора. (не включен в пример).

У меня есть связыватель модели, который анализирует строки, когда я вызываю его явно из списка параметров контроллера, но UpdateModel всегда дает сбой.

UPDATE Если я изменяю тег на workerRequests2, он работает. Итак, как мне переопределить defaultmodelbinder для свойства объекта workerRequests, которое определено как дочерний элемент основного объекта контроллера?

Исключение, которое видно в ModelState, таково:

Exception = {"The parameter conversion from type 'System.String' to type
             'Machete.Domain.WorkerRequest' failed because no type converter 
              can convert between these types."}

Объекты:

public DbSet<WorkOrder> WorkOrders { get; set; }
public DbSet<WorkerRequest> WorkerRequests { get; set; }

Объекты домена:

public class WorkOrder : Record
{
    // ID (comes from Record)
    public int EmployerID { get; set; } //included for context
    public virtual Employer Employer { get; set; }  //included for context
    ...
    public virtual ICollection<WorkerRequest> workerRequests { get; set; }
    //
}

UPDATE

public class WorkerRequest : Record
{
    //public int ID { get; set; }
    public int WorkOrderID { get; set; }
    public virtual WorkOrder workOrder { get; set; }
    public int WorkerID { get; set; }
    public virtual Worker workerRequested { get; set; }
    public string fullName
    {
        get {
            Person p = this.workerRequested.Person;
                return p.firstname1 + " " +
                     p.firstname2 + " " +
                     p.lastname1 + " " +
                     p.lastname2;
            }
    }
}

Global.asax:

protected void Application_Start()
{   ...
    ModelBinders.Binders.Add(typeof(List<WorkerRequest>), new workerRequestBinder());
    ...
}

ОБНОВЛЕНИЕ Я использую список выбора и планирую сделать что-нибудь на JavaScript, чтобы автоматически выбирать все опции. Мне нужен браузер для построения списка целочисленных ключей (что я и делаю с другими объектами js), и я планирую передать частично заполненные объекты workerRequest на уровень Service для синхронизации списков. HTML создание списка:

<select id="workerRequests" multiple="multiple" name="workerRequests" tabindex="12" class="valid">
    <option value="32">Van</option>
    <option value="29">Worker buses</option>
    <option value="30">Worker drives</option>
    <option value="31">Employer Picks up</option>
    <option value="86">Worker walks</option>
</select>

Вот действие Controller:

    public ActionResult Edit(int id, 
                             FormCollection collection, 
                             string userName, 
                             List<WorkerRequest> workerRequests)
    {
        //At this point, workerRequests is populated.
        WorkOrder workOrder = workOrderService.GetWorkOrder(id);
        TryUpdateModel(workOrder);
        //Update model is failing
        if (ModelState.IsValid)  //Found the exception in here
        {
            workOrderService.SaveWorkOrder(workOrder, userName);
            return RedirectToAction("Index", new { EmployerID = workOrder.EmployerID });
        }
        else
        {
            levent.Level = LogLevel.Error; levent.Message = "TryUpdateModel failed";
            levent.Properties["RecordID"] = workOrder.ID; log.Log(levent);
            return PartialView("Edit", workOrder);
        }
    }

Пользовательская модель Binder:

public class workerRequestBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {

        // see if there is an existing model to update and create one if not
        List<WorkerRequest> model = (List<WorkerRequest>)bindingContext.Model ?? new List<WorkerRequest>();
        // find out if the value provider has the required prefix
        bool hasPrefix = bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName);
        string searchPrefix = (hasPrefix) ? bindingContext.ModelName + "." : "";
        // Get the raw attempted value from the value provider
        ValueProviderResult vpr = bindingContext.ValueProvider.GetValue("workerRequests");
        var incomingData = vpr.AttemptedValue;
        if (incomingData != null)
        {

            model = incomingData.Split(new char[1] { ',' }).Select(data => new WorkerRequest
            {
                //workerRequested = workerService.GetWorkerByNum(int.Parse(data)),
                WorkerID = int.Parse(data)
            }).ToList();
        }
        bindingContext.ModelState.SetModelValue(bindingContext.ModelName, vpr);
        return model;
    }
}

Вопросы:

[10000 футов] Что я делаю не так? Что я неправильно использую в парадигме MVC?

[1000 футов] Как я могу проанализировать, что UpdateModel делает, чтобы выяснить здесь?

[100 футов] Чего не хватает, чтобы UpdateModel использовал мое пользовательское связующее?

...