diff --git a/src/Redwood.Framework/Controls/DelegateTemplate.cs b/src/Redwood.Framework/Controls/DelegateTemplate.cs index 722a7f69e7..ba224ca531 100644 --- a/src/Redwood.Framework/Controls/DelegateTemplate.cs +++ b/src/Redwood.Framework/Controls/DelegateTemplate.cs @@ -1,3 +1,5 @@ +using Redwood.Framework.Hosting; +using Redwood.Framework.Runtime; using System; using System.Collections.Generic; using System.Linq; @@ -7,12 +9,13 @@ namespace Redwood.Framework.Controls public class DelegateTemplate : ITemplate { - public Func BuildContentBody { get; set; } + public Func BuildContentBody { get; set; } - public void BuildContent(RedwoodControl container) + public void BuildContent(RedwoodRequestContext context, RedwoodControl container) { - var control = BuildContentBody(); + var controlBuilderFactory = context.Configuration.ServiceLocator.GetService(); + var control = BuildContentBody(controlBuilderFactory); container.Children.Add(control); } } diff --git a/src/Redwood.Framework/Controls/GridView.cs b/src/Redwood.Framework/Controls/GridView.cs index 4862856bdc..21249f86cd 100644 --- a/src/Redwood.Framework/Controls/GridView.cs +++ b/src/Redwood.Framework/Controls/GridView.cs @@ -51,18 +51,18 @@ public Action SortChanged protected internal override void OnLoad(RedwoodRequestContext context) { - DataBind(); + DataBind(context); base.OnLoad(context); } protected internal override void OnPreRender(RedwoodRequestContext context) { - DataBind(); // TODO: support for observable collection + DataBind(context); // TODO: support for observable collection base.OnPreRender(context); } - private void DataBind() + private void DataBind(RedwoodRequestContext context) { Children.Clear(); @@ -88,7 +88,7 @@ private void DataBind() if (dataSource != null) { // create header row - CreateHeaderRow(sortCommandPath); + CreateHeaderRow(context, sortCommandPath); foreach (var item in GetIEnumerableFromDataSource(dataSource)) { @@ -97,14 +97,14 @@ private void DataBind() placeholder.SetBinding(DataContextProperty, new ValueBindingExpression(dataSourcePath + "[" + index + "]")); Children.Add(placeholder); - CreateRow(placeholder); + CreateRow(context, placeholder); index++; } } } - private void CreateHeaderRow(string sortCommandPath) + private void CreateHeaderRow(RedwoodRequestContext context, string sortCommandPath) { var headerRow = new HtmlGenericControl("tr"); Children.Add(headerRow); @@ -114,7 +114,7 @@ private void CreateHeaderRow(string sortCommandPath) SetCellAttributes(column, cell, true); headerRow.Children.Add(cell); - column.CreateHeaderControls(this, sortCommandPath, cell); + column.CreateHeaderControls(context, this, sortCommandPath, cell); } } @@ -139,7 +139,7 @@ private static void SetCellAttributes(GridViewColumn column, HtmlGenericControl } } - private void CreateRow(DataItemContainer placeholder) + private void CreateRow(RedwoodRequestContext context, DataItemContainer placeholder) { var row = new HtmlGenericControl("tr"); @@ -158,7 +158,7 @@ private void CreateRow(DataItemContainer placeholder) var cell = new HtmlGenericControl("td"); SetCellAttributes(column, cell, false); row.Children.Add(cell); - column.CreateControls(cell); + column.CreateControls(context, cell); } } @@ -197,7 +197,7 @@ protected override void RenderContents(IHtmlWriter writer, RenderContext context var placeholder = new DataItemContainer { DataContext = null }; Children.Add(placeholder); - CreateRow(placeholder); + CreateRow(context.RequestContext, placeholder); context.PathFragments.Push(dataSourceBinding.GetViewModelPathExpression(this, DataSourceProperty) + "[$index]"); placeholder.Render(writer, context); diff --git a/src/Redwood.Framework/Controls/GridViewColumn.cs b/src/Redwood.Framework/Controls/GridViewColumn.cs index c66ae9c93b..1654893d7f 100644 --- a/src/Redwood.Framework/Controls/GridViewColumn.cs +++ b/src/Redwood.Framework/Controls/GridViewColumn.cs @@ -1,4 +1,5 @@ using Redwood.Framework.Binding; +using Redwood.Framework.Hosting; using System; namespace Redwood.Framework.Controls @@ -68,7 +69,7 @@ public string Width - public abstract void CreateControls(RedwoodControl container); + public abstract void CreateControls(RedwoodRequestContext context, RedwoodControl container); @@ -88,7 +89,7 @@ private void ThrowValueBindingNotSet() } - public virtual void CreateHeaderControls(GridView gridView, string sortCommandPath, HtmlGenericControl cell) + public virtual void CreateHeaderControls(RedwoodRequestContext context, GridView gridView, string sortCommandPath, HtmlGenericControl cell) { if (AllowSorting) { diff --git a/src/Redwood.Framework/Controls/GridViewTemplateColumn.cs b/src/Redwood.Framework/Controls/GridViewTemplateColumn.cs index 08cf7cd9df..3ed8c67bca 100644 --- a/src/Redwood.Framework/Controls/GridViewTemplateColumn.cs +++ b/src/Redwood.Framework/Controls/GridViewTemplateColumn.cs @@ -1,4 +1,5 @@ using Redwood.Framework.Binding; +using Redwood.Framework.Hosting; using System; using System.Collections.Generic; using System.Linq; @@ -21,9 +22,9 @@ public ITemplate ContentTemplate - public override void CreateControls(RedwoodControl container) + public override void CreateControls(RedwoodRequestContext context, RedwoodControl container) { - ContentTemplate.BuildContent(container); + ContentTemplate.BuildContent(context, container); } private ValueBindingExpression GetValueBinding() diff --git a/src/Redwood.Framework/Controls/GridViewTextColumn.cs b/src/Redwood.Framework/Controls/GridViewTextColumn.cs index 34727b5269..0f5cabbf4e 100644 --- a/src/Redwood.Framework/Controls/GridViewTextColumn.cs +++ b/src/Redwood.Framework/Controls/GridViewTextColumn.cs @@ -1,4 +1,5 @@ using Redwood.Framework.Binding; +using Redwood.Framework.Hosting; using System; using System.Collections.Generic; using System.Linq; @@ -22,7 +23,7 @@ public string FormatString - public override void CreateControls(RedwoodControl container) + public override void CreateControls(RedwoodRequestContext context, RedwoodControl container) { var literal = new Literal(); literal.FormatString = FormatString; diff --git a/src/Redwood.Framework/Controls/ITemplate.cs b/src/Redwood.Framework/Controls/ITemplate.cs index 09e99cdb2e..4e013c754c 100644 --- a/src/Redwood.Framework/Controls/ITemplate.cs +++ b/src/Redwood.Framework/Controls/ITemplate.cs @@ -1,3 +1,5 @@ +using Redwood.Framework.Hosting; + namespace Redwood.Framework.Controls { /// @@ -9,7 +11,7 @@ public interface ITemplate /// /// Builds the content of the template into the specified container. /// - void BuildContent(RedwoodControl container); + void BuildContent(RedwoodRequestContext context, RedwoodControl container); } } \ No newline at end of file diff --git a/src/Redwood.Framework/Controls/Repeater.cs b/src/Redwood.Framework/Controls/Repeater.cs index 554e67bf92..ec9142afd3 100644 --- a/src/Redwood.Framework/Controls/Repeater.cs +++ b/src/Redwood.Framework/Controls/Repeater.cs @@ -51,7 +51,7 @@ public Repeater() /// protected internal override void OnLoad(RedwoodRequestContext context) { - DataBind(); + DataBind(context); base.OnLoad(context); } @@ -60,14 +60,14 @@ protected internal override void OnLoad(RedwoodRequestContext context) /// protected internal override void OnPreRender(RedwoodRequestContext context) { - DataBind(); // TODO: we should handle observable collection operations to persist controlstate of controls inside the Repeater + DataBind(context); // TODO: we should handle observable collection operations to persist controlstate of controls inside the Repeater base.OnPreRender(context); } /// /// Performs the data-binding and builds the controls inside the . /// - private void DataBind() + private void DataBind(RedwoodRequestContext context) { Children.Clear(); @@ -83,7 +83,7 @@ private void DataBind() var placeholder = new DataItemContainer { DataItemIndex = index }; placeholder.SetBinding(DataContextProperty, new ValueBindingExpression(dataSourcePath + "[" + index + "]")); Children.Add(placeholder); - ItemTemplate.BuildContent(placeholder); + ItemTemplate.BuildContent(context, placeholder); index++; } @@ -130,7 +130,7 @@ protected override void RenderContents(IHtmlWriter writer, RenderContext context // render on client var placeholder = new DataItemContainer { DataContext = null }; Children.Add(placeholder); - ItemTemplate.BuildContent(placeholder); + ItemTemplate.BuildContent(context.RequestContext, placeholder); context.PathFragments.Push(dataSourceBinding.GetViewModelPathExpression(this, DataSourceProperty) + "[$index]"); placeholder.Render(writer, context); diff --git a/src/Redwood.Framework/Hosting/DefaultMarkupFileLoader.cs b/src/Redwood.Framework/Hosting/DefaultMarkupFileLoader.cs index 71dc9fa85d..8b1fd7cdf4 100644 --- a/src/Redwood.Framework/Hosting/DefaultMarkupFileLoader.cs +++ b/src/Redwood.Framework/Hosting/DefaultMarkupFileLoader.cs @@ -11,9 +11,9 @@ public class DefaultMarkupFileLoader : IMarkupFileLoader /// - /// Gets the markup file from the current request URL. + /// Gets the markup file virtual path from the current request URL. /// - public MarkupFile GetMarkup(RedwoodRequestContext context) + public string GetMarkupFileVirtualPath(RedwoodRequestContext context) { // get file name var fileName = context.Route != null ? context.Route.VirtualPath : context.OwinContext.Request.Uri.LocalPath; @@ -22,21 +22,16 @@ public MarkupFile GetMarkup(RedwoodRequestContext context) throw new Exception("The view must be a file with the .rwhtml extension!"); // TODO: exception handling } - return GetMarkupCore(context.Configuration, fileName); + return fileName; } /// /// Gets the markup file for the specified virtual path. /// public MarkupFile GetMarkup(RedwoodConfiguration configuration, string virtualPath) - { - return GetMarkupCore(configuration, virtualPath); - } - - private static MarkupFile GetMarkupCore(RedwoodConfiguration configuration, string fileName) { // check that we are not outside application directory - var fullPath = Path.Combine(configuration.ApplicationPhysicalPath, fileName); + var fullPath = Path.Combine(configuration.ApplicationPhysicalPath, virtualPath); fullPath = Path.GetFullPath(fullPath); if (!fullPath.StartsWith(configuration.ApplicationPhysicalPath, StringComparison.CurrentCultureIgnoreCase)) { @@ -44,7 +39,7 @@ private static MarkupFile GetMarkupCore(RedwoodConfiguration configuration, stri } // load the file - return new MarkupFile(fileName, fullPath); + return new MarkupFile(virtualPath, fullPath); } } } \ No newline at end of file diff --git a/src/Redwood.Framework/Hosting/IMarkupFileLoader.cs b/src/Redwood.Framework/Hosting/IMarkupFileLoader.cs index b3fba88eb7..d7de35d464 100644 --- a/src/Redwood.Framework/Hosting/IMarkupFileLoader.cs +++ b/src/Redwood.Framework/Hosting/IMarkupFileLoader.cs @@ -11,7 +11,7 @@ public interface IMarkupFileLoader /// /// Gets the markup file from the current request URL. /// - MarkupFile GetMarkup(RedwoodRequestContext context); + string GetMarkupFileVirtualPath(RedwoodRequestContext context); /// /// Gets the markup file for the specified virtual path. diff --git a/src/Redwood.Framework/Runtime/Compilation/DefaultViewCompiler.cs b/src/Redwood.Framework/Runtime/Compilation/DefaultViewCompiler.cs index 2c0ea9e742..3053a8532c 100644 --- a/src/Redwood.Framework/Runtime/Compilation/DefaultViewCompiler.cs +++ b/src/Redwood.Framework/Runtime/Compilation/DefaultViewCompiler.cs @@ -57,10 +57,10 @@ public IControlBuilder CompileView(IReader reader, string fileName, string assem // determine wrapper type string wrapperClassName; var wrapperType = ResolveWrapperType(node, className, out wrapperClassName); - var metadata = controlResolver.ResolveControl(wrapperType); + var metadata = controlResolver.ResolveControl(new ControlType(wrapperType, virtualPath: fileName)); // build the statements - emitter.PushNewMethod("BuildControl"); + emitter.PushNewMethod(DefaultViewCompilerCodeEmitter.BuildControlFunctionName); var pageName = wrapperClassName == null ? emitter.EmitCreateObject(wrapperType) : emitter.EmitCreateObject(wrapperClassName); emitter.EmitSetAttachedProperty(pageName, typeof(Internal).FullName, Internal.UniqueIDProperty.Name, pageName); foreach (var child in node.Content) @@ -310,7 +310,7 @@ private string ProcessTemplate(RwHtmlElementNode element) /// private string CompileTemplate(RwHtmlElementNode element) { - var methodName = "BuildTemplate" + currentTemplateIndex; + var methodName = DefaultViewCompilerCodeEmitter.BuildTemplateFunctionName + currentTemplateIndex; currentTemplateIndex++; emitter.PushNewMethod(methodName); @@ -343,8 +343,8 @@ private string ProcessObjectElement(RwHtmlElementNode element) } else { - // markup control - currentObjectName = emitter.EmitInvokeControlBuilder(controlMetadata.Type, controlMetadata.ControlBuilderType); + // markup control + currentObjectName = emitter.EmitInvokeControlBuilder(controlMetadata.Type, controlMetadata.VirtualPath); } emitter.EmitSetAttachedProperty(currentObjectName, typeof(Internal).FullName, Internal.UniqueIDProperty.Name, currentObjectName); diff --git a/src/Redwood.Framework/Runtime/Compilation/DefaultViewCompilerCodeEmitter.cs b/src/Redwood.Framework/Runtime/Compilation/DefaultViewCompilerCodeEmitter.cs index 40dedc35c4..6d83887e04 100644 --- a/src/Redwood.Framework/Runtime/Compilation/DefaultViewCompilerCodeEmitter.cs +++ b/src/Redwood.Framework/Runtime/Compilation/DefaultViewCompilerCodeEmitter.cs @@ -11,7 +11,7 @@ namespace Redwood.Framework.Runtime.Compilation { public class DefaultViewCompilerCodeEmitter { - + private int CurrentControlIndex { get { return methods.Peek().ControlIndex; } @@ -23,6 +23,12 @@ private List CurrentStatements get { return methods.Peek().Statements; } } + public const string ControlBuilderFactoryParameterName = "controlBuilderFactory"; + public const string BuildControlFunctionName = "BuildControl"; + public const string BuildTemplateFunctionName = "BuildTemplate"; + public const string GetControlBuilderFunctionName = "GetControlBuilder"; + + private Stack methods = new Stack(); private List outputMethods = new List(); public SyntaxTree SyntaxTree { get; private set; } @@ -91,10 +97,8 @@ public string EmitCreateObject(Type type, object[] constructorArguments = null) /// /// Emits the control builder invocation. /// - public string EmitInvokeControlBuilder(Type controlType, Type controlBuilderType) + public string EmitInvokeControlBuilder(Type controlType, string virtualPath) { - usedControlBuilderTypes.Add(controlBuilderType); - var builderName = "c" + CurrentControlIndex + "_builder"; var untypedName = "c" + CurrentControlIndex + "_untyped"; var name = "c" + CurrentControlIndex; @@ -105,8 +109,15 @@ public string EmitInvokeControlBuilder(Type controlType, Type controlBuilderType SyntaxFactory.VariableDeclaration(SyntaxFactory.IdentifierName("var")).WithVariables( SyntaxFactory.VariableDeclarator(builderName).WithInitializer( SyntaxFactory.EqualsValueClause( - SyntaxFactory.ObjectCreationExpression(SyntaxFactory.ParseTypeName(controlBuilderType.FullName)) - .WithArgumentList(SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList())) + SyntaxFactory.InvocationExpression( + SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.IdentifierName(ControlBuilderFactoryParameterName), + SyntaxFactory.IdentifierName(GetControlBuilderFunctionName) + ), + SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(new[] { + SyntaxFactory.Argument(EmitStringLiteral(virtualPath)) + })) + ) ) ) ) @@ -118,11 +129,14 @@ public string EmitInvokeControlBuilder(Type controlType, Type controlBuilderType SyntaxFactory.VariableDeclarator(untypedName).WithInitializer( SyntaxFactory.EqualsValueClause( SyntaxFactory.InvocationExpression( - SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, + SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(builderName), - SyntaxFactory.IdentifierName("BuildControl") - ) - ).WithArgumentList(SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList())) + SyntaxFactory.IdentifierName(BuildControlFunctionName) + ), + SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(new[] { + SyntaxFactory.Argument(SyntaxFactory.IdentifierName(ControlBuilderFactoryParameterName)) + })) + ) ) ) ) @@ -186,7 +200,7 @@ public ExpressionSyntax EmitValue(object value) private ExpressionSyntax EmitBooleanLiteral(bool value) { return SyntaxFactory.LiteralExpression(value ? SyntaxKind.TrueLiteralExpression : SyntaxKind.FalseLiteralExpression); - } + } /// /// Emits the set property statement. @@ -206,7 +220,7 @@ public void EmitSetProperty(string controlName, string propertyName, ExpressionS ) ) ); - } + } /// /// Emits the set property statement. @@ -256,7 +270,7 @@ public void EmitSetBinding(string controlName, string propertyName, string varia SyntaxFactory.IdentifierName("SetBinding") ), SyntaxFactory.ArgumentList( - SyntaxFactory.SeparatedList(new[] { + SyntaxFactory.SeparatedList(new[] { SyntaxFactory.Argument(SyntaxFactory.IdentifierName(propertyName)), SyntaxFactory.Argument(SyntaxFactory.IdentifierName(variableName)) }) @@ -281,7 +295,7 @@ public void EmitSetAttachedProperty(string controlName, string propertyType, str ), SyntaxFactory.ArgumentList( SyntaxFactory.SeparatedList( - new[] { + new[] { SyntaxFactory.Argument( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, @@ -447,13 +461,18 @@ public IEnumerable BuildTree(string namespaceName, string className) )) .WithMembers( SyntaxFactory.List( - outputMethods.Select(m => + outputMethods.Select(m => SyntaxFactory.MethodDeclaration( SyntaxFactory.ParseTypeName(typeof(RedwoodControl).FullName), - m.Name - ) - .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword))) - .WithBody(SyntaxFactory.Block(m.Statements)) + m.Name) + .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword))) + .WithParameterList(SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(new[] { + SyntaxFactory.Parameter( + SyntaxFactory.Identifier(ControlBuilderFactoryParameterName) + ) + .WithType(SyntaxFactory.ParseTypeName(typeof(IControlBuilderFactory).FullName)) + }))) + .WithBody(SyntaxFactory.Block(m.Statements)) ) ) ) @@ -462,46 +481,45 @@ public IEnumerable BuildTree(string namespaceName, string className) ) ).NormalizeWhitespace(); - // WORKAROUND: serializing and parsing the tree is necessary here because Roslyn throws compilation errors when pass the original tree which uses markup controls (they reference in-memory assemblies) - // the trees are the same (root2.GetChanges(root) returns empty collection) but without serialization and parsing it does not work - SyntaxTree = CSharpSyntaxTree.ParseText(root.ToString()); - return new[] { SyntaxTree }; - } + // WORKAROUND: serializing and parsing the tree is necessary here because Roslyn throws compilation errors when pass the original tree which uses markup controls (they reference in-memory assemblies) + // the trees are the same (root2.GetChanges(root) returns empty collection) but without serialization and parsing it does not work + SyntaxTree = CSharpSyntaxTree.ParseText(root.ToString()); + return new[] { SyntaxTree + }; +} - /// - /// Pushes the new method. - /// - public void PushNewMethod(string name) - { - methods.Push(new EmitterMethodInfo() - { - Name = name - }); - } +/// +/// Pushes the new method. +/// +public void PushNewMethod(string name, params ParameterSyntax[] parameters) +{ + var emitterMethodInfo = new EmitterMethodInfo() { Name = name }; + methods.Push(emitterMethodInfo); +} - /// - /// Pops the method. - /// - public void PopMethod() - { - outputMethods.Add(methods.Pop()); - } +/// +/// Pops the method. +/// +public void PopMethod() +{ + outputMethods.Add(methods.Pop()); +} - /// - /// Emits the control class. - /// - public void EmitControlClass(Type baseType, string className) - { - otherClassDeclarations.Add( - SyntaxFactory.ClassDeclaration(className + "Control") - .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword))) - .WithBaseList(SyntaxFactory.BaseList(SyntaxFactory.SeparatedList(new[] +/// +/// Emits the control class. +/// +public void EmitControlClass(Type baseType, string className) +{ + otherClassDeclarations.Add( + SyntaxFactory.ClassDeclaration(className + "Control") + .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword))) + .WithBaseList(SyntaxFactory.BaseList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName(baseType.ToString())) }))) - ); - } + ); +} } } diff --git a/src/Redwood.Framework/Runtime/Compilation/EmitterMethodInfo.cs b/src/Redwood.Framework/Runtime/Compilation/EmitterMethodInfo.cs index 42fe2f1e2b..26fa627a45 100644 --- a/src/Redwood.Framework/Runtime/Compilation/EmitterMethodInfo.cs +++ b/src/Redwood.Framework/Runtime/Compilation/EmitterMethodInfo.cs @@ -13,6 +13,7 @@ public class EmitterMethodInfo public string Name { get; set; } public int ControlIndex { get; set; } + public EmitterMethodInfo() { diff --git a/src/Redwood.Framework/Runtime/ControlResolverMetadata.cs b/src/Redwood.Framework/Runtime/ControlResolverMetadata.cs index 0a40649966..90d80220a2 100644 --- a/src/Redwood.Framework/Runtime/ControlResolverMetadata.cs +++ b/src/Redwood.Framework/Runtime/ControlResolverMetadata.cs @@ -22,6 +22,9 @@ public class ControlResolverMetadata public bool IsContentAllowed { get; set; } + public string VirtualPath { get; internal set; } + + /// /// Finds the property. diff --git a/src/Redwood.Framework/Runtime/ControlType.cs b/src/Redwood.Framework/Runtime/ControlType.cs index ed4ca1e403..a212a324c5 100644 --- a/src/Redwood.Framework/Runtime/ControlType.cs +++ b/src/Redwood.Framework/Runtime/ControlType.cs @@ -12,14 +12,17 @@ public class ControlType public Type ControlBuilderType { get; private set; } + public string VirtualPath { get; private set; } + /// /// Initializes a new instance of the class. /// - public ControlType(Type type, Type controlBuilderType = null) + public ControlType(Type type, Type controlBuilderType = null, string virtualPath = null) { Type = type; ControlBuilderType = controlBuilderType; + VirtualPath = virtualPath; } diff --git a/src/Redwood.Framework/Runtime/DefaultControlBuilderFactory.cs b/src/Redwood.Framework/Runtime/DefaultControlBuilderFactory.cs index ed0b2ccf39..9f3d1df499 100644 --- a/src/Redwood.Framework/Runtime/DefaultControlBuilderFactory.cs +++ b/src/Redwood.Framework/Runtime/DefaultControlBuilderFactory.cs @@ -14,26 +14,32 @@ namespace Redwood.Framework.Runtime /// public class DefaultControlBuilderFactory : IControlBuilderFactory { - public Func ViewCompilerFactory { get; private set; } + private RedwoodConfiguration configuration; + private IMarkupFileLoader markupFileLoader; + public Func ViewCompilerFactory { get; private set; } private ConcurrentDictionary controlBuilders = new ConcurrentDictionary(); public DefaultControlBuilderFactory(RedwoodConfiguration configuration) { + this.configuration = configuration; + ViewCompilerFactory = () => configuration.ServiceLocator.GetService(); + markupFileLoader = configuration.ServiceLocator.GetService(); } /// /// Gets the control builder. /// - public IControlBuilder GetControlBuilder(MarkupFile markupFile) + public IControlBuilder GetControlBuilder(string virtualPath) { + var markupFile = markupFileLoader.GetMarkup(configuration, virtualPath); return controlBuilders.GetOrAdd(markupFile, CreateControlBuilder); } - + /// /// Creates the control builder. /// diff --git a/src/Redwood.Framework/Runtime/DefaultControlResolver.cs b/src/Redwood.Framework/Runtime/DefaultControlResolver.cs index d3da2ec0cc..216ea1a339 100644 --- a/src/Redwood.Framework/Runtime/DefaultControlResolver.cs +++ b/src/Redwood.Framework/Runtime/DefaultControlResolver.cs @@ -20,7 +20,6 @@ public class DefaultControlResolver : IControlResolver private readonly RedwoodConfiguration configuration; private readonly IControlBuilderFactory controlBuilderFactory; - private readonly IMarkupFileLoader markupFileLoader; private static ConcurrentDictionary cachedTagMappings = new ConcurrentDictionary(); private static ConcurrentDictionary cachedMetadata = new ConcurrentDictionary(); @@ -35,7 +34,6 @@ public DefaultControlResolver(RedwoodConfiguration configuration) { this.configuration = configuration; this.controlBuilderFactory = configuration.ServiceLocator.GetService(); - this.markupFileLoader = configuration.ServiceLocator.GetService(); if (!isInitialized) { @@ -82,7 +80,7 @@ public ControlResolverMetadata ResolveControl(string tagPrefix, string tagName, var searchKey = GetSearchKey(tagPrefix, tagName); activationParameters = null; var controlType = cachedTagMappings.GetOrAdd(searchKey, _ => FindControlMetadata(tagPrefix, tagName)); - var metadata = ResolveControl(controlType.Type, controlType.ControlBuilderType); + var metadata = ResolveControl(controlType); return metadata; } @@ -94,9 +92,14 @@ private static string GetSearchKey(string tagPrefix, string tagName) /// /// Resolves the control metadata for specified type. /// - public ControlResolverMetadata ResolveControl(Type type, Type controlBuilderType = null) + public ControlResolverMetadata ResolveControl(ControlType controlType) { - return cachedMetadata.GetOrAdd(type, _ => BuildControlMetadata(type, controlBuilderType)); + return cachedMetadata.GetOrAdd(controlType.Type, _ => BuildControlMetadata(controlType)); + } + + public ControlResolverMetadata ResolveControl(Type controlType) + { + return ResolveControl(new ControlType(controlType)); } /// @@ -185,27 +188,27 @@ private ControlType FindCompiledControl(string tagName, string namespaceName, st /// private ControlType FindMarkupControl(string file) { - var markupFile = markupFileLoader.GetMarkup(configuration, file); - var controlBuilder = controlBuilderFactory.GetControlBuilder(markupFile); - return new ControlType(controlBuilder.BuildControl().GetType(), controlBuilder.GetType()); + var controlBuilder = controlBuilderFactory.GetControlBuilder(file); + return new ControlType(controlBuilder.BuildControl(controlBuilderFactory).GetType(), controlBuilder.GetType(), file); } /// /// Gets the control metadata. /// - private ControlResolverMetadata BuildControlMetadata(Type controlType, Type controlBuilderType) + private ControlResolverMetadata BuildControlMetadata(ControlType type) { - var attribute = controlType.GetCustomAttribute(); + var attribute = type.Type.GetCustomAttribute(); var metadata = new ControlResolverMetadata() { - Name = controlType.Name, - Namespace = controlType.Namespace, - HasHtmlAttributesCollection = typeof(IControlWithHtmlAttributes).IsAssignableFrom(controlType), - Type = controlType, - ControlBuilderType = controlBuilderType, - Properties = GetControlProperties(controlType), - IsContentAllowed = attribute.AllowContent + Name = type.Type.Name, + Namespace = type.Type.Namespace, + HasHtmlAttributesCollection = typeof(IControlWithHtmlAttributes).IsAssignableFrom(type.Type), + Type = type.Type, + ControlBuilderType = type.ControlBuilderType, + Properties = GetControlProperties(type.Type), + IsContentAllowed = attribute.AllowContent, + VirtualPath = type.VirtualPath }; return metadata; } diff --git a/src/Redwood.Framework/Runtime/DefaultRedwoodViewBuilder.cs b/src/Redwood.Framework/Runtime/DefaultRedwoodViewBuilder.cs index 4dac008b88..414888f138 100644 --- a/src/Redwood.Framework/Runtime/DefaultRedwoodViewBuilder.cs +++ b/src/Redwood.Framework/Runtime/DefaultRedwoodViewBuilder.cs @@ -15,10 +15,10 @@ namespace Redwood.Framework.Runtime /// public class DefaultRedwoodViewBuilder : IRedwoodViewBuilder { - - public IMarkupFileLoader MarkupFileLoader { get; private set; } - public IControlBuilderFactory ControlBuilderFactory { get; private set; } + private IMarkupFileLoader markupFileLoader; + + private IControlBuilderFactory controlBuilderFactory; @@ -27,8 +27,8 @@ public class DefaultRedwoodViewBuilder : IRedwoodViewBuilder /// public DefaultRedwoodViewBuilder(RedwoodConfiguration configuration) { - MarkupFileLoader = configuration.ServiceLocator.GetService(); - ControlBuilderFactory = configuration.ServiceLocator.GetService(); + markupFileLoader = configuration.ServiceLocator.GetService(); + controlBuilderFactory = configuration.ServiceLocator.GetService(); } /// @@ -37,19 +37,18 @@ public DefaultRedwoodViewBuilder(RedwoodConfiguration configuration) public RedwoodView BuildView(RedwoodRequestContext context) { // get the page markup - var markup = MarkupFileLoader.GetMarkup(context); + var markup = markupFileLoader.GetMarkupFileVirtualPath(context); // build the page - var pageBuilder = ControlBuilderFactory.GetControlBuilder(markup); - var contentPage = pageBuilder.BuildControl() as RedwoodView; + var pageBuilder = controlBuilderFactory.GetControlBuilder(markup); + var contentPage = pageBuilder.BuildControl(controlBuilderFactory) as RedwoodView; // check for master page and perform composition recursively while (IsNestedInMasterPage(contentPage)) { // load master page var masterPageFile = contentPage.Directives[Constants.MasterPageDirective]; - var masterPageMarkup = MarkupFileLoader.GetMarkup(context.Configuration, masterPageFile); - var masterPage = (RedwoodView)ControlBuilderFactory.GetControlBuilder(masterPageMarkup).BuildControl(); + var masterPage = (RedwoodView)controlBuilderFactory.GetControlBuilder(masterPageFile).BuildControl(controlBuilderFactory); PerformMasterPageComposition(contentPage, masterPage); contentPage = masterPage; diff --git a/src/Redwood.Framework/Runtime/IControlBuilder.cs b/src/Redwood.Framework/Runtime/IControlBuilder.cs index c936d459ff..635503d743 100644 --- a/src/Redwood.Framework/Runtime/IControlBuilder.cs +++ b/src/Redwood.Framework/Runtime/IControlBuilder.cs @@ -8,7 +8,7 @@ namespace Redwood.Framework.Runtime public interface IControlBuilder { - RedwoodControl BuildControl(); + RedwoodControl BuildControl(IControlBuilderFactory controlBuilderFactory); } } \ No newline at end of file diff --git a/src/Redwood.Framework/Runtime/IControlBuilderFactory.cs b/src/Redwood.Framework/Runtime/IControlBuilderFactory.cs index c40e4f981e..517bd248ee 100644 --- a/src/Redwood.Framework/Runtime/IControlBuilderFactory.cs +++ b/src/Redwood.Framework/Runtime/IControlBuilderFactory.cs @@ -9,7 +9,7 @@ namespace Redwood.Framework.Runtime public interface IControlBuilderFactory { - IControlBuilder GetControlBuilder(MarkupFile markupFile); + IControlBuilder GetControlBuilder(string virtualPath); } } \ No newline at end of file diff --git a/src/Redwood.Framework/Runtime/IControlResolver.cs b/src/Redwood.Framework/Runtime/IControlResolver.cs index 6b343ab886..9674e91f6f 100644 --- a/src/Redwood.Framework/Runtime/IControlResolver.cs +++ b/src/Redwood.Framework/Runtime/IControlResolver.cs @@ -16,7 +16,13 @@ public interface IControlResolver /// /// Resolves the control metadata for specified type. /// - ControlResolverMetadata ResolveControl(Type type, Type controlBuilderType = null); + ControlResolverMetadata ResolveControl(ControlType type); + + /// + /// Resolves the control metadata for specified type. + /// + ControlResolverMetadata ResolveControl(Type controlType); + /// /// Resolves the binding type.