-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Closed
Labels
DoneThis issue has been fixedThis issue has been fixedarea-blazorIncludes: Blazor, Razor ComponentsIncludes: Blazor, Razor Components
Milestone
Description
Blazor API Review: Components programming model
This is the API for the primary programming surface for authoring components. This includes types and attributes that make up ComponentBase as well as types that you will use like MarkupString and ElementRef. This excludes feature areas like IUriHelper, RenderTreeBuilder, or auth which get their own API review.
ComponentBase
namespace Microsoft.AspNetCore.Components
{
public abstract partial class ComponentBase : Microsoft.AspNetCore.Components.IComponent, Microsoft.AspNetCore.Components.IHandleAfterRender, Microsoft.AspNetCore.Components.IHandleEvent
{
public ComponentBase() { }
protected virtual void BuildRenderTree(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder) { }
protected System.Threading.Tasks.Task Invoke(System.Action workItem) { throw null; }
protected System.Threading.Tasks.Task InvokeAsync(System.Func<System.Threading.Tasks.Task> workItem) { throw null; }
void Microsoft.AspNetCore.Components.IComponent.Configure(Microsoft.AspNetCore.Components.RenderHandle renderHandle) { }
System.Threading.Tasks.Task Microsoft.AspNetCore.Components.IHandleAfterRender.OnAfterRenderAsync() { throw null; }
System.Threading.Tasks.Task Microsoft.AspNetCore.Components.IHandleEvent.HandleEventAsync(Microsoft.AspNetCore.Components.EventCallbackWorkItem callback, object arg) { throw null; }
protected virtual void OnAfterRender() { }
protected virtual System.Threading.Tasks.Task OnAfterRenderAsync() { throw null; }
protected virtual void OnInit() { }
protected virtual System.Threading.Tasks.Task OnInitAsync() { throw null; }
protected virtual void OnParametersSet() { }
protected virtual System.Threading.Tasks.Task OnParametersSetAsync() { throw null; }
public virtual System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterCollection parameters) { throw null; }
protected virtual bool ShouldRender() { throw null; }
protected void StateHasChanged() { }
}
public partial interface IComponent
{
void Configure(Microsoft.AspNetCore.Components.RenderHandle renderHandle);
System.Threading.Tasks.Task SetParametersAsync(Microsoft.AspNetCore.Components.ParameterCollection parameters);
}
public partial interface IComponentContext
{
bool IsConnected { get; }
}
public partial interface IHandleAfterRender
{
System.Threading.Tasks.Task OnAfterRenderAsync();
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct RenderHandle
{
private readonly object _dummy;
private readonly int _dummyPrimitive;
public bool IsInitialized { get { throw null; } }
public System.Threading.Tasks.Task Invoke(System.Action workItem) { throw null; }
public System.Threading.Tasks.Task InvokeAsync(System.Func<System.Threading.Tasks.Task> workItem) { throw null; }
public void Render(Microsoft.AspNetCore.Components.RenderFragment renderFragment) { }
}
}Some topics to discuss here:
- I don't feel great about the fact that
InvokeandInvokeAsyncare different method instead of overloads (here, onIDispatcherandRenderHandle). Should we have overloads ofInvokeandInvokeAsyncthat return something here as well?- Do we really want
OnInitvsOnInitialized? Abbreviations in APIs always feel bad to me, even if they are known things likeOnInit. Are we sure that it's worth providing sync and async versions of all of our lifecycle methods?SetParametersAsyncshould probably be an explicit implementation, the user cannot duplicate the behaviour of theComponentBaseimplementation, so it's not useful to override.We don't expose any lifecyle methods related toIHandleEvents(other thanShouldRender). That's probably ok? it could be done in the future.- Should we expose a property
HasRendered- basically provide some API for the common use case of initializing JS interop? -
RenderHandleseems to wear two hats. Should we pass the dispatcher into the component instead? - Is there a really good reason for
RenderHandleto be a struct? - I don't love
Configureas a name. Other ideas?
Events and EventCallback
namespace Microsoft.AspNetCore.Components
{
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public partial struct EventCallbackWorkItem
{
private object _dummy;
public static readonly Microsoft.AspNetCore.Components.EventCallbackWorkItem Empty;
public EventCallbackWorkItem(System.MulticastDelegate @delegate) { throw null; }
public System.Threading.Tasks.Task InvokeAsync(object arg) { throw null; }
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct EventCallback
{
private readonly object _dummy;
public static readonly Microsoft.AspNetCore.Components.EventCallback Empty;
public static readonly Microsoft.AspNetCore.Components.EventCallbackFactory Factory;
public EventCallback(Microsoft.AspNetCore.Components.IHandleEvent receiver, System.MulticastDelegate @delegate) { throw null; }
public bool HasDelegate { get { throw null; } }
public System.Threading.Tasks.Task InvokeAsync(object arg) { throw null; }
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct EventCallback<T>
{
private readonly object _dummy;
public EventCallback(Microsoft.AspNetCore.Components.IHandleEvent receiver, System.MulticastDelegate @delegate) { throw null; }
public bool HasDelegate { get { throw null; } }
public System.Threading.Tasks.Task InvokeAsync(T arg) { throw null; }
}
public partial interface IHandleEvent
{
System.Threading.Tasks.Task HandleEventAsync(Microsoft.AspNetCore.Components.EventCallbackWorkItem item, object arg);
}
public sealed partial class EventCallbackFactory
{
public EventCallbackFactory() { }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, Microsoft.AspNetCore.Components.EventCallback callback) { throw null; }
public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action callback) { throw null; }
public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Action<object> callback) { throw null; }
public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func<object, System.Threading.Tasks.Task> callback) { throw null; }
public Microsoft.AspNetCore.Components.EventCallback Create(object receiver, System.Func<System.Threading.Tasks.Task> callback) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public Microsoft.AspNetCore.Components.EventCallback<T> CreateInferred<T>(object receiver, System.Action<T> callback, T value) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public Microsoft.AspNetCore.Components.EventCallback<T> CreateInferred<T>(object receiver, System.Func<T, System.Threading.Tasks.Task> callback, T value) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public Microsoft.AspNetCore.Components.EventCallback<T> Create<T>(object receiver, Microsoft.AspNetCore.Components.EventCallback callback) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public Microsoft.AspNetCore.Components.EventCallback<T> Create<T>(object receiver, Microsoft.AspNetCore.Components.EventCallback<T> callback) { throw null; }
public Microsoft.AspNetCore.Components.EventCallback<T> Create<T>(object receiver, System.Action callback) { throw null; }
public Microsoft.AspNetCore.Components.EventCallback<T> Create<T>(object receiver, System.Action<T> callback) { throw null; }
public Microsoft.AspNetCore.Components.EventCallback<T> Create<T>(object receiver, System.Func<System.Threading.Tasks.Task> callback) { throw null; }
public Microsoft.AspNetCore.Components.EventCallback<T> Create<T>(object receiver, System.Func<T, System.Threading.Tasks.Task> callback) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public string Create<T>(object receiver, string callback) { throw null; }
}
public static partial class EventCallbackFactoryBinderExtensions
{
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<bool> setter, bool existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTime> setter, System.DateTime existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTime> setter, System.DateTime existingValue, string format) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<decimal> setter, decimal existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<double> setter, double existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<int> setter, int existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<long> setter, long existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<bool?> setter, bool? existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<System.DateTime?> setter, System.DateTime? existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<decimal?> setter, decimal? existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<double?> setter, double? existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<int?> setter, int? existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<long?> setter, long? existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<float?> setter, float? existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<float> setter, float existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<string> setter, string existingValue) { throw null; }
public static Microsoft.AspNetCore.Components.EventCallback<Microsoft.AspNetCore.Components.UIChangeEventArgs> CreateBinder<T>(this Microsoft.AspNetCore.Components.EventCallbackFactory factory, object receiver, System.Action<T> setter, T existingValue) { throw null; }
}
}Some topics to discuss here:
-
EventCallbackWorkItemshould be readonly. EventCallbackWorkItemis needed to keep the API from being insane due to generics, but I feel like it doesn't provide any useful information.ShouldEventCallbackandEventCallback<>have anInvokeAsync()method? It feels bad to pass null to the existing method.-
EventCallback<>should probably have anEmptymember for consistency. -
public string Create<T>(object receiver, string callback) { throw null; }should be removed. -
We decided to leaveEventCallbackFactoryBinderExtensions- we have a problem here. All of our existingbindfunctionality for elements is tied toUIChangeEventArgswhich is an HTML/DOM concept. I have no brilliant ideas what to do about this.UIChangeEventArgswhere it is for now.
Dispatcher
namespace Microsoft.AspNetCore.Components.Rendering
{
public partial interface IDispatcher
{
System.Threading.Tasks.Task Invoke(System.Action action);
System.Threading.Tasks.Task InvokeAsync(System.Func<System.Threading.Tasks.Task> asyncAction);
System.Threading.Tasks.Task<TResult> InvokeAsync<TResult>(System.Func<System.Threading.Tasks.Task<TResult>> asyncFunction);
System.Threading.Tasks.Task<TResult> Invoke<TResult>(System.Func<TResult> function);
}
}Some topics to discuss here:
- This should probably be an abstract class. We have a single implementation.
- We could also implement this on
ComponentBaseorRenderHandle(or both).
- We could also implement this on
- I don't love that these are different method names, but I'm not sure how to resolve the conflict between
Func<TResult>andFunc<Task>.
Parameters
namespace Microsoft.AspNetCore.Components
{
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct Parameter
{
private readonly object _dummy;
private readonly int _dummyPrimitive;
public bool Cascading { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public object Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct ParameterCollection
{
private readonly object _dummy;
private readonly int _dummyPrimitive;
public static Microsoft.AspNetCore.Components.ParameterCollection Empty { get { throw null; } }
public static Microsoft.AspNetCore.Components.ParameterCollection FromDictionary(System.Collections.Generic.IDictionary<string, object> parameters) { throw null; }
public Microsoft.AspNetCore.Components.ParameterEnumerator GetEnumerator() { throw null; }
public T GetValueOrDefault<T>(string parameterName) { throw null; }
public T GetValueOrDefault<T>(string parameterName, T defaultValue) { throw null; }
public System.Collections.Generic.IReadOnlyDictionary<string, object> ToDictionary() { throw null; }
public bool TryGetValue<T>(string parameterName, out T result) { throw null; }
}
public static partial class ParameterCollectionExtensions
{
public static void SetParameterProperties(this in Microsoft.AspNetCore.Components.ParameterCollection parameterCollection, object target) { }
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public partial struct ParameterEnumerator
{
private object _dummy;
private int _dummyPrimitive;
public Microsoft.AspNetCore.Components.Parameter Current { get { throw null; } }
public bool MoveNext() { throw null; }
}
}Some topics to discuss here:
- I'm still complaining about the name of this.
Parameteris reallyParameterStateorParameterValue. Low value, not doing.Cascading->IsCascadingValue?-
ParameterCollectiondoesn't implement any interfaces, this could easily implementIReadOnlyDictionary<>and then we don't needToDictionary(). edit we're renaming this instead. - It's extremely wierd that
SetParameterPropertiesis public, and extension method. This is OK, there is predendent for this in the BCLParameterEnumeratordoesn't implementIEnumerator.
Attributes
namespace Microsoft.AspNetCore.Components
{
[System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false, Inherited=false)]
public sealed partial class CascadingParameterAttribute : System.Attribute
{
public CascadingParameterAttribute() { }
public string Name { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false)]
public partial class InjectAttribute : System.Attribute
{
public InjectAttribute() { }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=true, Inherited=false)]
public partial class RouteAttribute : System.Attribute
{
public RouteAttribute(string template) { }
public string Template { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false, Inherited=false)]
public sealed partial class ParameterAttribute : System.Attribute
{
public ParameterAttribute() { }
public bool CaptureUnmatchedValues { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
}
}
namespace Microsoft.AspNetCore.Components.Layouts
{
[System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
public partial class LayoutAttribute : System.Attribute
{
public LayoutAttribute(System.Type layoutType) { }
public System.Type LayoutType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
}Some topics to discuss here:
- Make all of these sealed.
-
LayoutAttributeshould probably be in.Components -
Inherited = truefor all byRouteAttribute(which has a good reason to prevent inheritance)
Fundamental building blocks
namespace Microsoft.AspNetCore.Components
{
public delegate void RenderFragment(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder);
public delegate Microsoft.AspNetCore.Components.RenderFragment RenderFragment<T>(T value);
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct ElementRef
{
private readonly object _dummy;
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public string __internalId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct MarkupString
{
private readonly object _dummy;
public MarkupString(string value) { throw null; }
public string Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public static explicit operator Microsoft.AspNetCore.Components.MarkupString (string value) { throw null; }
public override string ToString() { throw null; }
}
}Some topics to discuss here:
- Should
ElementRefbeElementReference?
Metadata
Metadata
Assignees
Labels
DoneThis issue has been fixedThis issue has been fixedarea-blazorIncludes: Blazor, Razor ComponentsIncludes: Blazor, Razor Components