Skip to content

Commit 1baa3c3

Browse files
author
Meir Kriheli
committed
disallow usage of both [Service] and [ServiceInheritable]
in service binder and in schema generator. Exception will be thrown. + unit tests.
1 parent 25ce071 commit 1baa3c3

File tree

5 files changed

+76
-4
lines changed

5 files changed

+76
-4
lines changed

src/protobuf-net.Grpc.Reflection/SchemaGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ static Type ApplySubstitutes(Type type)
139139

140140
private static MethodInfo[] GetMethodsRecursively(ServiceBinder serviceBinder, Type contractType)
141141
{
142-
var includingInheritedInterfaces = ContractOperation.ExpandWithInterfacesMarkedAsServiceInheritable(contractType);
142+
var includingInheritedInterfaces = ContractOperation.ExpandWithInterfacesMarkedAsServiceInheritable(serviceBinder, contractType);
143143

144144
var inheritedMethods = includingInheritedInterfaces
145145
.SelectMany(t => t.GetMethods(BindingFlags.Public | BindingFlags.Instance))

src/protobuf-net.Grpc/Configuration/ServerBinder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public int Bind(object state, Type serviceType, BinderConfiguration? binderConfi
5252
var serviceContract = potentialServiceContract;
5353

5454
var typesToBeIncludedInMethodsBinding =
55-
ContractOperation.ExpandWithInterfacesMarkedAsServiceInheritable(serviceContract);
55+
ContractOperation.ExpandWithInterfacesMarkedAsServiceInheritable(binderConfiguration.Binder, serviceContract);
5656

5757
// Per service contract, we will collect all the methods of inherited interfaces
5858
// and bind them as they were defined in the service contract itself.

src/protobuf-net.Grpc/Internal/ContractOperation.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,13 +363,15 @@ internal static ISet<Type> ExpandInterfaces(Type type)
363363
if (type.IsInterface) set.Add(type);
364364
return set;
365365
}
366-
366+
367367
/// <summary>
368368
/// Collect all the types to be used for extracting methods for a specific Service Contract
369369
/// </summary>
370+
/// <param name="serviceBinder"></param>
370371
/// <param name="serviceContract">Must be a service contract</param>
371372
/// <returns>types to be used for extracting methods</returns>
372-
internal static ISet<Type> ExpandWithInterfacesMarkedAsServiceInheritable(Type serviceContract)
373+
internal static ISet<Type> ExpandWithInterfacesMarkedAsServiceInheritable(ServiceBinder serviceBinder,
374+
Type serviceContract)
373375
{
374376
var set = new HashSet<Type>();
375377

@@ -384,8 +386,24 @@ internal static ISet<Type> ExpandWithInterfacesMarkedAsServiceInheritable(Type s
384386
set.Add(t);
385387
}
386388
}
389+
390+
ValidateServiceContracts(serviceBinder, set);
387391
return set;
388392
}
393+
394+
private static void ValidateServiceContracts(ServiceBinder serviceBinder, HashSet<Type> set)
395+
{
396+
foreach (var item in set)
397+
{
398+
if (item.IsDefined(typeof(ServiceInheritableAttribute)))
399+
{
400+
if (serviceBinder.IsServiceContract(item, out var serviceName))
401+
throw new ArgumentException(
402+
$"Bad definition for service {serviceName}: " +
403+
$"A service contract cannot be marked as a service inheritable as well");
404+
}
405+
}
406+
}
389407
}
390408

391409
internal enum ContextKind

tests/protobuf-net.Grpc.Reflection.Test/SchemaGeneration.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,21 @@ public void WhenClassIsNotServiceContract_Throw()
324324
Assert.Throws<ArgumentException>(activation.Invoke);
325325
}
326326

327+
328+
[Service]
329+
[ServiceInheritable]
330+
public interface IIServiceWithBothServiceAndServiceInheritableAttributes
331+
{
332+
void SomeMethod();
333+
}
334+
[Fact]
335+
public void WhenInterfaceHasAttributesServiceAndServiceInheritable_Throw()
336+
{
337+
var generator = new SchemaGenerator();
338+
Action activation = () => generator.GetSchema<IIServiceWithBothServiceAndServiceInheritableAttributes>();
339+
Assert.Throws<ArgumentException>(activation.Invoke);
340+
}
341+
327342
[Service]
328343
public interface ISimpleService1
329344
{

tests/protobuf-net.Grpc.Test/ContractOperationTests.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,45 @@ public void CheckAllMethodsCovered()
8282

8383
Assert.Empty(expected);
8484
}
85+
86+
87+
[Service]
88+
[ServiceInheritable]
89+
public interface IIServiceWithBothServiceAndServiceInheritableAttributes
90+
{
91+
void SomeMethod();
92+
}
93+
94+
[Fact]
95+
public void WhenInterfaceHasAttributesServiceAndServiceInheritable_Throw()
96+
{
97+
var config = BinderConfiguration.Default;
98+
Action activation = () => ContractOperation.ExpandWithInterfacesMarkedAsServiceInheritable(
99+
config.Binder,
100+
typeof(IIServiceWithBothServiceAndServiceInheritableAttributes));
101+
Assert.Throws<ArgumentException>(activation.Invoke);
102+
}
103+
104+
public class ServiceContractClassInheritsServiceAndServiceInheritableAttributes
105+
: IIServiceWithBothServiceAndServiceInheritableAttributes, IGrpcService
106+
{
107+
public void SomeMethod()
108+
{
109+
}
110+
}
111+
112+
[Fact]
113+
public void WhenServiceContractClassImplementsInterfaceHavingAttributesServiceAndServiceInheritable_Throw()
114+
{
115+
var config = BinderConfiguration.Default;
116+
Action activation = () => ContractOperation.ExpandWithInterfacesMarkedAsServiceInheritable(
117+
config.Binder,
118+
typeof(ServiceContractClassInheritsServiceAndServiceInheritableAttributes));
119+
Assert.Throws<ArgumentException>(activation.Invoke);
120+
}
121+
122+
123+
85124
#pragma warning disable CS0618 // Empty
86125
[Theory]
87126
[InlineData(nameof(IAllOptions.Client_AsyncUnary), typeof(HelloRequest), typeof(HelloReply), MethodType.Unary, (int)ContextKind.CallOptions, (int)ResultKind.Grpc, (int)VoidKind.None)]

0 commit comments

Comments
 (0)