Skip to content

Commit

Permalink
Merge pull request #136 from TimeWarpEngineering/Cramer-2019-05-15
Browse files Browse the repository at this point in the history
Implement IDisposable on BaseComponent
  • Loading branch information
StevenTCramer authored Jun 4, 2019
2 parents a98f50b + 5936495 commit f6881ae
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 37 deletions.
24 changes: 13 additions & 11 deletions Documentation/TemplateOverview.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
## TimeWarp-Blazor Template
# TimeWarp-Blazor Template

### Installation
## Installation

```
```console
dotnet new --install TimeWarp.AspNetCore.Blazor.Templates
```

### Usage
## Usage

```
```console
dotnet new timewarp-blazor -n MyBlazorApp
```

### Projects
MyBlazorApp.Client<br/>
MyBlazorApp.Server<br/>
## Projects

MyBlazorApp.Client
MyBlazorApp.Server
MyBlazorApp.Shared

### Test Projects
MyBlazorApp.Client.Integration.Tests<br/>
MyBlazorApp.Server.Integration.Tests<br/>
## Test Projects

MyBlazorApp.Client.Integration.Tests
MyBlazorApp.Server.Integration.Tests
MyBlazorApp.EndToEnd.Tests
4 changes: 3 additions & 1 deletion source/BlazorState/Components/BlazorStateComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/// And exposes StateHasChanged
/// </summary>
/// <remarks>Implements IBlazorStateComponent by Injecting</remarks>
public class BlazorStateComponent : ComponentBase,
public class BlazorStateComponent : ComponentBase, IDisposable,
IBlazorStateComponent
{
static readonly ConcurrentDictionary<string, int> s_InstanceCounts = new ConcurrentDictionary<string, int>();
Expand Down Expand Up @@ -59,5 +59,7 @@ protected T GetState<T>()
Subscriptions.Add(stateType, this);
return Store.GetState<T>();
}

public void Dispose() => Subscriptions.Remove(this);
}
}
86 changes: 61 additions & 25 deletions source/BlazorState/Subscriptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,41 @@
{
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;

public class Subscriptions
{
private readonly struct Subscription : IEquatable<Subscription>
{
public Subscription(Type aStateType, string aComponentId, WeakReference<BlazorStateComponent> aBlazorStateComponentReference)
{
StateType = aStateType;
ComponentId = aComponentId;
BlazorStateComponentReference = aBlazorStateComponentReference;
}

public Type StateType { get; }
public string ComponentId { get; }
public WeakReference<BlazorStateComponent> BlazorStateComponentReference { get; }

public bool Equals(Subscription aSubscription) =>
EqualityComparer<Type>.Default.Equals(StateType, aSubscription.StateType) &&
ComponentId == aSubscription.ComponentId &&
EqualityComparer<WeakReference<BlazorStateComponent>>.Default.Equals(BlazorStateComponentReference, aSubscription.BlazorStateComponentReference);

public static bool operator ==(Subscription aLeftSubscription, Subscription aRightSubscription) => aLeftSubscription.Equals(aRightSubscription);
public static bool operator !=(Subscription aLeftSubscription, Subscription aRightSubscription) => !(aLeftSubscription == aRightSubscription);
}

public Subscriptions(ILogger<Subscriptions> aLogger)
{
Logger = aLogger;
BlazorStateComponentReferencesDictionary = new Dictionary<Type, List<WeakReference<BlazorStateComponent>>>();
BlazorStateComponentReferencesList = new List<Subscription>();
}

private ILogger Logger { get; }
private Dictionary<Type, List<WeakReference<BlazorStateComponent>>> BlazorStateComponentReferencesDictionary { get; }
private List<Subscription> BlazorStateComponentReferencesList { get; }

public Subscriptions Add<T>(BlazorStateComponent aBlazorStateComponent)
{
Expand All @@ -23,18 +46,27 @@ public Subscriptions Add<T>(BlazorStateComponent aBlazorStateComponent)
}
public Subscriptions Add(Type aType, BlazorStateComponent aBlazorStateComponent)
{

if (!(BlazorStateComponentReferencesDictionary.TryGetValue(aType, out List<WeakReference<BlazorStateComponent>> blazorStateComponentReferences)))
// Add only once.
if (!BlazorStateComponentReferencesList.Any(aSubscription => aSubscription.StateType == aType && aSubscription.ComponentId == aBlazorStateComponent.Id))
{
blazorStateComponentReferences = new List<WeakReference<BlazorStateComponent>>();
BlazorStateComponentReferencesDictionary.Add(aType, blazorStateComponentReferences);
}
var subscription = new Subscription(
aType,
aBlazorStateComponent.Id,
new WeakReference<BlazorStateComponent>(aBlazorStateComponent));

blazorStateComponentReferences.Add(new WeakReference<BlazorStateComponent>(aBlazorStateComponent));
BlazorStateComponentReferencesList.Add(subscription);
}

return this;
}

public Subscriptions Remove(BlazorStateComponent aBlazorStateComponent)
{
Logger.LogDebug($"Removing Subscription for {aBlazorStateComponent.Id}");
BlazorStateComponentReferencesList.RemoveAll(aRecord => aRecord.ComponentId == aBlazorStateComponent.Id);

return this;
}
/// <summary>
/// Will iterate over all subscriptions for the given type and call ReRender on each.
/// If the target component no longer exists it will remove its subscription.
Expand All @@ -54,27 +86,31 @@ public void ReRenderSubscribers<T>()
/// <param name="aType"></param>
public void ReRenderSubscribers(Type aType)
{
//GC.Collect(); // I added the collect to test that I am not holding strong references and they were collected.
bool isAny = BlazorStateComponentReferencesDictionary.TryGetValue(aType, out List<WeakReference<BlazorStateComponent>> blazorStateblazorStateComponentReferencesComponents);
if (isAny)
IEnumerable<Subscription> subscriptions = BlazorStateComponentReferencesList.Where(aRecord => aRecord.StateType == aType);
foreach (Subscription subscription in subscriptions)
{
Logger.LogDebug($"ReRendering {blazorStateblazorStateComponentReferencesComponents.Count} Subscribers for state of type: {aType.Name}");
WeakReference<BlazorStateComponent>[] blazorStateComponentReferencesArray = blazorStateblazorStateComponentReferencesComponents.ToArray();

foreach (WeakReference<BlazorStateComponent> aBlazorStateComponentReference in blazorStateComponentReferencesArray)
if (subscription.BlazorStateComponentReference.TryGetTarget(out BlazorStateComponent target))
{
if (aBlazorStateComponentReference.TryGetTarget(out BlazorStateComponent target))
{
Logger.LogDebug($"ReRender: {target.GetType().Name}");
target.ReRender();
}
else
{
Logger.LogDebug($"Removing subscription to previously destroyed component.");
blazorStateblazorStateComponentReferencesComponents.Remove(aBlazorStateComponentReference);
}
Logger.LogDebug($"ReRender: {target.GetType().Name}");
target.ReRender();
}
else
{
// If Dispose is called will I ever have items in this list that got Garbage collected?
// Maybe for those that don't inherit from our BaseComponent.
BlazorStateComponentReferencesList.Remove(subscription);
}
}
}

public override bool Equals(object obj) => obj is Subscriptions subscriptions && EqualityComparer<ILogger>.Default.Equals(Logger, subscriptions.Logger) && EqualityComparer<List<Subscription>>.Default.Equals(BlazorStateComponentReferencesList, subscriptions.BlazorStateComponentReferencesList);

public override int GetHashCode()
{
var hashCode = -914156548;
hashCode = hashCode * -1521134295 + EqualityComparer<ILogger>.Default.GetHashCode(Logger);
hashCode = hashCode * -1521134295 + EqualityComparer<List<Subscription>>.Default.GetHashCode(BlazorStateComponentReferencesList);
return hashCode;
}
}
}

0 comments on commit f6881ae

Please sign in to comment.