Skip to content

Commit

Permalink
feature: Support passing Types as 'simple' names instead of Type obje…
Browse files Browse the repository at this point in the history
…cts, to allow for version mismatches between Client & Host assemblies
  • Loading branch information
spaceisfun authored and jacqueskang committed Sep 12, 2020
1 parent 04fbfa4 commit b3b7a73
Show file tree
Hide file tree
Showing 6 changed files with 688 additions and 325 deletions.
60 changes: 51 additions & 9 deletions src/JKang.IpcServiceFramework.Client/IpcClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public async Task<TResult> InvokeAsync<TResult>(Expression<Func<TInterface, Task
}
}

private static IpcRequest GetRequest(Expression exp, TInterface proxy)
private IpcRequest GetRequest(Expression exp, TInterface proxy)
{
if (!(exp is LambdaExpression lambdaExp))
{
Expand All @@ -115,18 +115,60 @@ private static IpcRequest GetRequest(Expression exp, TInterface proxy)
Delegate @delegate = lambdaExp.Compile();
@delegate.DynamicInvoke(proxy);

return new IpcRequest
if (_options.UseSimpleTypeNameAssemblyFormatHandling)
{
MethodName = (proxy as IpcProxy).LastInvocation.Method.Name,
Parameters = (proxy as IpcProxy).LastInvocation.Arguments,
IpcRequestParameterType[] paramByName = null;
IpcRequestParameterType[] genericByName = null;

ParameterTypes = (proxy as IpcProxy).LastInvocation.Method.GetParameters()
.Select(p => p.ParameterType)
.ToArray(),
var parameterTypes = (proxy as IpcProxy).LastInvocation.Method.GetParameters().Select(p => p.ParameterType);

if (parameterTypes.Any())
{
paramByName = new IpcRequestParameterType[parameterTypes.Count()];
int i = 0;
foreach (var type in parameterTypes)
{
paramByName[i++] = new IpcRequestParameterType(type);
}
}

var genericTypes = (proxy as IpcProxy).LastInvocation.Method.GetGenericArguments();

if (genericTypes.Length > 0)
{
genericByName = new IpcRequestParameterType[genericTypes.Count()];
int i = 0;
foreach (var type in genericTypes)
{
genericByName[i++] = new IpcRequestParameterType(type);
}
}


return new IpcRequest
{
MethodName = (proxy as IpcProxy).LastInvocation.Method.Name,
Parameters = (proxy as IpcProxy).LastInvocation.Arguments,

GenericArguments = (proxy as IpcProxy).LastInvocation.Method.GetGenericArguments(),
};
ParameterTypesByName = paramByName,
GenericArgumentsByName = genericByName
};
}
else
{
return new IpcRequest
{
MethodName = (proxy as IpcProxy).LastInvocation.Method.Name,
Parameters = (proxy as IpcProxy).LastInvocation.Arguments,

ParameterTypes = (proxy as IpcProxy).LastInvocation.Method.GetParameters()
.Select(p => p.ParameterType)
.ToArray(),


GenericArguments = (proxy as IpcProxy).LastInvocation.Method.GetGenericArguments(),
};
}
}

protected abstract Task<IpcStreamWrapper> ConnectToServerAsync(CancellationToken cancellationToken);
Expand Down
13 changes: 12 additions & 1 deletion src/JKang.IpcServiceFramework.Client/IpcClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,18 @@ public class IpcClientOptions
/// The number of milliseconds to wait for the server to respond before
/// the connection times out. Default value is 60000.
/// </summary>
public int ConnectionTimeout { get; set; } = 60000;
public int ConnectionTimeout { get; set; } = 60000;

/// <summary>
/// Indicates the method that will be used during deserialization on the server for locating and loading assemblies.
/// If <c>false</c>, the assembly used during deserialization must match exactly the assembly used during serialization.
///
/// If <c>true</c>, the assembly used during deserialization need not match exactly the assembly used during serialization.
/// Specifically, the version numbers need not match.
///
/// Default is <c>false</c>.
/// </summary>
public bool UseSimpleTypeNameAssemblyFormatHandling { get; set; } = false;

public IIpcMessageSerializer Serializer { get; set; } = new DefaultIpcMessageSerializer();

Expand Down
50 changes: 48 additions & 2 deletions src/JKang.IpcServiceFramework.Core/IpcRequest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;

namespace JKang.IpcServiceFramework
Expand All @@ -11,12 +12,57 @@ public class IpcRequest
public string MethodName { get; set; }

[DataMember]
public IEnumerable<object> Parameters { get; set; }

public IEnumerable<object> Parameters { get; set; }

[DataMember]
public IEnumerable<Type> ParameterTypes { get; set; }

[DataMember]
public IEnumerable<IpcRequestParameterType> ParameterTypesByName { get; set; }

[DataMember]
public IEnumerable<Type> GenericArguments { get; set; }

[DataMember]
public IEnumerable<IpcRequestParameterType> GenericArgumentsByName { get; set; }
}

/// <summary>
/// Used to pass ParameterTypes annd GenericArguments by "Name" instead of by an explicit Type object.
/// This allows for ParameterTypes to resolve properly even if the assembly version isn't an exact match on the Client & Host.
/// </summary>
[DataContract]
public class IpcRequestParameterType
{
[DataMember]
public string ParameterType { get; private set; }

[DataMember]
public string AssemblyName { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="IpcRequestParameterType"/> class.
/// </summary>
public IpcRequestParameterType()
{
ParameterType = null;
AssemblyName = null;
}

/// <summary>
/// Initializes a new instance of the <see cref="IpcRequestParameterType"/> class.
/// </summary>
/// <param name="paramType">The type of parameter.</param>
/// <exception cref="ArgumentNullException">paramType</exception>
public IpcRequestParameterType(Type paramType)
{
if (paramType == null)
{
throw new ArgumentNullException(nameof(paramType));
}

ParameterType = paramType.FullName;
AssemblyName = paramType.Assembly.GetName().Name;
}
}
}
Loading

0 comments on commit b3b7a73

Please sign in to comment.