private bool ApplyEdit(IObjectFacade nakedObject, ObjectAndControlData controlData, IAssociationFacade parent = null) {
            var oid = Facade.OidTranslator.GetOidTranslation(nakedObject);

            var usableAndVisibleFields = nakedObject.Specification.Properties.Where(p => p.IsVisible(nakedObject) && p.IsUsable(nakedObject).IsAllowed);
            var fieldsAndMatchingValues = GetFieldsAndMatchingValues(nakedObject, parent, usableAndVisibleFields, controlData, GetFieldInputId).ToList();

            CheckConcurrency(nakedObject, null, controlData, GetConcurrencyFieldInputId);

            fieldsAndMatchingValues.ForEach(pair => AddAttemptedValue(GetFieldInputId(parent, nakedObject, pair.Item1), pair.Item2));

            var ac = new ArgumentsContextFacade {
                Values = fieldsAndMatchingValues.ToDictionary(f => f.Item1.Id, f => GetObjectValue(f.Item1, nakedObject, f.Item2)),
                ValidateOnly = false
            };

            // check mandatory fields first to emulate WPF UI behaviour where no validation takes place until 
            // all mandatory fields are set. 
            foreach (var pair in fieldsAndMatchingValues) {
                var result = pair.Item2;
                var stringResult = result as string;

                if (pair.Item1.IsMandatory && (result == null || (result is string && string.IsNullOrEmpty(stringResult)))) {
                    AddErrorAndAttemptedValue(nakedObject, stringResult, pair.Item1, MvcUi.Mandatory);
                }
            }

            if (!ModelState.IsValid) {
                return false;
            }

            ApplyInlineEdit(nakedObject, controlData, usableAndVisibleFields);

            if (!ModelState.IsValid) {
                return false;
            }

            var res = Facade.PutObject(oid, ac);

            if (HasError(res)) {
                foreach (var parm in res.VisibleProperties) {
                    if (!string.IsNullOrEmpty(parm.Reason)) {
                        ModelState.AddModelError(GetFieldInputId(parent, nakedObject, parm.Property), parm.Reason);
                    }
                }

                if (!(string.IsNullOrEmpty(res.Reason))) {
                    ModelState.AddModelError("", res.Reason);
                }

                return false;
            }

            return true;
        }
        internal ArgumentsContextFacade Convert(FormCollection form, bool validateOnly = false) {
            var ac = new ArgumentsContextFacade {
                ValidateOnly = validateOnly,
                Values = form.AllKeys.ToDictionary(k => k, k => form.GetValue(k).RawValue)
            };

            return ac;
        }
        private ActionResult ExecuteAction(ObjectAndControlData controlData, IObjectFacade nakedObject, IActionFacade action) {
            if (ActionExecutingAsContributed(action, nakedObject) && action.ParameterCount == 1) {
                // contributed action being invoked with a single parm that is the current target
                // no dialog - go straight through 

                var ac = new ArgumentsContextFacade {Values = new Dictionary<string, object>(), ValidateOnly = false};

                if (nakedObject.Specification.IsCollection && !nakedObject.Specification.IsParseable) {
                    var oids = nakedObject.ToEnumerable().Select(no => Facade.OidTranslator.GetOidTranslation(no)).ToArray();
                    var spec = nakedObject.ElementSpecification;

                    var ar = Facade.ExecuteListAction(oids, spec, action.Id, ac);
                    return AppropriateView(controlData, GetResult(ar), action);
                }
                else {
                    var oid = Facade.OidTranslator.GetOidTranslation(nakedObject);
                    var ar = Facade.ExecuteObjectAction(oid, action.Id, ac);

                    return AppropriateView(controlData, GetResult(ar), action);
                }
            }

            if (!action.Parameters.Any()) {
                var ac = new ArgumentsContextFacade {Values = new Dictionary<string, object>(), ValidateOnly = false};
                var oid = Facade.OidTranslator.GetOidTranslation(nakedObject);
                var result = Facade.ExecuteObjectAction(oid, action.Id, ac);

                return AppropriateView(controlData, GetResult(result), action);
            }

            SetDefaults(nakedObject, action);
            // do after any parameters set by contributed action so this takes priority
            SetSelectedParameters(action);
            SetPagingValues(controlData, nakedObject);
            var property = DisplaySingleProperty(controlData, controlData.DataDict);

            return View(property == null ? "ActionDialog" : "PropertyEdit", new FindViewModel {ContextObject = nakedObject.GetDomainObject(), ContextAction = action, PropertyName = property});
        }
        internal ArgumentsContextFacade ConvertForSave(IObjectFacade nakedObject, ObjectAndControlData controlData, bool validateOnly = false) {
            List<IAssociationFacade> usableAndVisibleFields;
            List<Tuple<IAssociationFacade, object>> fieldsAndMatchingValues;
            GetUsableAndVisibleFields(nakedObject, controlData, null, out usableAndVisibleFields, out fieldsAndMatchingValues);

            var ac = new ArgumentsContextFacade {
                ValidateOnly = validateOnly,
                Values = fieldsAndMatchingValues.ToDictionary(t => t.Item1.Id, f => GetObjectValue(f.Item1, nakedObject, f.Item2))
            };

            return ac;
        }