Skip to content

Commit

Permalink
Merge pull request #652 from rruizGit/dev/rruiz/pr637
Browse files Browse the repository at this point in the history
AddLocalRpcTarget<T> should honor base interfaces when T is an interface
  • Loading branch information
AArnott authored Apr 24, 2021
2 parents aa2f836 + 23d7e71 commit b664ca8
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 4 deletions.
22 changes: 21 additions & 1 deletion src/StreamJsonRpc/Reflection/RpcTargetInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,27 @@ private static IReadOnlyDictionary<string, List<MethodSignature>> GetRequestMeth

MethodNameMap mapping = GetMethodNameMap(exposedMembersOnType);

for (TypeInfo? t = exposedMembersOnType; t != null && t != typeof(object).GetTypeInfo(); t = t.BaseType?.GetTypeInfo())
// We retrieve exposed types differently for interfaces vs. classes
var typesToMap = new List<TypeInfo>();
if (exposedMembersOnType.IsInterface)
{
Type[] ifaces = exposedMembersOnType.GetInterfaces();
typesToMap.Capacity = 1 + ifaces.Length;
typesToMap.Add(exposedMembersOnType.GetTypeInfo());
foreach (Type iface in ifaces)
{
typesToMap.Add(iface.GetTypeInfo());
}
}
else
{
for (TypeInfo? t = exposedMembersOnType.GetTypeInfo(); t != null && t != typeof(object).GetTypeInfo(); t = t.BaseType?.GetTypeInfo())
{
typesToMap.Add(t);
}
}

foreach (TypeInfo t in typesToMap)
{
// As we enumerate methods, skip accessor methods
foreach (MethodInfo method in t.DeclaredMethods.Where(m => !m.IsSpecialName))
Expand Down
15 changes: 12 additions & 3 deletions test/StreamJsonRpc.Tests/JsonRpcTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ private interface IServer
int Add_ExplicitInterfaceImplementation(int a, int b);
}

private interface IServerDerived : IServer
{
bool MethodOnDerived();
}

[Fact]
public async Task AddLocalRpcTarget_OfT_InterfaceOnly()
{
Expand All @@ -101,14 +106,15 @@ public async Task AddLocalRpcTarget_OfT_InterfaceOnly()
this.InitializeFormattersAndHandlers();

this.serverRpc = new JsonRpc(this.serverMessageHandler);
this.serverRpc.AddLocalRpcTarget<IServer>(this.server, null);
this.serverRpc.AddLocalRpcTarget<IServerDerived>(this.server, null);
this.serverRpc.StartListening();

this.clientRpc = new JsonRpc(this.clientMessageHandler);
this.clientRpc.StartListening();

// Verify that members on the interface are callable.
// Verify that members on the interface and base interfaces are callable.
await this.clientRpc.InvokeAsync("AnotherName", new object[] { "my -name" });
await this.clientRpc.InvokeAsync(nameof(IServerDerived.MethodOnDerived));

// Verify that explicitly interface implementations of members on the interface are callable.
Assert.Equal(3, await this.clientRpc.InvokeAsync<int>(nameof(IServer.Add_ExplicitInterfaceImplementation), 1, 2));
Expand Down Expand Up @@ -136,6 +142,7 @@ public async Task AddLocalRpcTarget_OfT_ActualClass()

// Verify that public members on the class (and NOT the interface) are callable.
await this.clientRpc.InvokeAsync(nameof(Server.AsyncMethod), new object[] { "my-name" });
await this.clientRpc.InvokeAsync(nameof(BaseClass.BaseMethod));

// Verify that explicitly interface implementations of members on the interface are NOT callable.
await Assert.ThrowsAsync<RemoteMethodNotFoundException>(() => this.clientRpc.InvokeAsync<int>(nameof(IServer.Add_ExplicitInterfaceImplementation), 1, 2));
Expand Down Expand Up @@ -2786,7 +2793,7 @@ public class BaseClass
}

#pragma warning disable CA1801 // use all parameters
public class Server : BaseClass, IServer
public class Server : BaseClass, IServerDerived
{
internal const string ExceptionMessage = "some message";
internal const string ThrowAfterCancellationMessage = "Throw after cancellation";
Expand Down Expand Up @@ -3271,6 +3278,8 @@ public void SendException(Exception? ex)

public string? GetTraceState(bool useCorrelationManager) => useCorrelationManager ? CorrelationManagerTracingStrategy.TraceState : Activity.Current?.TraceStateString;

public bool MethodOnDerived() => true;

int IServer.Add_ExplicitInterfaceImplementation(int a, int b) => a + b;

internal void InternalMethod()
Expand Down

0 comments on commit b664ca8

Please sign in to comment.