Skip to content

Commit

Permalink
Issue 121 - Possible ImplementationMapper for .netCore
Browse files Browse the repository at this point in the history
  • Loading branch information
Euan-McVie committed Aug 7, 2020
1 parent 6741922 commit 8b9ca9c
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 14 deletions.
3 changes: 2 additions & 1 deletion examples/pb-net-grpc/Server_CS/MyCalculator.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Shared_CS;

namespace Services_CS
{
//[Authorize]
[Authorize]
public class MyCalculator : ICalculator
{
private int counter = 0;
Expand Down
4 changes: 2 additions & 2 deletions examples/pb-net-grpc/Server_CS/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment _)

app.UseEndpoints(endpoints =>
{
//endpoints.MapGrpcService<ICalculator>();
endpoints.MapGrpcService<MyCalculator>();
endpoints.MapGrpcService<ICalculator>();
//endpoints.MapGrpcService<MyCalculator>();
endpoints.MapGrpcService<MyTimeService>();
});
}
Expand Down
33 changes: 28 additions & 5 deletions src/protobuf-net.Grpc.AspNetCore/ServicesExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using Grpc.AspNetCore.Server;
using System;
using System.Linq;
using Grpc.AspNetCore.Server;
using Grpc.AspNetCore.Server.Model;
using Grpc.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using ProtoBuf.Grpc.Configuration;
using System;

namespace ProtoBuf.Grpc.Server
{
Expand All @@ -25,23 +26,45 @@ public static class ServicesExtensions
public static IGrpcServerBuilder AddCodeFirstGrpc(this IServiceCollection services, Action<GrpcServiceOptions>? configureOptions)
{
var builder = configureOptions == null ? services.AddGrpc() : services.AddGrpc(configureOptions);
services.TryAddSingleton<IServiceImplementationMapper>(_ => new DependencyInjectionMapper(services));
services.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IServiceMethodProvider<>), typeof(CodeFirstServiceMethodProvider<>)));
return builder;
}

private sealed class DependencyInjectionMapper : IServiceImplementationMapper
{
private readonly IServiceCollection _serviceCollection;

public DependencyInjectionMapper(IServiceCollection serviceCollection)
{
_serviceCollection = serviceCollection;
}

public Type Map(Type serviceType)
{
if (!serviceType.IsInterface)
return serviceType;

var serviceImplementationType = _serviceCollection.SingleOrDefault(x => x.ServiceType == serviceType);
return (serviceImplementationType is null) ? serviceType : serviceImplementationType.ImplementationType;
}
}

private sealed class CodeFirstServiceMethodProvider<TService> : IServiceMethodProvider<TService> where TService : class
{
private readonly ILogger<CodeFirstServiceMethodProvider<TService>> _logger;
private readonly BinderConfiguration? _binderConfiguration;
public CodeFirstServiceMethodProvider(ILoggerFactory loggerFactory, BinderConfiguration? binderConfiguration = null)
private readonly IServiceImplementationMapper? _serviceImplementationMapper;
public CodeFirstServiceMethodProvider(ILoggerFactory loggerFactory, IServiceImplementationMapper? serviceImplementationMapper = null, BinderConfiguration? binderConfiguration = null)
{
_binderConfiguration = binderConfiguration;
_logger = loggerFactory.CreateLogger<CodeFirstServiceMethodProvider<TService>>();
_serviceImplementationMapper = serviceImplementationMapper;
}

void IServiceMethodProvider<TService>.OnServiceMethodDiscovery(ServiceMethodProviderContext<TService> context)
{
int count = new Binder(_logger).Bind<TService>(context, _binderConfiguration);
int count = new Binder(_logger).Bind<TService>(context, _binderConfiguration, _serviceImplementationMapper);
if (count != 0) _logger.Log(LogLevel.Information, "RPC services being provided by {0}: {1}", typeof(TService), count);
}
}
Expand All @@ -63,7 +86,7 @@ protected override bool TryBind<TService, TRequest, TResponse>(ServiceBindContex
where TResponse : class
{
var metadata = bindContext.GetMetadata(stub.Method);

var context = (ServiceMethodProviderContext<TService>)bindContext.State;
switch (method.Type)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;

namespace ProtoBuf.Grpc.Configuration
{
public interface IServiceImplementationMapper
{
Type Map(Type serviceType);
}
}
20 changes: 14 additions & 6 deletions src/protobuf-net.Grpc/Configuration/ServerBinder.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using Grpc.Core;
using ProtoBuf.Grpc.Internal;
using System;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using Grpc.Core;
using ProtoBuf.Grpc.Internal;

namespace ProtoBuf.Grpc.Configuration
{
Expand All @@ -22,14 +22,18 @@ are observed and respected
/// <summary>
/// Initiate a bind operation, causing all service methods to be crawled for the provided type
/// </summary>
public int Bind<TService>(object state, BinderConfiguration? binderConfiguration = null, IServiceImplementationMapper? serviceImplementationMapper = null, TService? service = null)
where TService : class
=> Bind(state, typeof(TService), binderConfiguration, serviceImplementationMapper, service);

public int Bind<TService>(object state, BinderConfiguration? binderConfiguration = null, TService? service = null)
where TService : class
=> Bind(state, typeof(TService), binderConfiguration, service);
=> Bind(state, typeof(TService), binderConfiguration, null, service);

/// <summary>
/// Initiate a bind operation, causing all service methods to be crawled for the provided type
/// </summary>
public int Bind(object state, Type serviceType, BinderConfiguration? binderConfiguration = null, object? service = null)
public int Bind(object state, Type serviceType, BinderConfiguration? binderConfiguration = null, IServiceImplementationMapper? serviceImplementationMapper = null, object? service = null)
{
int totalCount = 0;
object?[]? argsBuffer = null;
Expand All @@ -40,12 +44,16 @@ public int Bind(object state, Type serviceType, BinderConfiguration? binderConfi
? new HashSet<Type> { serviceType }
: ContractOperation.ExpandInterfaces(serviceType);

Type serviceImplementationType = (serviceImplementationMapper != null)
? serviceImplementationMapper.Map(serviceType)
: serviceType;

foreach (var serviceContract in serviceContracts)
{
if (!binderConfiguration.Binder.IsServiceContract(serviceContract, out serviceName)) continue;

int svcOpCount = 0;
var bindCtx = new ServiceBindContext(serviceContract, serviceType, state);
var bindCtx = new ServiceBindContext(serviceContract, serviceImplementationType, state);
foreach (var op in ContractOperation.FindOperations(binderConfiguration, serviceContract, this))
{
if (ServerInvokerLookup.TryGetValue(op.MethodType, op.Context, op.Result, op.Void, out var invoker)
Expand Down

0 comments on commit 8b9ca9c

Please sign in to comment.