This project is read-only.

TryUpdateModel not available on button postback

Topics: Writing modules
Oct 15, 2014 at 2:18 PM
I'm writing a ContentPartDriver in a custom module. My part is used on a custom form. The editor template has multiple fields that can be filled out, and it also has a button that allows for adding additional field blocks.

My problem is when I click on the button to add additional fields, the post back to the driver calls the Editor(AccidentPart part, dynamic shapeHelper) method and not the method with the IUpdateModel parameter.

What I would like to do is be able to call TryUpdateModel on the button post back so that the user does not lose all of the unsaved data when I display the data back to them. I can see of all of the form data in HttpRequestBase retrieved from IHttpContextAccessor.Current, but I would like the ability to merge that form data to my viewmodel.

Is their a way to get at the Controller or IUpdateModel from the button post back? Or is their a way to recreate the TryUpdateModel functionality in the Driver?
Oct 15, 2014 at 6:15 PM
I created a work around, but it is quite a hack, so if someone has a better solution I would appreciate it. My workaround is to create an AdminController and perform the TryUpdateModel code in the Driver. This workaround is working for both the Admin backside and the Custom Form module usage in the font-end even though they use different controllers. My function looks like this:
private void TryUpdateModel(EditAccidentViewModel model, string prefix, string[] includeProperties, string[] excludeProperties)
    if (model == null)
        throw new ArgumentNullException("model");
    var httpContext = _httpContextAccessor.Current();
    var controller = new Orchard.Core.Contents.Controllers.AdminController(
    var requestContext = httpContext.Handler as IHasRequestContext;
    var controllerContext = new System.Web.Mvc.ControllerContext(requestContext.RequestContext, controller);
    System.Web.Mvc.IValueProvider valueProvider = System.Web.Mvc.ValueProviderFactories.Factories.GetValueProvider(controllerContext);

    Predicate<string> propertyFilter = propertyName => AccidentPartDriver.IsPropertyAllowed(propertyName, includeProperties, excludeProperties);
    System.Web.Mvc.IModelBinder binder = System.Web.Mvc.ModelBinders.Binders.GetBinder(typeof(EditAccidentViewModel));

    System.Web.Mvc.ModelBindingContext bindingContext = new System.Web.Mvc.ModelBindingContext()
        ModelMetadata = System.Web.Mvc.ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(EditAccidentViewModel)),
        ModelName = prefix,
        ModelState = new System.Web.Mvc.ModelStateDictionary(),
        PropertyFilter = propertyFilter,
        ValueProvider = valueProvider
    binder.BindModel(controllerContext, bindingContext);           
Mar 7, 2015 at 4:22 AM
(At least this one is only a few months old now...)

If I understand correctly - you have a view which has a potentially repeating section. As in, maybe you have a table with one row of n input fields, and you have a button that allows the user to add an additional row with the same input fields... Is this correct?

If it is, I would suggest that you just dynamically create the field block on client side. That way when you post back all the fields will be sent at the same time and you do not need to worry about getting update model back