Skip to content
This repository has been archived by the owner on Sep 10, 2021. It is now read-only.

Commit

Permalink
Fixes for object type handling
Browse files Browse the repository at this point in the history
- Moved to 0.1.7.1
- Fixed that SetData in the protobuf serializer used the object type and not the actual type of the operation signature. This caused certain objects to be serialized as wire types and then fail to deserialize as a serialized type when received, resulting in null values
  • Loading branch information
alandoherty committed Jan 14, 2019
1 parent 9d42fd3 commit 6a19d0d
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 34 deletions.
6 changes: 3 additions & 3 deletions src/Holon/Holon.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@

<PropertyGroup>
<TargetFramework>netstandard1.6</TargetFramework>
<Version>0.1.7</Version>
<Version>0.1.7.1</Version>
<Authors>Alan Doherty</Authors>
<Company>Alan Doherty</Company>
<Description>A minimal service and event bus with additional support for RPC</Description>
<Copyright>BattleCrate Ltd 2018</Copyright>
<PackageProjectUrl>https://github.com/alandoherty/holon-net</PackageProjectUrl>
<RepositoryUrl>https://github.com/alandoherty/holon-net</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<AssemblyVersion>0.1.7.0</AssemblyVersion>
<AssemblyVersion>0.1.7.1</AssemblyVersion>
<PackageLicenseUrl>https://github.com/alandoherty/holon-net/blob/master/LICENSE</PackageLicenseUrl>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageIconUrl>https://s3-eu-west-1.amazonaws.com/assets.alandoherty.co.uk/github/holon-net-nuget.png</PackageIconUrl>
<FileVersion>0.1.7.0</FileVersion>
<FileVersion>0.1.7.1</FileVersion>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
Expand Down
4 changes: 2 additions & 2 deletions src/Holon/Remoting/RpcBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,12 @@ private async Task<RpcResponse> ApplyRequestAsync(RpcRequest req, MemberInfo mem

// check if the operation returns anything
if (operationMethod.ReturnType == typeof(Task)) {
return new RpcResponse(null);
return new RpcResponse(null, typeof(void));
} else {
// get result
object realRes = methodResult.GetType().GetTypeInfo().GetProperty("Result").GetValue(methodResult);

return new RpcResponse(realRes);
return new RpcResponse(realRes, operationMethod.ReturnType);
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/Holon/Remoting/RpcProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,16 @@ protected override object Invoke(MethodInfo targetMethod, object[] args) {
protected virtual async Task<TT> InvokeOperationAsync<TT>(MethodInfo method, object[] args, Type returnType) {
// build arguments
Dictionary<string, object> argsPayload = new Dictionary<string, object>();
Dictionary<string, Type> argsTypes = new Dictionary<string, Type>();
ParameterInfo[] argsMethod = method.GetParameters();

for (int i = 0; i < args.Length; i++) {
argsPayload[argsMethod[i].Name] = args[i];
argsTypes[argsMethod[i].Name] = argsMethod[i].ParameterType;
}

// create request
RpcRequest req = new RpcRequest(_contractAttr.Name != null ? _contractAttr.Name : _typeInfo.Name, method.Name, argsPayload);
RpcRequest req = new RpcRequest(_contractAttr.Name != null ? _contractAttr.Name : _typeInfo.Name, method.Name, argsPayload, argsTypes);

// serialize
byte[] requestBody = new ProtobufRpcSerializer().SerializeRequest(req);
Expand Down
14 changes: 13 additions & 1 deletion src/Holon/Remoting/RpcRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public sealed class RpcRequest
private string _interface;
private string _operation;
private Dictionary<string, object> _arguments;
private Dictionary<string, Type> _argumentTypes;
#endregion

#region Properties
Expand Down Expand Up @@ -42,6 +43,15 @@ public Dictionary<string, object> Arguments {
return _arguments;
}
}

/// <summary>
/// Gets the types of the arguments.
/// </summary>
public Dictionary<string, Type> ArgumentTypes {
get {
return _argumentTypes;
}
}
#endregion

#region Methods
Expand All @@ -54,10 +64,12 @@ public Dictionary<string, object> Arguments {
/// <param name="interface">The target interface.</param>
/// <param name="operation">The target operation.</param>
/// <param name="arguments">The arguments.</param>
internal RpcRequest(string @interface, string operation, Dictionary<string, object> arguments) {
/// <param name="argumentTypes">The argument types.</param>
internal RpcRequest(string @interface, string operation, Dictionary<string, object> arguments, Dictionary<string, Type> argumentTypes) {
_interface = @interface;
_operation = operation;
_arguments = arguments;
_argumentTypes = argumentTypes;
}

/// <summary>
Expand Down
15 changes: 13 additions & 2 deletions src/Holon/Remoting/RpcResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,29 @@ public sealed class RpcResponse
{
#region Fields
private object _data;
private Type _dataType;
private RpcError _error;
#endregion

#region Properties
/// <summary>
/// Gets or sets the data.
/// Gets the data.
/// </summary>
public object Data {
get {
return _data;
}
}

/// <summary>
/// Gets the data type.
/// </summary>
public Type DataType {
get {
return _dataType;
}
}

/// <summary>
/// Gets the error, if any.
/// </summary>
Expand All @@ -48,7 +58,8 @@ public bool IsSuccess {
/// Creates a new RPC response.
/// </summary>
/// <param name="data">The provided data.</param>
internal RpcResponse(object data) {
/// <param name="type">The data type.</param>
internal RpcResponse(object data, Type type) {
_data = data;
_error = null;
}
Expand Down
50 changes: 27 additions & 23 deletions src/Holon/Remoting/Serializers/ProtobufRpcSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public RpcRequest DeserializeRequest(byte[] body, RpcSignatureResolver resolver)

// convert arguments
Dictionary<string, object> args = new Dictionary<string, object>();
Dictionary<string, Type> argsTypes = new Dictionary<string, Type>();
RpcArgument[] rpcArgs = resolver(msg.Interface, msg.Operation);

if (msg.Arguments != null) {
Expand All @@ -39,11 +40,14 @@ public RpcRequest DeserializeRequest(byte[] body, RpcSignatureResolver resolver)
continue;

// add argument
args.Add(arg.Key, arg.GetData(rpcArgs.Single(a => a.Name.Equals(arg.Key, StringComparison.CurrentCultureIgnoreCase)).Type));
RpcArgument rpcArg = rpcArgs.Single(a => a.Name.Equals(arg.Key, StringComparison.CurrentCultureIgnoreCase));

args.Add(arg.Key, arg.GetData(rpcArg.Type));
argsTypes.Add(arg.Key, rpcArg.Type);
}
}

return new RpcRequest(msg.Interface, msg.Operation, args);
return new RpcRequest(msg.Interface, msg.Operation, args, argsTypes);
}
}

Expand All @@ -57,7 +61,7 @@ public RpcResponse DeserializeResponse(byte[] body, Type responseType) {
ResponseMsg msg = Serializer.Deserialize<ResponseMsg>(ms);

if (msg.IsSuccess)
return new RpcResponse(msg.Data.GetData(responseType));
return new RpcResponse(msg.Data.GetData(responseType), responseType);
else
return new RpcResponse(msg.Error.Code, msg.Error.Message);
}
Expand All @@ -73,9 +77,10 @@ public byte[] SerializeRequest(RpcRequest request) {
RequestMsg req = new RequestMsg();
req.Interface = request.Interface;
req.Operation = request.Operation;

req.Arguments = request.Arguments.Select(kv => {
ValueMsg value = new ValueMsg() { Key = kv.Key };
value.SetData(kv.Value);
value.SetData(kv.Value, request.ArgumentTypes[kv.Key]);
return value;
}).ToArray();

Expand All @@ -96,7 +101,7 @@ public byte[] SerializeResponse(RpcResponse response) {

if (response.IsSuccess) {
ValueMsg result = new ValueMsg();
result.SetData(response.Data);
result.SetData(response.Data, response.DataType);
res.Data = result;
} else {
res.Error = new ErrorMsg() {
Expand Down Expand Up @@ -147,40 +152,39 @@ class ValueMsg
/// Sets the data from a .NET type.
/// </summary>
/// <param name="val">The value.</param>
public void SetData(object val) {
/// <param name="type">The type to serialize as.</param>
public void SetData(object val, Type type) {
if (val == null)
Data = null;
else if (val is string)
else if (type == typeof(string))
Data = Encoding.UTF8.GetBytes((string)val);
else if (val is sbyte)
else if (type == typeof(sbyte))
Data = new byte[] { (byte)(sbyte)val };
else if (val is short)
else if (type == typeof(short))
Data = BitConverter.GetBytes((short)val);
else if (val is int)
else if (type == typeof(int))
Data = BitConverter.GetBytes((int)val);
else if (val is long)
else if (type == typeof(long))
Data = BitConverter.GetBytes((long)val);
else if (val is byte)
else if (type == typeof(byte))
Data = new byte[] { (byte)val };
else if (val is ushort)
else if (type == typeof(ushort))
Data = BitConverter.GetBytes((ushort)val);
else if (val is uint)
else if (type == typeof(uint))
Data = BitConverter.GetBytes((uint)val);
else if (val is ulong)
else if (type == typeof(ulong))
Data = BitConverter.GetBytes((ulong)val);
else if (val is double)
else if (type == typeof(double))
Data = BitConverter.GetBytes((double)val);
else if (val is bool)
else if (type == typeof(bool))
Data = new byte[] { (bool)val ? (byte)1 : (byte)0 };
else if (val == null)
Data = null;
else if (val is Guid)
else if (type == typeof(Guid))
Data = ((Guid)val).ToByteArray();
else if (val is ServiceAddress)
else if (type == typeof(ServiceAddress))
Data = Encoding.UTF8.GetBytes(((ServiceAddress)val).ToString());
else if (val is byte[])
else if (type == typeof(byte[]))
Data = ((byte[])val);
else if (val is DateTime)
else if (type == typeof(DateTime))
Data = Encoding.UTF8.GetBytes(((DateTime)val).ToString());
else {
TypeInfo typeInfo = val.GetType().GetTypeInfo();
Expand Down
6 changes: 4 additions & 2 deletions src/Holon/Remoting/Serializers/XmlRpcSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public RpcRequest DeserializeRequest(byte[] body, RpcSignatureResolver resolver)
// read arguments
XElement arguments = req.Elements().SingleOrDefault((e) => e.Name == "Arguments");
Dictionary<string, object> argumentsData = new Dictionary<string, object>();
Dictionary<string, Type> argumentTypes = new Dictionary<string, Type>();

if (arguments != null) {
// resolve arguments
Expand All @@ -52,11 +53,12 @@ public RpcRequest DeserializeRequest(byte[] body, RpcSignatureResolver resolver)

if (argsMap.TryGetValue(argElement.Name.LocalName, out RpcArgument arg)) {
argumentsData[arg.Name] = DeserializeValue(arg.Type, argElement);
argumentTypes[arg.Name] = arg.Type;
}
}
}

return new RpcRequest(iface.Value, op.Value, argumentsData);
return new RpcRequest(iface.Value, op.Value, argumentsData, argumentTypes);
}
}

Expand Down Expand Up @@ -128,7 +130,7 @@ public RpcResponse DeserializeResponse(byte[] body, Type dataType) {
XElement data = req.Element(XName.Get("Data"));

if (data != null) {
return new RpcResponse(DeserializeValue(dataType, data));
return new RpcResponse(DeserializeValue(dataType, data), dataType);
} else {
// find the error element then
XElement err = req.Element(XName.Get("Error"));
Expand Down

0 comments on commit 6a19d0d

Please sign in to comment.