diff --git a/src/Framework/Core/ViewModel/AllowStaticCommandAttribute.cs b/src/Framework/Core/ViewModel/AllowStaticCommandAttribute.cs index 307da6592e..f09f0fb468 100644 --- a/src/Framework/Core/ViewModel/AllowStaticCommandAttribute.cs +++ b/src/Framework/Core/ViewModel/AllowStaticCommandAttribute.cs @@ -3,6 +3,11 @@ namespace DotVVM.Framework.ViewModel { + /// Allows DotVVM to call the method from staticCommand. + /// + /// This attribute must be used to prevent attackers from calling any method in your system. + /// While DotVVM signs the method names used staticCommand and it shouldn't be possible to execute any other method, + /// the attribute offers a decent protection against RCE in case the Asp.Net Core encryption keys are compromised. public class AllowStaticCommandAttribute : Attribute { } diff --git a/src/Framework/Core/ViewModel/Direction.cs b/src/Framework/Core/ViewModel/Direction.cs index c47a9a2922..2f51f88980 100644 --- a/src/Framework/Core/ViewModel/Direction.cs +++ b/src/Framework/Core/ViewModel/Direction.cs @@ -5,19 +5,31 @@ namespace DotVVM.Framework.ViewModel { /// - /// ServerToClient, ServerToClient on postback, ClientToServer, C2S iff in command path + /// Specifies on which requests should the property be serialized and sent. Default is Both. + /// Set to None to disable serialization of the property. + /// This enumeration can be treated as flags, the directions can be arbitrarily combined. /// [Flags] public enum Direction { + /// Never send this property to the client, it won't be allowed to use this property from value and staticCommand bindings. None = 0, + /// Sent to client on the initial GET request, but not sent again on postbacks ServerToClientFirstRequest = 1, + /// Property is updated on postbacks, but not sent on the first request (initially it will be set to null or default value of the primitive type) ServerToClientPostback = 2, + /// Sent from server to client, but not sent back. ServerToClient = ServerToClientFirstRequest | ServerToClientPostback, + /// Complement to , not meant to be used on its own. ClientToServerNotInPostbackPath = 4, + /// Sent from client to server, but only if the current data context is this property. If the data context is a child object of this property, only that part of the object will be sent, all other properties are ignored. + /// To sent the initial value to client, use Direction.ServerToClientFirstRequest | Direction.ClientToServerInPostbackPath ClientToServerInPostbackPath = 8, + /// Sent back on postbacks. Initially the property will set to null or primitive default value. To send the initial value to client, use Direction.ServerToClientFirstRequest | Direction.ClientToServer ClientToServer = ClientToServerInPostbackPath | ClientToServerNotInPostbackPath, + /// Always sent to client, sent back only when the object is the current data context (see also ) IfInPostbackPath = ServerToClient | ClientToServerInPostbackPath, + /// Value is sent on each request. This is the default value. Both = 15, } -} \ No newline at end of file +} diff --git a/src/Framework/Core/ViewModel/ProtectMode.cs b/src/Framework/Core/ViewModel/ProtectMode.cs index 18c2c9a958..288ee41e6d 100644 --- a/src/Framework/Core/ViewModel/ProtectMode.cs +++ b/src/Framework/Core/ViewModel/ProtectMode.cs @@ -11,17 +11,17 @@ namespace DotVVM.Framework.ViewModel public enum ProtectMode { /// - /// The property value is sent to the client unencrypted and it is not signed. It can be modified on the client with no restrictions. + /// The property value is sent to the client unencrypted and it is not signed. It can be modified on the client with no restrictions. This is the default. /// None, /// - /// The property value is sent to the client unencrypted, but it is also signed. If it is modified on the client, the server will throw an exception during postback. + /// The property value is sent to the client in both unencrypted and encrypted form. On server, the encrypted value is read, so it cannot be modified on the client. /// SignData, /// - /// The property value is encrypted before it is sent to the client. + /// The property value is encrypted before it is sent to the client. Encrypted properties thus cannot be used in value bindings. /// EncryptData } diff --git a/src/Framework/Framework/Binding/ActiveDotvvmProperty.cs b/src/Framework/Framework/Binding/ActiveDotvvmProperty.cs index 719beda699..831b85d787 100644 --- a/src/Framework/Framework/Binding/ActiveDotvvmProperty.cs +++ b/src/Framework/Framework/Binding/ActiveDotvvmProperty.cs @@ -10,6 +10,7 @@ namespace DotVVM.Framework.Binding { + /// An abstract DotvvmProperty which contains code to be executed when the assigned control is being rendered. public abstract class ActiveDotvvmProperty : DotvvmProperty { public abstract void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context, DotvvmControl control); diff --git a/src/Framework/Framework/Binding/AttachedPropertyAttribute.cs b/src/Framework/Framework/Binding/AttachedPropertyAttribute.cs index 65ee39234e..a30427ab94 100644 --- a/src/Framework/Framework/Binding/AttachedPropertyAttribute.cs +++ b/src/Framework/Framework/Binding/AttachedPropertyAttribute.cs @@ -6,6 +6,8 @@ namespace DotVVM.Framework.Binding { + /// Used to mark DotvvmProperty which are used on other control than the declaring type. For example, Validation.Target is an attached property. + /// Note that DotVVM allows this for any DotvvmProperty, but this attribute instructs editor extension to include the property in autocompletion. [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] public class AttachedPropertyAttribute : Attribute { diff --git a/src/Framework/Framework/Binding/BindingCompilationOptionsAttribute.cs b/src/Framework/Framework/Binding/BindingCompilationOptionsAttribute.cs index d04de43a34..5a7e8eddc8 100644 --- a/src/Framework/Framework/Binding/BindingCompilationOptionsAttribute.cs +++ b/src/Framework/Framework/Binding/BindingCompilationOptionsAttribute.cs @@ -1,11 +1,18 @@ using System; using System.Collections.Generic; using System.Text; +using DotVVM.Framework.Binding.Expressions; +using DotVVM.Framework.Compilation.Binding; namespace DotVVM.Framework.Binding { + /// Allow to adjust how bindings are compiled. Can be placed on custom binding type (for example, see ) or on a dotvvm property public abstract class BindingCompilationOptionsAttribute : Attribute { + /// Returns a list of resolvers - functions which accept any set of existing binding properties and returns one new binding property. + /// It will be automatically invoked when the returned property is needed. + /// See for a list of default property resolvers - to adjust how the binding is compiled, you'll want to redefine one of the default resolvers. + /// See for example how to use this method. public abstract IEnumerable GetResolvers(); } } diff --git a/src/Framework/Framework/Binding/BindingCompilationService.cs b/src/Framework/Framework/Binding/BindingCompilationService.cs index d349303b5e..f5e2ee7ddd 100644 --- a/src/Framework/Framework/Binding/BindingCompilationService.cs +++ b/src/Framework/Framework/Binding/BindingCompilationService.cs @@ -26,10 +26,13 @@ public class BindingCompilationOptions public List TransformerClasses { get; set; } = new List(); } + /// A service used to create new bindings and compute binding properties. public class BindingCompilationService { private readonly IExpressionToDelegateCompiler expressionCompiler; private readonly Lazy noInitService; + + /// Utilities for caching bindings created at runtime public DotvvmBindingCacheHelper Cache { get; } public BindingCompilationService(IOptions options, IExpressionToDelegateCompiler expressionCompiler, IDotvvmCacheAdapter cache) @@ -123,7 +126,7 @@ public BindingCompilationRequirementsAttribute GetRequirements(IBinding binding, } /// - /// Resolves required and optional properties + /// Resolves required properties of the binding. If the binding contains it will be used to report errors instead of throwing an exception. /// public virtual void InitializeBinding(IBinding binding, IEnumerable? bindingRequirements = null) { diff --git a/src/Framework/Framework/Binding/BindingHelper.cs b/src/Framework/Framework/Binding/BindingHelper.cs index a7e7172b90..c646d716f7 100644 --- a/src/Framework/Framework/Binding/BindingHelper.cs +++ b/src/Framework/Framework/Binding/BindingHelper.cs @@ -24,8 +24,10 @@ namespace DotVVM.Framework.Binding { public static partial class BindingHelper { + /// Gets the binding property identified by the type. The result may be null, if is ReturnNul This method should always return the same result and should run fast (may rely on caching, so first call might not be that fast). [return: MaybeNull] - public static T GetProperty(this IBinding binding, ErrorHandlingMode errorMode = ErrorHandlingMode.ThrowException) => (T)binding.GetProperty(typeof(T), errorMode)!; + public static T GetProperty(this IBinding binding, ErrorHandlingMode errorMode) => (T)binding.GetProperty(typeof(T), errorMode)!; + /// Gets the binding property identified by the type. This method should always return the same result and should run fast (may rely on caching, so first call might not be that fast). public static T GetProperty(this IBinding binding) => GetProperty(binding, ErrorHandlingMode.ThrowException)!; [Obsolete] diff --git a/src/Framework/Framework/Binding/BindingPageInfo.cs b/src/Framework/Framework/Binding/BindingPageInfo.cs index f705bd4534..80d64dcca6 100644 --- a/src/Framework/Framework/Binding/BindingPageInfo.cs +++ b/src/Framework/Framework/Binding/BindingPageInfo.cs @@ -11,8 +11,11 @@ namespace DotVVM.Framework.Binding { public class BindingPageInfo { + /// Returns true if any command or staticCommand is currently running. Always returns false on the server. public bool IsPostbackRunning => false; + /// Returns true on server and false in JavaScript. public bool EvaluatingOnServer => true; + /// Returns false on server and true in JavaScript. public bool EvaluatingOnClient => false; internal static void RegisterJavascriptTranslations(JavascriptTranslatableMethodCollection methods) diff --git a/src/Framework/Framework/Binding/CollectionElementDataContextChangeAttribute.cs b/src/Framework/Framework/Binding/CollectionElementDataContextChangeAttribute.cs index 3dadaa94bd..7a53483fe2 100644 --- a/src/Framework/Framework/Binding/CollectionElementDataContextChangeAttribute.cs +++ b/src/Framework/Framework/Binding/CollectionElementDataContextChangeAttribute.cs @@ -10,6 +10,7 @@ namespace DotVVM.Framework.Binding { + /// Sets data context type to the element type of current data context. public class CollectionElementDataContextChangeAttribute : DataContextChangeAttribute { public override int Order { get; } diff --git a/src/Framework/Framework/Binding/CompileTimeOnlyDotvvmProperty.cs b/src/Framework/Framework/Binding/CompileTimeOnlyDotvvmProperty.cs index 744d391820..b982ee6569 100644 --- a/src/Framework/Framework/Binding/CompileTimeOnlyDotvvmProperty.cs +++ b/src/Framework/Framework/Binding/CompileTimeOnlyDotvvmProperty.cs @@ -7,7 +7,7 @@ namespace DotVVM.Framework.Binding { /// - /// The DotvvmProperty that fallbacks to another DotvvmProperty's value. + /// The DotvvmProperty that can only be used at compile time (in server-side styles or precompiled CompositeControls) /// public class CompileTimeOnlyDotvvmProperty : DotvvmProperty { diff --git a/src/Framework/Framework/Binding/ConstantDataContextChangeAttribute.cs b/src/Framework/Framework/Binding/ConstantDataContextChangeAttribute.cs index 63c4d4bebb..b0b82d8d3e 100644 --- a/src/Framework/Framework/Binding/ConstantDataContextChangeAttribute.cs +++ b/src/Framework/Framework/Binding/ConstantDataContextChangeAttribute.cs @@ -9,6 +9,7 @@ namespace DotVVM.Framework.Binding { + /// Changes the data context type to the type specified in the attribute constructor. public class ConstantDataContextChangeAttribute : DataContextChangeAttribute { public Type Type { get; } diff --git a/src/Framework/Framework/Binding/ControlPropertyBindingDataContextChangeAttribute.cs b/src/Framework/Framework/Binding/ControlPropertyBindingDataContextChangeAttribute.cs index b56d25d813..be4ca4606b 100644 --- a/src/Framework/Framework/Binding/ControlPropertyBindingDataContextChangeAttribute.cs +++ b/src/Framework/Framework/Binding/ControlPropertyBindingDataContextChangeAttribute.cs @@ -10,6 +10,7 @@ namespace DotVVM.Framework.Binding { + /// Sets data context type to the result type of binding the specified property. public class ControlPropertyBindingDataContextChangeAttribute : DataContextChangeAttribute { public string PropertyName { get; set; } diff --git a/src/Framework/Framework/Binding/ControlPropertyTypeDataContextChangeAttribute.cs b/src/Framework/Framework/Binding/ControlPropertyTypeDataContextChangeAttribute.cs index 050ee0294a..f509c813ef 100644 --- a/src/Framework/Framework/Binding/ControlPropertyTypeDataContextChangeAttribute.cs +++ b/src/Framework/Framework/Binding/ControlPropertyTypeDataContextChangeAttribute.cs @@ -8,6 +8,7 @@ namespace DotVVM.Framework.Binding { + [Obsolete("Use ControlPropertyBindingDataContextChangeAttribute instead.")] public class ControlPropertyTypeDataContextChangeAttribute : DataContextChangeAttribute { public string PropertyName { get; set; } diff --git a/src/Framework/Framework/Binding/DelegateActionProperty.cs b/src/Framework/Framework/Binding/DelegateActionProperty.cs index 591d2d5feb..81c1e23c86 100644 --- a/src/Framework/Framework/Binding/DelegateActionProperty.cs +++ b/src/Framework/Framework/Binding/DelegateActionProperty.cs @@ -10,6 +10,7 @@ namespace DotVVM.Framework.Binding { + /// DotvvmProperty which calls the function passed in the Register method, when the assigned control is being rendered. public sealed class DelegateActionProperty: ActiveDotvvmProperty { private Action func; diff --git a/src/Framework/Framework/Binding/DotvvmBindingCacheHelper.cs b/src/Framework/Framework/Binding/DotvvmBindingCacheHelper.cs index 25b9abd82f..cc11591f26 100644 --- a/src/Framework/Framework/Binding/DotvvmBindingCacheHelper.cs +++ b/src/Framework/Framework/Binding/DotvvmBindingCacheHelper.cs @@ -22,6 +22,7 @@ public DotvvmBindingCacheHelper(IDotvvmCacheAdapter cache, BindingCompilationSer this.compilationService = compilationService; } + /// Creates a new binding using the , unless an existing cache entry is found. Entries are identified using the identifier and keys. By default, the cache is LRU with size=1000 public T CreateCachedBinding(string identifier, object?[] keys, Func factory) where T: IBinding { return this.cache.GetOrAdd(new CacheKey(typeof(T), identifier, keys), _ => { @@ -31,6 +32,7 @@ public T CreateCachedBinding(string identifier, object?[] keys, Func facto }); } + /// Creates a new binding of type with the specified properties, unless an existing cache entry is found. Entries are identified using the identifier and keys. By default, the cache is LRU with size=1000 public T CreateCachedBinding(string identifier, object[] keys, object[] properties) where T: IBinding { return CreateCachedBinding(identifier, keys, () => (T)BindingFactory.CreateBinding(this.compilationService, typeof(T), properties)); diff --git a/src/Framework/Framework/Binding/Expressions/BindingExpression.cs b/src/Framework/Framework/Binding/Expressions/BindingExpression.cs index 513d20d756..6d4972d6a7 100644 --- a/src/Framework/Framework/Binding/Expressions/BindingExpression.cs +++ b/src/Framework/Framework/Binding/Expressions/BindingExpression.cs @@ -18,6 +18,9 @@ namespace DotVVM.Framework.Binding.Expressions { + /// Represents a data-binding in DotVVM. + /// This is a base class for all bindings, BindingExpression in general does not guarantee that the binding will have any property. + /// This class only contains the glue code which automatically calls resolvers and caches the results when is invoked. [BindingCompilationRequirements(optional: new[] { typeof(BindingResolverCollection) })] [Newtonsoft.Json.JsonConverter(typeof(BindingDebugJsonConverter))] public abstract class BindingExpression : IBinding, ICloneableBinding diff --git a/src/Framework/Framework/Binding/Expressions/IBinding.cs b/src/Framework/Framework/Binding/Expressions/IBinding.cs index 7a5753fe80..64c9410954 100644 --- a/src/Framework/Framework/Binding/Expressions/IBinding.cs +++ b/src/Framework/Framework/Binding/Expressions/IBinding.cs @@ -4,26 +4,33 @@ namespace DotVVM.Framework.Binding.Expressions { + /// Controls what happens when the binding property does not exist on this binding or when its resolver throws an exception. public enum ErrorHandlingMode { + /// Returns null. The null is returned even in case when resolver throws an exception, you can't distinguish between the "property does not exist", "resolver failed" states using this mode. ReturnNull, + /// Throws the exception. Always throws . In case the property is missing, message = "resolver not found". Otherwise, the exception will have the resolver error as InnerException. ThrowException, + /// Behaves similarly to ThrowException, but the exception is returned instead of being thrown. This is useful when you'd catch the exception immediately to avoid annoying debugger by throwing too many exceptions. ReturnException } + + /// General interface which all DotVVM data binding types must implement. This interface does not provide any specific binding properties, only the basic building blocks - that bindings are composed of binding properties (), should have a DataContext and may have resolvers. public interface IBinding { + /// Gets the binding property identified by the type. Returned object will always be of type , null, or Exception (this depends on the ). This method should always return the same result and should run fast (may rely on caching, so first call might not be that fast). object? GetProperty(Type type, ErrorHandlingMode errorMode = ErrorHandlingMode.ThrowException); + /// If the binding expects a specific data context, this property should return it. "Normal" binding coming from dothtml markup won't return null since they always depend on the data context. DataContextStack? DataContext { get; } BindingResolverCollection? GetAdditionalResolvers(); - //IDictionary Properties { get; } - //IList AdditionalServices { get; } } public interface ICloneableBinding: IBinding { + /// Returns a list of all properties which are already cached. Creating a new binding with these properties will produce the same binding. IEnumerable GetAllComputedProperties(); } } diff --git a/src/Framework/Framework/Binding/Expressions/StaticCommandBindingExpression.cs b/src/Framework/Framework/Binding/Expressions/StaticCommandBindingExpression.cs index 30d1f9dcd1..5e50a872c7 100644 --- a/src/Framework/Framework/Binding/Expressions/StaticCommandBindingExpression.cs +++ b/src/Framework/Framework/Binding/Expressions/StaticCommandBindingExpression.cs @@ -10,6 +10,7 @@ namespace DotVVM.Framework.Binding.Expressions { + /// The `{staticCommand: ...}` binding. It is a command that runs primarily client-side and is well-suited to handle events. Compared to `value` binding, `staticCommand`s are expected to have side effects and run asynchronously (the binding will return a Promise or a Task). [BindingCompilationRequirements( required: new[] { typeof(StaticCommandOptionsLambdaJavascriptProperty), /*typeof(BindingDelegate)*/ } )] diff --git a/src/Framework/Framework/Binding/HelperNamespace/ListExtensions.cs b/src/Framework/Framework/Binding/HelperNamespace/ListExtensions.cs index 44597c1a70..b647ff25ef 100644 --- a/src/Framework/Framework/Binding/HelperNamespace/ListExtensions.cs +++ b/src/Framework/Framework/Binding/HelperNamespace/ListExtensions.cs @@ -8,6 +8,7 @@ namespace DotVVM.Framework.Binding.HelperNamespace { public static class ListExtensions { + /// Updates all entries identified by using the . If none match, the is appended to the list. public static void AddOrUpdate(this List list, T element, Func matcher, Func updater) { var found = false; @@ -24,6 +25,7 @@ public static void AddOrUpdate(this List list, T element, Func mat list.Add(element); } + /// Removes the first entry identified by . public static void RemoveFirst(this List list, Func predicate) { for (var index = 0; index < list.Count; index++) @@ -36,6 +38,7 @@ public static void RemoveFirst(this List list, Func predicate) } } + /// Removes the last entry identified by . public static void RemoveLast(this List list, Func predicate) { for (var index = list.Count - 1; index >= 0; index--) diff --git a/src/Framework/Framework/Binding/VirtualPropertyGroupDictionary.cs b/src/Framework/Framework/Binding/VirtualPropertyGroupDictionary.cs index 323e740f89..8be168dd0e 100644 --- a/src/Framework/Framework/Binding/VirtualPropertyGroupDictionary.cs +++ b/src/Framework/Framework/Binding/VirtualPropertyGroupDictionary.cs @@ -12,6 +12,7 @@ namespace DotVVM.Framework.Binding { + /// Represents a dictionary of values of . public readonly struct VirtualPropertyGroupDictionary : IDictionary, IReadOnlyDictionary { private readonly DotvvmBindableObject control; @@ -38,6 +39,7 @@ public IEnumerable Keys } } + /// Lists all values. If any of the properties contains a binding, it will be automatically evaluated. public IEnumerable Values { get @@ -106,6 +108,7 @@ public bool Any() ICollection IDictionary.Values => Values.ToList(); + /// Gets or sets value of property identified by . If the property contains a binding, the getter will automatically evaluate it. public TValue this[string key] { get @@ -122,8 +125,11 @@ public TValue this[string key] } } + /// Gets the value binding set to a specified property. Returns null if the property is not a binding, throws if the binding some kind of command. public IValueBinding? GetValueBinding(string key) => control.GetValueBinding(group.GetDotvvmProperty(key)); + /// Gets the binding set to a specified property. Returns null if the property is not set or if the value is not a binding. public IBinding? GetBinding(string key) => control.GetBinding(group.GetDotvvmProperty(key)); + /// Gets the value or a binding object for a specified property. public object? GetValueRaw(string key) { var p = group.GetDotvvmProperty(key); @@ -133,12 +139,15 @@ public TValue this[string key] return p.DefaultValue!; } + /// Adds value or overwrites the property identified by . public void Set(string key, ValueOrBinding value) { control.properties.Set(group.GetDotvvmProperty(key), value.UnwrapToObject()); } + /// Adds value or overwrites the property identified by with the value. public void Set(string key, TValue value) => control.properties.Set(group.GetDotvvmProperty(key), value); + /// Adds binding or overwrites the property identified by with the binding. public void SetBinding(string key, IBinding binding) => control.properties.Set(group.GetDotvvmProperty(key), binding); @@ -156,6 +165,7 @@ private void AddOnConflict(GroupedDotvvmProperty property, object? value) control.properties.Set(property, mergedValue); } + /// Adds the property identified by . If the property is already set, it tries appending the value using the group's public void Add(string key, ValueOrBinding value) { var prop = group.GetDotvvmProperty(key); @@ -163,9 +173,12 @@ public void Add(string key, ValueOrBinding value) if (!control.properties.TryAdd(prop, val)) AddOnConflict(prop, val); } + + /// Adds the property identified by . If the property is already set, it tries appending the value using the group's public void Add(string key, TValue value) => this.Add(key, new ValueOrBinding(value)); + /// Adds the property identified by . If the property is already set, it tries appending the value using the group's public void AddBinding(string key, IBinding? binding) { Add(key, new ValueOrBinding(binding!)); @@ -222,6 +235,7 @@ public bool Remove(string key) return control.Properties.Remove(group.GetDotvvmProperty(key)); } + /// Tries getting value of property identified by . If the property contains a binding, it will be automatically evaluated. #pragma warning disable CS8767 public bool TryGetValue(string key, [MaybeNullWhen(false)] out TValue value) #pragma warning restore CS8767 @@ -239,6 +253,7 @@ public bool TryGetValue(string key, [MaybeNullWhen(false)] out TValue value) } } + /// Adds the property-value pair to the dictionary. If the property is already set, it tries appending the value using the group's public void Add(KeyValuePair item) { Add(item.Key, item.Value); @@ -303,6 +318,7 @@ public bool Remove(KeyValuePair item) return false; } + /// Enumerates all keys and values. If a property contains a binding, it will be automatically evaluated. public IEnumerator> GetEnumerator() { foreach (var (p, value) in control.properties) @@ -316,6 +332,7 @@ public IEnumerator> GetEnumerator() } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + /// Enumerates all keys and values, without evaluating the bindings. public IEnumerable> RawValues { get diff --git a/src/Framework/Framework/Compilation/ControlTree/DataContextStack.cs b/src/Framework/Framework/Compilation/ControlTree/DataContextStack.cs index 2b71472435..a655cadc35 100644 --- a/src/Framework/Framework/Compilation/ControlTree/DataContextStack.cs +++ b/src/Framework/Framework/Compilation/ControlTree/DataContextStack.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; @@ -17,9 +17,13 @@ namespace DotVVM.Framework.Compilation.ControlTree public sealed class DataContextStack : IDataContextStack { public DataContextStack? Parent { get; } + /// Type of `_this` public Type DataContextType { get; } + /// Namespaces imported by data context change attributes. public ImmutableArray NamespaceImports { get; } + /// Extension parameters added by data context change attributes (for example _index, _collection). public ImmutableArray ExtensionParameters { get; } + /// Extension property resolvers added by data context change attributes. public ImmutableArray BindingPropertyResolvers { get; } private readonly int hashCode; diff --git a/src/Framework/Framework/Compilation/ControlTree/DotvvmPropertyGroup.cs b/src/Framework/Framework/Compilation/ControlTree/DotvvmPropertyGroup.cs index 03d5868330..2fa03d4137 100644 --- a/src/Framework/Framework/Compilation/ControlTree/DotvvmPropertyGroup.cs +++ b/src/Framework/Framework/Compilation/ControlTree/DotvvmPropertyGroup.cs @@ -12,6 +12,7 @@ namespace DotVVM.Framework.Compilation.ControlTree { + /// A set of DotvvmProperties identified by a common prefix. For example RouteLink.Params-XX or html attributes are property groups. public class DotvvmPropertyGroup : IPropertyGroupDescriptor { public FieldInfo? DescriptorField { get; }