public void ExpressionEvaluator_UpdateSource_Simple()
        {
            var viewModel = new TestViewModel() { SubObject = new TestViewModel2() { Value = "hello" } };
            var view = new RedwoodView()
            {
                DataContext = viewModel,
                Children =
                {
                    new HtmlGenericControl("html")
                    {
                        Children =
                        {
                            new TextBox()
                            {
                                ID = "txb"
                            }
                            .WithBinding(TextBox.TextProperty, new ValueBindingExpression("Value"))
                        }
                    }
                    .WithBinding(RedwoodBindableControl.DataContextProperty, new ValueBindingExpression("SubObject"))
                }
            };
            var textbox = view.FindControl("txb") as TextBox;
            var binding = textbox.GetBinding(TextBox.TextProperty) as ValueBindingExpression;

            binding.UpdateSource("test", textbox, TextBox.TextProperty);

            Assert.AreEqual("test", viewModel.SubObject.Value);
        }
예제 #2
0
        public void CommandResolver_Valid_SimpleTest()
        {
            var path = new[] { "A[0]" };
            var command = "Test(StringToPass, _parent.NumberToPass)";

            var testObject = new
            {
                A = new[]
                {
                    new TestA() { StringToPass = "******" }
                },
                NumberToPass = 16
            };
            var viewRoot = new RedwoodView() { DataContext = testObject };
            viewRoot.SetBinding(Validate.TargetProperty, new ValueBindingExpression("_root"));

            var placeholder = new HtmlGenericControl("div");
            placeholder.SetBinding(RedwoodBindableControl.DataContextProperty, new ValueBindingExpression(path[0]));
            viewRoot.Children.Add(placeholder);

            var button = new Button();
            button.SetBinding(ButtonBase.ClickProperty, new CommandBindingExpression(command));
            placeholder.Children.Add(button);

            var resolver = new CommandResolver();
            var context = new RedwoodRequestContext() { ViewModel = testObject };
            context.ModelState.ValidationTargetPath = KnockoutHelper.GetValidationTargetExpression(button, true);

            resolver.GetFunction(viewRoot, context, path, command).GetAction()();

            Assert.AreEqual(testObject.NumberToPass, testObject.A[0].ResultInt);
            Assert.AreEqual(testObject.A[0].ResultString, testObject.A[0].ResultString);
        }
        public void ExpressionEvaluator_Complex_EvaluateInRootDataContext()
        {
            var view = new RedwoodView()
            {
                DataContext = new TestViewModel() { SubObject = new TestViewModel2() { Value = "hello" } },
                Children =
                {
                    new HtmlGenericControl("html")
                    {
                        Children =
                        {
                            new TextBox()
                            {
                                ID = "txb"
                            }
                        }
                    }
                    .WithBinding(RedwoodBindableControl.DataContextProperty, new ValueBindingExpression("SubObject"))
                }
            };
            var textbox = view.FindControl("txb") as TextBox;

            var evaluator = new ExpressionEvaluator();
            var result = evaluator.Evaluate(new ValueBindingExpression("Value"), RedwoodBindableControl.DataContextProperty, textbox);

            Assert.IsInstanceOfType(result, typeof(string));
            Assert.AreEqual("hello", result);
        }
예제 #4
0
 public async Task WriteViewModelResponse(RedwoodRequestContext context, RedwoodView view)
 {
     // return the response
     context.OwinContext.Response.ContentType = "application/json; charset=utf-8";
     var serializedViewModel = context.GetSerializedViewModel();
     await context.OwinContext.Response.WriteAsync(serializedViewModel);
 }
예제 #5
0
        /// <summary>
        /// Initializes the view model for the specified view.
        /// </summary>
        public object InitializeViewModel(RedwoodRequestContext context, RedwoodView view)
        {
            string viewModel;
            if (!view.Directives.TryGetValue(Constants.ViewModelDirectiveName, out viewModel))
            {
                throw new Exception("Couldn't find a viewmodel for the specified view!");       // TODO: exception handling
            }

            var viewModelType = Type.GetType(viewModel);
            if (viewModelType == null)
            {
                throw new Exception(string.Format("Couldn't create a class of type '{0}'!", viewModel));       // TODO: exception handling
            }
            return CreateViewModelInstance(viewModelType);
        }
예제 #6
0
        /// <summary>
        /// Embeds the resource links in the page.
        /// </summary>
        private void EmbedResourceLinks(RedwoodView view)
        {
            var sections = view.GetThisAndAllDescendants()
                .OfType<HtmlGenericControl>()
                .Where(t => t.TagName == "head" || t.TagName == "body")
                .OrderBy(t => t.TagName)
                .ToList();

            if (sections.Count != 2 || sections[0].TagName == sections[1].TagName)
            {
                throw new Exception("The page must have exactly one <head> and one <body> section!");
            }

            sections[0].Children.Add(new BodyResourceLinks());
            sections[1].Children.Add(new HeadResourceLinks());
        }
예제 #7
0
        public void RenderPage(RedwoodRequestContext context, RedwoodView view)
        {
            // embed resource links
            EmbedResourceLinks(view);

            // prepare the render context
            var renderContext = new RenderContext(context);

            // get the HTML
            using (var textWriter = new StringWriter())
            {
                var htmlWriter = new HtmlWriter(textWriter, context);
                view.Render(htmlWriter, renderContext);
                context.RenderedHtml = textWriter.ToString();
            }
        }
예제 #8
0
        public void CommandResolver_CannotCallSetter()
        {
            var testObject = new TestA()
            {
                StringToPass = "******"
            };
            var viewRoot = new RedwoodView() { DataContext = testObject };
            viewRoot.SetBinding(Validate.TargetProperty, new ValueBindingExpression("_root"));
            viewRoot.SetBinding(RedwoodProperty.Register<Action, RedwoodView>("Test"), new CommandBindingExpression("set_StringToPass(StringToPass)"));

            var path = new string[] { };
            var command = "set_StringToPass(StringToPass)";

            var resolver = new CommandResolver();
            var context = new RedwoodRequestContext() { ViewModel = testObject };
            resolver.GetFunction(viewRoot, context, path, command).GetAction()();
        }
예제 #9
0
        public void NamingContainers_EnsureControlHasID_GenerateUniqueID()
        {
            var page = new RedwoodView();
            page.SetValue(Internal.UniqueIDProperty, "c0");

            var head = new HtmlGenericControl("head");
            head.SetValue(Internal.UniqueIDProperty, "c1");
            page.Children.Add(head);

            var title = new HtmlGenericControl("title");
            title.SetValue(Internal.UniqueIDProperty, "c2");
            head.Children.Add(title);

            var body = new HtmlGenericControl("body");
            body.SetValue(Internal.UniqueIDProperty, "c3");
            page.Children.Add(body);

            var div1 = new HtmlGenericControl("div");
            div1.SetValue(Internal.UniqueIDProperty, "c4");
            body.Children.Add(div1);

            var div2 = new HtmlGenericControl("div");
            div2.SetValue(Internal.UniqueIDProperty, "c5");
            div2.SetValue(Internal.IsNamingContainerProperty, true);
            body.Children.Add(div2);

            var div3 = new HtmlGenericControl("div");
            div3.SetValue(Internal.UniqueIDProperty, "c6");
            div2.Children.Add(div3);

            div3.EnsureControlHasId(true);
            div1.EnsureControlHasId(true);

            Assert.AreEqual("c4", div1.ID);
            Assert.AreEqual("c5_c6", div3.ID);
        }
예제 #10
0
        /// <summary>
        /// Resolves the command for the specified post data.
        /// </summary>
        public void ResolveCommand(RedwoodRequestContext context, RedwoodView view, string serializedPostData, out ActionInfo actionInfo)
        {
            // get properties
            var data = JObject.Parse(serializedPostData);
            var path = data["currentPath"].Values<string>().ToArray();
            var command = data["command"].Value<string>();
            var controlUniqueId = data["controlUniqueId"].Value<string>();

            if (string.IsNullOrEmpty(command))
            {
                // empty command
                actionInfo = null;
            }
            else
            {
                // find the command target
                if (!string.IsNullOrEmpty(controlUniqueId))
                {
                    var target = view.FindControl(controlUniqueId);
                    if (target == null)
                    {
                        throw new Exception(string.Format("The control with ID '{0}' was not found!", controlUniqueId));
                    }
                    actionInfo = commandResolver.GetFunction(target, view, context, path, command);
                }
                else
                {
                    actionInfo = commandResolver.GetFunction(view, context, path, command);
                }
            }
        }
예제 #11
0
        /// <summary>
        /// Populates the view model from the data received from the request.
        /// </summary>
        /// <returns></returns>
        public void PopulateViewModel(RedwoodRequestContext context, RedwoodView 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 = new JsonSerializer();
            serializer.Converters.Add(viewModelConverter);
            viewModelConverter.Populate(viewModelToken, serializer, context.ViewModel);

            // load the control state
            var walker = new ViewModelJTokenControlTreeWalker(viewModelToken, view);
            walker.ProcessControlTree(walker.LoadControlState);
        }
예제 #12
0
        /// <summary>
        /// Builds the view model for the client.
        /// </summary>
        public void BuildViewModel(RedwoodRequestContext context, RedwoodView view)
        {
            // serialize the ViewModel
            var serializer = new JsonSerializer();
            var viewModelConverter = new ViewModelJsonConverter()
            {
                EncryptedValues = new JArray(),
                UsedSerializationMaps = new HashSet<ViewModelSerializationMap>()
            };
            serializer.Converters.Add(viewModelConverter);
            var writer = new JTokenWriter();
            serializer.Serialize(writer, context.ViewModel);

            // save the control state
            var walker = new ViewModelJTokenControlTreeWalker(writer.Token, view);
            walker.ProcessControlTree(walker.SaveControlState);

            // 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"] = RedwoodMiddleware.GetVirtualDirectory(context.OwinContext);
            if (context.IsPostBack || context.IsSpaRequest)
            {
                result["action"] = "successfulCommand";

                result["resources"] = BuildResourcesJson(context, _ => true);
            }
            else
            {
                result["renderedResources"] = JArray.FromObject(context.ResourceManager.RequiredResources);
            }
            // TODO: do not send on postbacks
            if (validationRules.Count > 0) result["validationRules"] = validationRules;

            context.ViewModelJson = result;
        }