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); }
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); }
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); }
/// <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); }
/// <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()); }
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(); } }
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()(); }
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); }
/// <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); } } }
/// <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); }
/// <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; }