Skip to content
Draft
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
660 changes: 660 additions & 0 deletions src/Components/Components.sln

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions src/Components/Components/src/ITempData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.AspNetCore.Components;

/// <summary>
/// Provides a dictionary for storing data that is needed for subsequent requests.
/// Data stored in TempData is automatically removed after it is read unless
/// <see cref="Keep()"/> or <see cref="Keep(string)"/> is called, or it is accessed via <see cref="Peek(string)"/>.
/// </summary>
public interface ITempData : IDictionary<string, object?>
{
/// <summary>
/// Gets the value associated with the specified key and then schedules it for deletion.
/// </summary>
object? Get(string key);

/// <summary>
/// Gets the value associated with the specified key without scheduling it for deletion.
/// </summary>
object? Peek(string key);

/// <summary>
/// Makes all of the keys currently in TempData persist for another request.
/// </summary>
void Keep();

/// <summary>
/// Makes the element with the <paramref name="key"/> persist for another request.
/// </summary>
void Keep(string key);
}
18 changes: 18 additions & 0 deletions src/Components/Components/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
#nullable enable
Microsoft.AspNetCore.Components.ITempData
Microsoft.AspNetCore.Components.ITempData.Get(string! key) -> object?
Microsoft.AspNetCore.Components.ITempData.Keep() -> void
Microsoft.AspNetCore.Components.ITempData.Keep(string! key) -> void
Microsoft.AspNetCore.Components.ITempData.Peek(string! key) -> object?
Microsoft.AspNetCore.Components.TempData
Microsoft.AspNetCore.Components.TempData.TempData() -> void
Microsoft.AspNetCore.Components.TempData.Get(string! key) -> object?
Microsoft.AspNetCore.Components.TempData.this[string! key].get -> object?
Microsoft.AspNetCore.Components.TempData.this[string! key].set -> void
Microsoft.AspNetCore.Components.TempData.Keep() -> void
Microsoft.AspNetCore.Components.TempData.Keep(string! key) -> void
Microsoft.AspNetCore.Components.TempData.Peek(string! key) -> object?
Microsoft.AspNetCore.Components.TempData.Clear() -> void
Microsoft.AspNetCore.Components.TempData.Remove(string! key) -> bool
Microsoft.AspNetCore.Components.TempData.ContainsKey(string! key) -> bool
Microsoft.AspNetCore.Components.TempData.Load(System.Collections.Generic.IDictionary<string!, object?>! data) -> void
Microsoft.AspNetCore.Components.TempData.Save() -> System.Collections.Generic.IDictionary<string!, object?>!
*REMOVED*Microsoft.AspNetCore.Components.ResourceAsset.ResourceAsset(string! url, System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Components.ResourceAssetProperty!>? properties) -> void
*REMOVED*Microsoft.AspNetCore.Components.Routing.Router.PreferExactMatches.get -> bool
*REMOVED*Microsoft.AspNetCore.Components.Routing.Router.PreferExactMatches.set -> void
184 changes: 184 additions & 0 deletions src/Components/Components/src/TempData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;

namespace Microsoft.AspNetCore.Components;

/// <inheritdoc/>
public class TempData : ITempData
{
private readonly Dictionary<string, object?> _data = new(StringComparer.OrdinalIgnoreCase);
private readonly HashSet<string> _retainedKeys = new(StringComparer.OrdinalIgnoreCase);

/// <inheritdoc/>
public object? this[string key]
{
get => Get(key);
set
{
_data[key] = value;
_retainedKeys.Add(key);
}
}

/// <inheritdoc/>
public object? Get(string key)
{
_retainedKeys.Remove(key);
return _data.GetValueOrDefault(key);
}

/// <inheritdoc/>
public object? Peek(string key)
{
return _data.GetValueOrDefault(key);
}

/// <inheritdoc/>
public void Keep()
{
_retainedKeys.Clear();
_retainedKeys.UnionWith(_data.Keys);
}

/// <inheritdoc/>
public void Keep(string key)
{
if (_data.ContainsKey(key))
{
_retainedKeys.Add(key);
}
}

/// <inheritdoc/>
public bool ContainsKey(string key)
{
return _data.ContainsKey(key);
}

/// <inheritdoc/>
public bool Remove(string key)
{
_retainedKeys.Remove(key);
return _data.Remove(key);
}

/// <summary>
/// Gets the data that should be saved for the next request.
/// </summary>
public IDictionary<string, object?> Save()
{
var dataToSave = new Dictionary<string, object?>();
foreach (var key in _retainedKeys)
{
dataToSave[key] = _data[key];
}
return dataToSave;
}

/// <summary>
/// Loads data from a <paramref name="data"/> into the TempData dictionary.
/// </summary>
public void Load(IDictionary<string, object?> data)
{
_data.Clear();
_retainedKeys.Clear();
foreach (var kvp in data)
{
_data[kvp.Key] = kvp.Value;
_retainedKeys.Add(kvp.Key);
}
}

/// <inheritdoc/>
public void Clear()
{
_data.Clear();
_retainedKeys.Clear();
}

ICollection<string> IDictionary<string, object?>.Keys => _data.Keys;

ICollection<object?> IDictionary<string, object?>.Values => _data.Values;

int ICollection<KeyValuePair<string, object?>>.Count => _data.Count;

bool ICollection<KeyValuePair<string, object?>>.IsReadOnly => ((ICollection<KeyValuePair<string, object?>>)_data).IsReadOnly;

void IDictionary<string, object?>.Add(string key, object? value)
{
_data.Add(key, value);
_retainedKeys.Add(key);
}

bool IDictionary<string, object?>.TryGetValue(string key, out object? value)
{
_retainedKeys.Remove(key);
return _data.TryGetValue(key, out value);
}

void ICollection<KeyValuePair<string, object?>>.Add(KeyValuePair<string, object?> item)
{
((IDictionary<string, object?>)this).Add(item.Key, item.Value);
}

bool ICollection<KeyValuePair<string, object?>>.Contains(KeyValuePair<string, object?> item)
{
return ContainsKey(item.Key) && _data[item.Key] == item.Value;
}

void ICollection<KeyValuePair<string, object?>>.CopyTo(KeyValuePair<string, object?>[] array, int arrayIndex)
{
((ICollection<KeyValuePair<string, object?>>)_data).CopyTo(array, arrayIndex);
}

bool ICollection<KeyValuePair<string, object?>>.Remove(KeyValuePair<string, object?> item)
{
if (((ICollection<KeyValuePair<string, object?>>)_data).Remove(item))
{
_retainedKeys.Remove(item.Key);
return true;
}
return false;
}

IEnumerator<KeyValuePair<string, object?>> IEnumerable<KeyValuePair<string, object?>>.GetEnumerator()
{
return new TempDataEnumerator(this);
}

IEnumerator IEnumerable.GetEnumerator()
{
return new TempDataEnumerator(this);
}

class TempDataEnumerator : IEnumerator<KeyValuePair<string, object?>>
{
private readonly IEnumerator<KeyValuePair<string, object?>> _innerEnumerator;

public TempDataEnumerator(TempData tempData)
{
_innerEnumerator = tempData._data.GetEnumerator();
}

public KeyValuePair<string, object?> Current => _innerEnumerator.Current;

object IEnumerator.Current => _innerEnumerator.Current;

public void Dispose()
{
_innerEnumerator.Dispose();
}

public bool MoveNext()
{
return _innerEnumerator.MoveNext();
}

public void Reset()
{
_innerEnumerator.Reset();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,26 @@ public static IRazorComponentsBuilder AddRazorComponents(this IServiceCollection
services.TryAddCascadingValue(sp => sp.GetRequiredService<EndpointHtmlRenderer>().HttpContext);
services.TryAddScoped<WebAssemblySettingsEmitter>();
services.TryAddScoped<ResourcePreloadService>();
services.TryAddCascadingValue(sp =>
{
var httpContext = sp.GetRequiredService<EndpointHtmlRenderer>().HttpContext;
if (httpContext is null)
{
return null!;
}
var key = typeof(ITempData);
if (!httpContext.Items.TryGetValue(key, out var tempData))
{
var tempDataInstance = TempDataService.Load(httpContext);
httpContext.Items[key] = tempDataInstance;
httpContext.Response.OnStarting(() =>
{
TempDataService.Save(httpContext, tempDataInstance);
return Task.CompletedTask;
});
}
return (ITempData)httpContext.Items[key]!;
});

services.TryAddScoped<ResourceCollectionProvider>();
RegisterPersistentComponentStateServiceCollectionExtensions.AddPersistentServiceRegistration<ResourceCollectionProvider>(services, RenderMode.InteractiveWebAssembly);
Expand Down
Loading