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

Features/support inheritance tree #12

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
5 changes: 3 additions & 2 deletions SignalR.Strong.Dynamic/SignalR.Strong.Dynamic.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Title>SignalR.Strong.Dynamic</Title>
<Description>Strongly-typed hub implementation for SignalR.Strong using dynamic proxies</Description>
<Version>0.3.0</Version>
<Version>0.3.1</Version>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
Expand All @@ -15,7 +15,8 @@
<ItemGroup>
<PackageReference Include="Castle.Core" Version="4.4.1" />
<PackageReference Include="Castle.Core.AsyncInterceptor" Version="1.7.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client.Core" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client.Core" Version="7.0.7" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
5 changes: 3 additions & 2 deletions SignalR.Strong.Expressive/SignalR.Strong.Expressive.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Title>SignalR.Strong.Expressive</Title>
<Description>Strongly-typed hub implementation for SignalR.Strong using expressions</Description>
<Version>0.3.0</Version>
<Version>0.3.1</Version>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client.Core" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client.Core" Version="7.0.7" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
9 changes: 9 additions & 0 deletions SignalR.Strong.Samples.Common/Hubs/IMockBase1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Threading.Tasks;

namespace SignalR.Strong.Samples.Common.Hubs
{
public interface IMockBase1 : IMockBase2
{
Task<string> Hello1(string name);
}
}
9 changes: 9 additions & 0 deletions SignalR.Strong.Samples.Common/Hubs/IMockBase2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Threading.Tasks;

namespace SignalR.Strong.Samples.Common.Hubs
{
public interface IMockBase2
{
Task<string> Hello2(string name);
}
}
3 changes: 2 additions & 1 deletion SignalR.Strong.Samples.Common/Hubs/IMockHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
// ReSharper disable PossibleInterfaceMemberAmbiguity

namespace SignalR.Strong.Samples.Common.Hubs
{
public interface IMockHub
public interface IMockHub : IMockBase1
{
Task<int> GetValueType();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client.Core" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client.Core" Version="7.0.7" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client.Core" Version="7.0.7" />
</ItemGroup>

</Project>
6 changes: 3 additions & 3 deletions SignalR.Strong.SourceGenerator/HubGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ public sealed class {typeName} : {hubSymbol.ToString()}
{{
this.conn = connection;
}}");

var members = hubSymbol.GetMembers()
var members = hubSymbol
.GetAllInterfaceMethods(true)
.Where(member => member.Kind == SymbolKind.Method)
.Select(member => (IMethodSymbol) member);
.Select(member => member);

foreach (var member in members)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
<NoPackageAnalysis>true</NoPackageAnalysis>
<Title>SignalR.Strong.SourceGenerator</Title>
<Description>Strongly-typed hub implementation for SignalR.Strong using source generators</Description>
<Version>0.3.3</Version>
<Version>0.3.4</Version>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
Expand Down
61 changes: 61 additions & 0 deletions SignalR.Strong.SourceGenerator/TypeSymbolExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
// ReSharper disable HeapView.BoxingAllocation
// ReSharper disable HeapView.DelegateAllocation

namespace SignalR.Strong.SourceGenerator
{
public static class TypeSymbolExtensions
{
public static IEnumerable<ITypeSymbol> GetAllInterfaces(this ITypeSymbol typeSymbol, bool includeTop = false)
=> Enumerable
.Repeat(typeSymbol, includeTop ? 1 : 0)
.Concat(typeSymbol.AllInterfaces)
.Where(symbol => symbol.TypeKind == TypeKind.Interface);

public static IEnumerable<IMethodSymbol> GetAllInterfaceMethods(this ITypeSymbol typeSymbol, bool includeTop = false)
{
if (typeSymbol == null) throw new ArgumentNullException(nameof(typeSymbol));

return typeSymbol
.GetAllInterfaces(includeTop)
.SelectMany(x => x.GetMembers())
.Where(x => x.Kind == SymbolKind.Method)
.Cast<IMethodSymbol>()
.GroupBy(x => x.Name)
.Preview(g =>
{
var byArity = g.GroupBy(x => x.Arity);
if (byArity.Count() > 1)
throw new NotSupportedException(
$"Not Supported Overloaded Methods with the same name \"{g.Key}\""
);
})
.Select(g =>
{
return g.Aggregate((a, b) =>
{
if (a.Equals(b, SymbolEqualityComparer.Default))
throw new NotSupportedException(
$"Not Supported Overloaded Methods with the same name \"{g.Key}\" and different signatures"
);
return a;
});
});
}

private static IEnumerable<T> Preview<T>(this IEnumerable<T> items, Action<T> onItem)
{
if (items == null) throw new ArgumentNullException(nameof(items));
if (onItem == null) throw new ArgumentNullException(nameof(onItem));

return items.Select(item =>
{
onItem(item);
return item;
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@
<Configuration>Release</Configuration>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.0" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
<PackageReference Include="BenchmarkDotNet.Annotations" Version="0.13.5" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.12.0" />
<PackageReference Include="System.Text.Encodings.Web" Version="5.0.0" />
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
<PackageReference Include="System.Text.Encodings.Web" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SignalR.Strong.Samples.Common\SignalR.Strong.Samples.Common.csproj" />
Expand Down
10 changes: 10 additions & 0 deletions SignalR.Strong.Tests.Common/MockHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,5 +241,15 @@ public Task SetChannel(ChannelReader<int> reader)
{
return Task.CompletedTask;
}

public Task<string> Hello2(string name)
{
return Task.FromResult($"[2] Hello, {name}!");
}

public Task<string> Hello1(string name)
{
return Task.FromResult($"[1] Hello, {name}!");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client.Core" Version="7.0.7" />
</ItemGroup>

<ItemGroup>
Expand Down
20 changes: 16 additions & 4 deletions SignalR.Strong.Tests.xUnit/SignalR.Strong.Tests.xUnit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,29 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
<PackageReference Include="BenchmarkDotNet.Annotations" Version="0.13.5" />
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="coverlet.msbuild" Version="2.9.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="5.4.2" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.Json" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="5.0.1" />
<PackageReference Include="Iced" Version="1.19.0" />
<PackageReference Include="MessagePack" Version="2.5.108" />
<PackageReference Include="MessagePack.Annotations" Version="2.5.108" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.Json" Version="7.0.7" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="7.0.7" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
<PackageReference Include="Moq" Version="4.15.2" />
<PackageReference Include="System.Text.Encodings.Web" Version="5.0.0" />
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
<PackageReference Include="System.Text.Encodings.Web" Version="7.0.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion SignalR.Strong/HubConnectionExtensions.RegisterSpoke.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace SignalR.Strong
{
public static partial class HubConnectionExtensionsSpokes
public static class HubConnectionExtensionsSpokes
{
public static SpokeRegistration RegisterSpoke(this HubConnection conn, object spoke, Type intfType = null)
{
Expand Down
63 changes: 63 additions & 0 deletions SignalR.Strong/HubConnectionSpokes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Collections.Concurrent;
using System.Reflection;
using Microsoft.AspNetCore.SignalR.Client;
using SignalR.Strong.IoC;

// ReSharper disable HeapView.PossibleBoxingAllocation
// ReSharper disable HeapView.ObjectAllocation.Evident
// ReSharper disable UnusedType.Global
// ReSharper disable ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
// ReSharper disable HeapView.DelegateAllocation
// ReSharper disable HeapView.ClosureAllocation
// ReSharper disable SuggestBaseTypeForParameter
// ReSharper disable UnusedTypeParameter
// ReSharper disable UnusedMember.Global
// ReSharper disable InvertIf

namespace SignalR.Strong
{
/// <inheritdoc/>
public sealed class HubConnectionSpokes
: IHubConnectionSpokes
{
private readonly ConcurrentBag<IDisposable> _disconnectors = new ConcurrentBag<IDisposable>();
private readonly IServiceProvider _services;

/// <summary>
/// Constructs registration container that manages <see cref="HubConnection"/>-connected
/// spokes (<see cref="HubConnection"/> incoming event handlers).
/// </summary>
/// <param name="services">IoC <see cref="IServiceProvider"/></param>
/// <exception cref="ArgumentNullException">
/// Throws is <see cref="IServiceProvider"/> services is null
/// </exception>
public HubConnectionSpokes(IServiceProvider services)
=> _services = services ?? throw new ArgumentNullException(nameof(services));

/// <inheritdoc/>
public IHubConnectionSpokes AddSpoke<TSpoke>(HubConnection connection)
{
var methods = typeof(TSpoke)
.GetMethods(BindingFlags.Instance | BindingFlags.Public);

foreach (var method in methods)
{
connection.ListenWith<TSpoke>(_services, method, _disconnectors.Add);
}

return this;
}

/// <summary>
/// Dispose and clean up all registrations
/// </summary>
public void Dispose()
{
while (_disconnectors.TryTake(out var disconnector))
{
disconnector.Dispose();
}
}
}
}
22 changes: 22 additions & 0 deletions SignalR.Strong/IHubConnectionSpokes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using Microsoft.AspNetCore.SignalR.Client;
// ReSharper disable UnusedMember.Global

namespace SignalR.Strong
{
/// <summary>
/// Spokes on the <see cref="HubConnection"/> interface
/// </summary>
public interface IHubConnectionSpokes
: IDisposable
{
/// <summary>
/// Configure dependency-injected Spoke to handle HubConnection events
/// </summary>
/// <param name="connection"><see cref="HubConnection"/></param>
/// <typeparam name="TSpoke">Spoke type to be used</typeparam>
/// <returns>Returns this to chain calls</returns>
/// <exception cref="ArgumentNullException">Throws if <see cref="HubConnection"/> connection is null</exception>
IHubConnectionSpokes AddSpoke<TSpoke>(HubConnection connection);
}
}
32 changes: 32 additions & 0 deletions SignalR.Strong/IoC/HubConnectionListenerDSLs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.SignalR.Client;

namespace SignalR.Strong.IoC
{
internal static class HubConnectionListenerDSLs
{
public static void ListenWith<TSpoke>(
this HubConnection connection,
IServiceProvider services,
MethodInfo method,
Action<IDisposable> registerDisconnector
)
{
var listenerBuilderType = typeof(ListenerBuilderImpl<,>)
.MakeGenericType(typeof(TSpoke), method.ReturnType);
var listenerBuilder = (IListenerBuilder)Activator
.CreateInstance(listenerBuilderType);

var parameterTypes = method
.GetParameters()
.Select(a => a.ParameterType)
.ToArray();

var disconnector = listenerBuilder
.Build(services, connection, method, parameterTypes);
registerDisconnector(disconnector);
}
}
}
Loading