Beispiel #1
0
        /// <summary>
        /// Populates the view model from the data received from the request.
        /// </summary>
        /// <returns></returns>
        public void PopulateViewModel(DotvvmRequestContext context, string serializedPostData)
        {
            // get properties
            var data           = context.ReceivedViewModelJson = JObject.Parse(serializedPostData);
            var viewModelToken = (JObject)data["viewModel"];

            // load CSRF token
            context.CsrfToken = viewModelToken["$csrfToken"].Value <string>();

            ViewModelJsonConverter viewModelConverter;

            if (viewModelToken["$encryptedValues"] != null)
            {
                // load encrypted values
                var encryptedValuesString = viewModelToken["$encryptedValues"].Value <string>();
                viewModelConverter = new ViewModelJsonConverter(context.IsPostBack, JObject.Parse(viewModelProtector.Unprotect(encryptedValuesString, context)));
            }
            else
            {
                viewModelConverter = new ViewModelJsonConverter(context.IsPostBack);
            }

            // get validation path
            context.ModelState.ValidationTargetPath = data["validationTargetPath"].Value <string>();

            // populate the ViewModel
            var serializer = CreateJsonSerializer();

            serializer.Converters.Add(viewModelConverter);
            viewModelConverter.Populate(viewModelToken, serializer, context.ViewModel);
        }
Beispiel #2
0
        /// <summary>
        /// Builds the view model.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <exception cref="Exception"></exception>
        public virtual void BuildViewModel(ViewModelState state)
        {
            var jsonSerializer     = CreateJsonSerializer();
            var viewModelConverter = new ViewModelJsonConverter(true, Mapper)
            {
                UsedSerializationMaps = new HashSet <ViewModelSerializationMap>()
            };

            jsonSerializer.Converters.Add(viewModelConverter);
            var writer = new JTokenWriter();

            try
            {
                jsonSerializer.Serialize(writer, state.LastSentViewModel);
            }
            catch (Exception ex)
            {
                throw new Exception(
                          $"Could not serialize viewModel of type {state.LastSentViewModel.GetType().Name}. Serialization failed at property {writer.Path}.",
                          ex);
            }

            writer.Token["$csrfToken"] = state.CsrfToken;


            var result = new JObject();

            result["viewModel"]        = writer.Token;
            result["action"]           = WebSocketRequestType.SuccessfulCommand;
            state.ChangedViewModelJson = result;
        }
Beispiel #3
0
        protected override void DefaultVisit(JsNode node)
        {
            base.DefaultVisit(node);

            if (node.Annotation <VMPropertyInfoAnnotation>() is VMPropertyInfoAnnotation propAnnotation)
            {
                var target = node.GetChildByRole(JsTreeRoles.TargetExpression);
                if (target.HasAnnotation <ObservableUnwrapInvocationAnnotation>())
                {
                    target = target.GetChildByRole(JsTreeRoles.TargetExpression);
                }
                else if (target.HasAnnotation <ObservableSetterInvocationAnnotation>())
                {
                    throw new NotImplementedException();
                }

                var propertyType        = propAnnotation.MemberInfo.GetResultType();
                var containsObservables = true;
                if (propAnnotation.SerializationMap == null && target?.Annotation <ViewModelInfoAnnotation>() is ViewModelInfoAnnotation targetAnnotation)
                {
                    propAnnotation.SerializationMap = targetAnnotation.SerializationMap.Properties.FirstOrDefault(p => p.PropertyInfo == propAnnotation.MemberInfo);
                    containsObservables             = targetAnnotation.ContainsObservables;
                }
                if (propAnnotation.SerializationMap is ViewModelPropertyMap propertyMap)
                {
                    if (propertyMap.ViewModelProtection == ViewModel.ProtectMode.EncryptData)
                    {
                        throw new Exception($"Property {propAnnotation.MemberInfo.Name} is encrypted and cannot be used in JS.");
                    }
                    if (node is JsMemberAccessExpression memberAccess && propertyMap.Name != memberAccess.MemberName)
                    {
                        memberAccess.MemberName = propertyMap.Name;
                    }
                }
                else if (propAnnotation.MemberInfo is FieldInfo)
                {
                    throw new NotSupportedException($"Can not translate field '{propAnnotation.MemberInfo}' to Javascript");
                }

                if (containsObservables)
                {
                    node.AddAnnotation(ResultIsObservableAnnotation.Instance);

                    if (ViewModelJsonConverter.IsCollection(propertyType))
                    {
                        node.AddAnnotation(ResultIsObservableArrayAnnotation.Instance);
                    }
                }

                node.AddAnnotation(new ViewModelInfoAnnotation(propertyType, containsObservables: containsObservables));
                node.AddAnnotation(MayBeNullAnnotation.Instance);
            }

            if (node.Annotation <ViewModelInfoAnnotation>() is var vmAnnotation && vmAnnotation?.Type != null && vmAnnotation.SerializationMap == null)
            {
                vmAnnotation.SerializationMap = mapper.GetMap(vmAnnotation.Type);
            }
        }
Beispiel #4
0
 private string SetProperty(string target, PropertyInfo property, string value)
 {
     if (ViewModelJsonConverter.IsPrimitiveType(property.PropertyType))
     {
         return(target + "." + property.Name + "(" + value + ")");
     }
     else
     {
         return($"dotvvm.serialization.deserialize({ value }, { target }.{ property.Name })");
     }
 }
Beispiel #5
0
        /// <summary>
        /// Builds the view model for the client.
        /// </summary>
        public void BuildViewModel(DotvvmRequestContext context)
        {
            // serialize the ViewModel
            var serializer         = CreateJsonSerializer();
            var viewModelConverter = new ViewModelJsonConverter(context.IsPostBack)
            {
                UsedSerializationMaps = new HashSet <ViewModelSerializationMap>()
            };

            serializer.Converters.Add(viewModelConverter);
            var writer = new JTokenWriter();

            serializer.Serialize(writer, context.ViewModel);

            // persist CSRF token
            writer.Token["$csrfToken"] = context.CsrfToken;

            // persist encrypted values
            if (viewModelConverter.EncryptedValues.Count > 0)
            {
                writer.Token["$encryptedValues"] = viewModelProtector.Protect(viewModelConverter.EncryptedValues.ToString(Formatting.None), context);
            }

            // serialize validation rules
            var validationRules = SerializeValidationRules(viewModelConverter);

            // create result object
            var result = new JObject();

            result["viewModel"]        = writer.Token;
            result["url"]              = context.OwinContext.Request.Uri.PathAndQuery;
            result["virtualDirectory"] = DotvvmMiddleware.GetVirtualDirectory(context.OwinContext);
            if (context.IsPostBack || context.IsSpaRequest)
            {
                result["action"] = "successfulCommand";
                var renderedResources = new HashSet <string>(context.ReceivedViewModelJson?["renderedResources"]?.Values <string>() ?? new string[] { });
                result["resources"] = BuildResourcesJson(context, rn => !renderedResources.Contains(rn));
            }
            else
            {
                result["renderedResources"] = JArray.FromObject(context.ResourceManager.RequiredResources);
            }
            // TODO: do not send on postbacks
            if (validationRules.Count > 0)
            {
                result["validationRules"] = validationRules;
            }

            context.ViewModelJson = result;
        }
Beispiel #6
0
        /// <summary>
        /// Serializes the validation rules.
        /// </summary>
        private JObject SerializeValidationRules(ViewModelJsonConverter viewModelConverter)
        {
            var validationRules = new JObject();

            foreach (var map in viewModelConverter.UsedSerializationMaps)
            {
                var rule = new JObject();
                foreach (var property in map.Properties.Where(p => p.ClientValidationRules.Any()))
                {
                    rule[property.Name] = JToken.FromObject(property.ClientValidationRules);
                }
                if (rule.Count > 0)
                {
                    validationRules[map.Type.ToString()] = rule;
                }
            }
            return(validationRules);
        }
        /// <summary>
        /// Builds the view model for the client.
        /// </summary>
        public void BuildViewModel(DotvvmRequestContext context, DotvvmView view)
        {
            // serialize the ViewModel
            var serializer = CreateJsonSerializer();
            var viewModelConverter = new ViewModelJsonConverter()
            {
                EncryptedValues = new JArray(),
                UsedSerializationMaps = new HashSet<ViewModelSerializationMap>()
            };
            serializer.Converters.Add(viewModelConverter);
            var writer = new JTokenWriter();
            serializer.Serialize(writer, context.ViewModel);

            // persist CSRF token
            writer.Token["$csrfToken"] = context.CsrfToken;

            // persist encrypted values
            if (viewModelConverter.EncryptedValues.Count > 0)
                writer.Token["$encryptedValues"] = viewModelProtector.Protect(viewModelConverter.EncryptedValues.ToString(Formatting.None), context);

            // serialize validation rules
            var validationRules = SerializeValidationRules(viewModelConverter);

            // create result object
            var result = new JObject();
            result["viewModel"] = writer.Token;
            result["url"] = context.OwinContext.Request.Uri.PathAndQuery;
            result["virtualDirectory"] = DotvvmMiddleware.GetVirtualDirectory(context.OwinContext);
            if (context.IsPostBack || context.IsSpaRequest)
            {
                result["action"] = "successfulCommand";
                var renderedResources = new HashSet<string>(context.ReceivedViewModelJson?["renderedResources"]?.Values<string>() ?? new string[] { });
                result["resources"] = BuildResourcesJson(context, rn => !renderedResources.Contains(rn));
            }
            else
            {
                result["renderedResources"] = JArray.FromObject(context.ResourceManager.RequiredResources);
            }
            // TODO: do not send on postbacks
            if (validationRules.Count > 0) result["validationRules"] = validationRules;

            context.ViewModelJson = result;
        }
 public static bool IsComplexType(this JsExpression expr)
 {
     if (expr.TryGetAnnotation <ViewModelInfoAnnotation>(out var vmInfo))
     {
         return(ViewModelJsonConverter.IsComplexType(vmInfo.Type));
     }
     if (expr is JsAssignmentExpression assignment && assignment.Operator == null)
     {
         return(IsComplexType(assignment.Right));
     }
     if (expr is JsBinaryExpression binary && (binary.Operator == BinaryOperatorType.ConditionalAnd || binary.Operator == BinaryOperatorType.ConditionalOr))
     {
         return(IsComplexType(binary.Left) && IsComplexType(binary.Right));
     }
     if (expr is JsConditionalExpression conditional)
     {
         return(IsComplexType(conditional.TrueExpression) && IsComplexType(conditional.FalseExpression));
     }
     if (expr is JsLiteral literal)
     {
         return(literal.Value != null && ViewModelJsonConverter.IsComplexType(literal.Value.GetType()));
     }
     return(false);
 }
Beispiel #9
0
        /// <summary>
        /// Populates the view model from Json sent.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="serializedPostData">The serialized post data.</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public virtual string PopulateViewModel(ViewModelState state, string serializedPostData)
        {
            var data           = state.LastSentViewModelJson = JObject.Parse(serializedPostData);
            var viewModelToken = (JObject)data["viewModel"];

            state.CsrfToken = viewModelToken["$csrfToken"].Value <string>();

            var viewModelConverter = new ViewModelJsonConverter(true, Mapper);

            var serializer = CreateJsonSerializer();

            serializer.Converters.Add(viewModelConverter);
            try
            {
                viewModelConverter.Populate(viewModelToken.CreateReader(), serializer, state.LastSentViewModel);
            }
            catch (Exception ex)
            {
                throw new Exception(
                          $"Could not deserialize viewModel of type {state.LastSentViewModel.GetType().Name}. {GeneralViewModelRecommendations}",
                          ex);
            }
            return((string)data["taskId"]);
        }
        /// <summary>
        /// Populates the view model from the data received from the request.
        /// </summary>
        /// <returns></returns>
        public void PopulateViewModel(DotvvmRequestContext context, DotvvmView view, string serializedPostData)
        {
            var viewModelConverter = new ViewModelJsonConverter();

            // get properties
            var data = context.ReceivedViewModelJson = JObject.Parse(serializedPostData);
            var viewModelToken = (JObject)data["viewModel"];

            // load CSRF token
            context.CsrfToken = viewModelToken["$csrfToken"].Value<string>();

            if (viewModelToken["$encryptedValues"] != null)
            {
                // load encrypted values
                var encryptedValuesString = viewModelToken["$encryptedValues"].Value<string>();
                viewModelConverter.EncryptedValues = JArray.Parse(viewModelProtector.Unprotect(encryptedValuesString, context));
            }
            else viewModelConverter.EncryptedValues = new JArray();

            // get validation path
            context.ModelState.ValidationTargetPath = data["validationTargetPath"].Value<string>();

            // populate the ViewModel
            var serializer = CreateJsonSerializer();
            serializer.Converters.Add(viewModelConverter);
            viewModelConverter.Populate(viewModelToken, serializer, context.ViewModel);
        }
 /// <summary>
 /// Serializes the validation rules.
 /// </summary>
 private JObject SerializeValidationRules(ViewModelJsonConverter viewModelConverter)
 {
     var validationRules = new JObject();
     foreach (var map in viewModelConverter.UsedSerializationMaps)
     {
         var rule = new JObject();
         foreach (var property in map.Properties.Where(p => p.ClientValidationRules.Any()))
         {
             rule[property.Name] = JToken.FromObject(property.ClientValidationRules);
         }
         if (rule.Count > 0) validationRules[map.Type.ToString()] = rule;
     }
     return validationRules;
 }
Beispiel #12
0
        /// <summary>
        /// Validates the view model.
        /// </summary>
        private IEnumerable <ViewModelValidationError> ValidateViewModel(object viewModel, string pathPrefix, HashSet <object> alreadyValidated)
        {
            if (alreadyValidated.Contains(viewModel))
            {
                yield break;
            }

            if (viewModel == null)
            {
                yield break;
            }
            var viewModelType = viewModel.GetType();

            if (ViewModelJsonConverter.IsPrimitiveType(viewModelType) || ViewModelJsonConverter.IsNullableType(viewModelType))
            {
                yield break;
            }

            alreadyValidated.Add(viewModel);

            if (ViewModelJsonConverter.IsEnumerable(viewModelType))
            {
                if (pathPrefix.Length == 0)
                {
                    pathPrefix = "$data";
                }
                else
                {
                    pathPrefix += "()";
                }

                // collections
                var index = 0;
                foreach (var item in (IEnumerable)viewModel)
                {
                    foreach (var error in ValidateViewModel(item, pathPrefix + "[" + index + "]()", alreadyValidated))
                    {
                        yield return(error);
                    }
                    index++;
                }
                yield break;
            }

            // validate all properties on the object
            var map = viewModelSerializationMapper.GetMap(viewModel.GetType());

            foreach (var property in map.Properties.Where(p => p.TransferToServer))
            {
                var value = property.PropertyInfo.GetValue(viewModel);
                var path  = CombinePath(pathPrefix, property.Name);

                // validate the property
                if (property.ValidationRules.Any())
                {
                    var context = new ValidationContext(viewModel, validationItems)
                    {
                        MemberName = property.Name
                    };

                    foreach (var rule in property.ValidationRules)
                    {
                        var propertyResult = rule.SourceValidationAttribute?.GetValidationResult(value, context);
                        if (propertyResult != ValidationResult.Success)
                        {
                            yield return(new ViewModelValidationError()
                            {
                                PropertyPath = path,
                                ErrorMessage = rule.ErrorMessage
                            });
                        }
                    }
                }

                // inspect objects
                if (value != null)
                {
                    if (ViewModelJsonConverter.IsComplexType(property.Type))
                    {
                        // complex objects
                        foreach (var error in ValidateViewModel(value, path, alreadyValidated))
                        {
                            yield return(error);
                        }
                    }
                }
            }

            if (viewModel is IValidatableObject)
            {
                foreach (var error in ((IValidatableObject)viewModel).Validate(
                             new ValidationContext(viewModel, validationItems)))
                {
                    var paths = new List <string>();
                    if (error.MemberNames != null)
                    {
                        foreach (var memberName in error.MemberNames)
                        {
                            paths.Add(CombinePath(pathPrefix, memberName));
                        }
                    }
                    if (!paths.Any())
                    {
                        paths.Add(pathPrefix);
                    }

                    foreach (var memberPath in paths)
                    {
                        yield return(new ViewModelValidationError()
                        {
                            PropertyPath = memberPath,
                            ErrorMessage = error.ErrorMessage
                        });
                    }
                }
            }
        }