Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation comments to various binding-related classes #1541

Merged
merged 2 commits into from
Feb 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Framework/Core/ViewModel/AllowStaticCommandAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@

namespace DotVVM.Framework.ViewModel
{
/// <summary> Allows DotVVM to call the method from staticCommand. </summary>
/// <remarks>
/// 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. </remarks>
public class AllowStaticCommandAttribute : Attribute
{
}
Expand Down
16 changes: 14 additions & 2 deletions src/Framework/Core/ViewModel/Direction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,31 @@
namespace DotVVM.Framework.ViewModel
{
///<summary>
/// ServerToClient, ServerToClient on postback, ClientToServer, C2S iff in command path
/// Specifies on which requests should the property be serialized and sent. Default is <see cref="Direction.Both">Both</see>.
/// Set to <see cref="Direction.None">None</see> to disable serialization of the property.
/// This enumeration can be treated as flags, the directions can be arbitrarily combined.
///</summary>
[Flags]
public enum Direction
{
/// <summary> Never send this property to the client, it won't be allowed to use this property from value and staticCommand bindings. </summary>
None = 0,
/// <summary> Sent to client on the initial GET request, but not sent again on postbacks </summary>
ServerToClientFirstRequest = 1,
/// <summary> 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) </summary>
ServerToClientPostback = 2,
/// <summary> Sent from server to client, but not sent back. </summary>
ServerToClient = ServerToClientFirstRequest | ServerToClientPostback,
/// <summary> Complement to <see cref="ClientToServerInPostbackPath" />, not meant to be used on its own. </summary>
ClientToServerNotInPostbackPath = 4,
/// <summary> 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 <c>Direction.ServerToClientFirstRequest | Direction.ClientToServerInPostbackPath</c> </summary>
ClientToServerInPostbackPath = 8,
/// <summary> Sent back on postbacks. Initially the property will set to null or primitive default value. To send the initial value to client, use <c>Direction.ServerToClientFirstRequest | Direction.ClientToServer</c> </summary>
ClientToServer = ClientToServerInPostbackPath | ClientToServerNotInPostbackPath,
/// <summary> Always sent to client, sent back only when the object is the current data context (see also <see cref="ClientToServerInPostbackPath"/>) </summary>
IfInPostbackPath = ServerToClient | ClientToServerInPostbackPath,
/// <summary> Value is sent on each request. This is the default value. </summary>
Both = 15,
}
}
}
6 changes: 3 additions & 3 deletions src/Framework/Core/ViewModel/ProtectMode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ namespace DotVVM.Framework.ViewModel
public enum ProtectMode
{
/// <summary>
/// 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.
/// </summary>
None,

/// <summary>
/// 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.
/// </summary>
SignData,

/// <summary>
/// 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.
/// </summary>
EncryptData
}
Expand Down
1 change: 1 addition & 0 deletions src/Framework/Framework/Binding/ActiveDotvvmProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

namespace DotVVM.Framework.Binding
{
/// <summary> An abstract DotvvmProperty which contains code to be executed when the assigned control is being rendered. </summary>
public abstract class ActiveDotvvmProperty : DotvvmProperty
{
public abstract void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context, DotvvmControl control);
Expand Down
2 changes: 2 additions & 0 deletions src/Framework/Framework/Binding/AttachedPropertyAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

namespace DotVVM.Framework.Binding
{
/// <summary> Used to mark DotvvmProperty which are used on other control than the declaring type. For example, Validation.Target is an attached property. </summary>
/// <remark> Note that DotVVM allows this for any DotvvmProperty, but this attribute instructs editor extension to include the property in autocompletion. </remark>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class AttachedPropertyAttribute : Attribute
{
Expand Down
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary> Allow to adjust how bindings are compiled. Can be placed on custom binding type (for example, see <see cref="ValueBindingExpression" />) or on a dotvvm property </summary>
public abstract class BindingCompilationOptionsAttribute : Attribute
{
/// <summary> 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 <see cref="BindingPropertyResolvers" /> 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 <see cref="StaticCommandBindingExpression.OptionsAttribute" /> for example how to use this method. </summary>
public abstract IEnumerable<Delegate> GetResolvers();
}
}
5 changes: 4 additions & 1 deletion src/Framework/Framework/Binding/BindingCompilationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ public class BindingCompilationOptions
public List<object> TransformerClasses { get; set; } = new List<object>();
}

/// <summary> A service used to create new bindings and compute binding properties. </summary>
public class BindingCompilationService
{
private readonly IExpressionToDelegateCompiler expressionCompiler;
private readonly Lazy<BindingCompilationService> noInitService;

/// <summary> Utilities for caching bindings created at runtime </summary>
public DotvvmBindingCacheHelper Cache { get; }

public BindingCompilationService(IOptions<BindingCompilationOptions> options, IExpressionToDelegateCompiler expressionCompiler, IDotvvmCacheAdapter cache)
Expand Down Expand Up @@ -123,7 +126,7 @@ public BindingCompilationRequirementsAttribute GetRequirements(IBinding binding,
}

/// <summary>
/// Resolves required and optional properties
/// Resolves required properties of the binding. If the binding contains <see cref="BindingErrorReporterProperty" /> it will be used to report errors instead of throwing an exception.
/// </summary>
public virtual void InitializeBinding(IBinding binding, IEnumerable<BindingCompilationRequirementsAttribute>? bindingRequirements = null)
{
Expand Down
4 changes: 3 additions & 1 deletion src/Framework/Framework/Binding/BindingHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ namespace DotVVM.Framework.Binding
{
public static partial class BindingHelper
{
/// <summary> Gets the binding property identified by the type. The result may be null, if <paramref name="errorMode"/> is <see cref="ErrorHandlingMode.ReturnNull">ReturnNul</see> This method should always return the same result and should run fast (may rely on caching, so first call might not be that fast). </summary>
[return: MaybeNull]
public static T GetProperty<T>(this IBinding binding, ErrorHandlingMode errorMode = ErrorHandlingMode.ThrowException) => (T)binding.GetProperty(typeof(T), errorMode)!;
public static T GetProperty<T>(this IBinding binding, ErrorHandlingMode errorMode) => (T)binding.GetProperty(typeof(T), errorMode)!;
/// <summary> 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). </summary>
public static T GetProperty<T>(this IBinding binding) => GetProperty<T>(binding, ErrorHandlingMode.ThrowException)!;

[Obsolete]
Expand Down
3 changes: 3 additions & 0 deletions src/Framework/Framework/Binding/BindingPageInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ namespace DotVVM.Framework.Binding
{
public class BindingPageInfo
{
/// <summary> Returns true if any command or staticCommand is currently running. Always returns false on the server. </summary>
public bool IsPostbackRunning => false;
/// <summary> Returns true on server and false in JavaScript. </summary>
public bool EvaluatingOnServer => true;
/// <summary> Returns false on server and true in JavaScript. </summary>
public bool EvaluatingOnClient => false;

internal static void RegisterJavascriptTranslations(JavascriptTranslatableMethodCollection methods)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

namespace DotVVM.Framework.Binding
{
/// <summary> Sets data context type to the element type of current data context. </summary>
public class CollectionElementDataContextChangeAttribute : DataContextChangeAttribute
{
public override int Order { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace DotVVM.Framework.Binding
{
/// <summary>
/// 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)
/// </summary>
public class CompileTimeOnlyDotvvmProperty : DotvvmProperty
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

namespace DotVVM.Framework.Binding
{
/// <summary> Changes the data context type to the type specified in the attribute constructor. </summary>
public class ConstantDataContextChangeAttribute : DataContextChangeAttribute
{
public Type Type { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

namespace DotVVM.Framework.Binding
{
/// <summary> Sets data context type to the result type of binding the specified property. </summary>
public class ControlPropertyBindingDataContextChangeAttribute : DataContextChangeAttribute
{
public string PropertyName { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

namespace DotVVM.Framework.Binding
{
[Obsolete("Use ControlPropertyBindingDataContextChangeAttribute instead.")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how commonly this is used but we could mention it in release notes

public class ControlPropertyTypeDataContextChangeAttribute : DataContextChangeAttribute
{
public string PropertyName { get; set; }
Expand Down
1 change: 1 addition & 0 deletions src/Framework/Framework/Binding/DelegateActionProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

namespace DotVVM.Framework.Binding
{
/// <summary> DotvvmProperty which calls the function passed in the Register method, when the assigned control is being rendered. </summary>
public sealed class DelegateActionProperty<TValue>: ActiveDotvvmProperty
{
private Action<IHtmlWriter, IDotvvmRequestContext, DotvvmProperty, DotvvmControl> func;
Expand Down
2 changes: 2 additions & 0 deletions src/Framework/Framework/Binding/DotvvmBindingCacheHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public DotvvmBindingCacheHelper(IDotvvmCacheAdapter cache, BindingCompilationSer
this.compilationService = compilationService;
}

/// <summary> Creates a new binding using the <paramref name="factory"/>, unless an existing cache entry is found. Entries are identified using the identifier and keys. By default, the cache is LRU with size=1000 </summary>
public T CreateCachedBinding<T>(string identifier, object?[] keys, Func<T> factory) where T: IBinding
{
return this.cache.GetOrAdd(new CacheKey(typeof(T), identifier, keys), _ => {
Expand All @@ -31,6 +32,7 @@ public T CreateCachedBinding<T>(string identifier, object?[] keys, Func<T> facto
});
}

/// <summary> Creates a new binding of type <typeparamref name="T"/> 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 </summary>
public T CreateCachedBinding<T>(string identifier, object[] keys, object[] properties) where T: IBinding
{
return CreateCachedBinding<T>(identifier, keys, () => (T)BindingFactory.CreateBinding(this.compilationService, typeof(T), properties));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

namespace DotVVM.Framework.Binding.Expressions
{
/// <summary> 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 <see cref="GetProperty(Type, ErrorHandlingMode)" /> is invoked. </summary>
[BindingCompilationRequirements(optional: new[] { typeof(BindingResolverCollection) })]
[Newtonsoft.Json.JsonConverter(typeof(BindingDebugJsonConverter))]
public abstract class BindingExpression : IBinding, ICloneableBinding
Expand Down
11 changes: 9 additions & 2 deletions src/Framework/Framework/Binding/Expressions/IBinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,33 @@

namespace DotVVM.Framework.Binding.Expressions
{
/// <summary> Controls what happens when the binding property does not exist on this binding or when its resolver throws an exception. </summary>
public enum ErrorHandlingMode
{
/// <summary> 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. </summary>
ReturnNull,
/// <summary> Throws the exception. Always throws <see cref="BindingPropertyException" />. In case the property is missing, message = "resolver not found". Otherwise, the exception will have the resolver error as InnerException. </summary>
ThrowException,
/// <summary> 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. </summary>
ReturnException
}

/// <summary> 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 (<see cref="GetProperty(Type, ErrorHandlingMode)" />), should have a DataContext and may have resolvers. </summary>
public interface IBinding
{
/// <summary> Gets the binding property identified by the type. Returned object will always be of type <paramref name="type"/>, null, or Exception (this depends on the <paramref name="errorMode" />). This method should always return the same result and should run fast (may rely on caching, so first call might not be that fast). </summary>
object? GetProperty(Type type, ErrorHandlingMode errorMode = ErrorHandlingMode.ThrowException);

/// <summary> 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. </summary>
DataContextStack? DataContext { get; }

BindingResolverCollection? GetAdditionalResolvers();
//IDictionary<Type, object> Properties { get; }
//IList<Delegate> AdditionalServices { get; }
}


public interface ICloneableBinding: IBinding
{
/// <summary> Returns a list of all properties which are already cached. Creating a new binding with these properties will produce the same binding. </summary>
IEnumerable<object> GetAllComputedProperties();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

namespace DotVVM.Framework.Binding.Expressions
{
/// <summary> 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). </summary>
[BindingCompilationRequirements(
required: new[] { typeof(StaticCommandOptionsLambdaJavascriptProperty), /*typeof(BindingDelegate)*/ }
)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace DotVVM.Framework.Binding.HelperNamespace
{
public static class ListExtensions
{
/// <summary> Updates all entries identified by <paramref name="matcher"/> using the <paramref name="updater"/>. If none match, the <paramref name="element"/> is appended to the list. </summary>
public static void AddOrUpdate<T>(this List<T> list, T element, Func<T,bool> matcher, Func<T,T> updater)
{
var found = false;
Expand All @@ -24,6 +25,7 @@ public static void AddOrUpdate<T>(this List<T> list, T element, Func<T,bool> mat
list.Add(element);
}

/// <summary> Removes the first entry identified by <paramref name="predicate"/>. </summary>
public static void RemoveFirst<T>(this List<T> list, Func<T,bool> predicate)
{
for (var index = 0; index < list.Count; index++)
Expand All @@ -36,6 +38,7 @@ public static void RemoveFirst<T>(this List<T> list, Func<T,bool> predicate)
}
}

/// <summary> Removes the last entry identified by <paramref name="predicate"/>. </summary>
public static void RemoveLast<T>(this List<T> list, Func<T, bool> predicate)
{
for (var index = list.Count - 1; index >= 0; index--)
Expand Down
Loading