Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
jweber committed Nov 3, 2013
2 parents adfe821 + 4c648c3 commit f6983c2
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .semver
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
:major: 1
:minor: 2
:patch: 2
:patch: 3
:special: ''
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Runtime.Serialization;
using System.ServiceModel;

namespace WcfClientProxyGenerator.Tests.Infrastructure
{
[ServiceContract]
public interface IOutParamTestService
{
[OperationContract]
int SingleOutParam(out byte[] output);

[OperationContract]
int MultipleOutParams(out byte[] out1, out string out2);

[OperationContract]
int MixedParams(int inp1, out int out1, string inp2);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using Moq;

namespace WcfClientProxyGenerator.Tests.Infrastructure
{
public class OutParamTestServiceImpl : IOutParamTestService
{
private readonly Mock<IOutParamTestService> _mock;

public OutParamTestServiceImpl()
{}

public OutParamTestServiceImpl(Mock<IOutParamTestService> mock)
{
_mock = mock;
}

public int SingleOutParam(out byte[] out1)
{
if (_mock != null)
return _mock.Object.SingleOutParam(out out1);

out1 = new byte[] { 0x00, 0x01 };
return 1;
}

public int MultipleOutParams(out byte[] out1, out string out2)
{
if (_mock != null)
return _mock.Object.MultipleOutParams(out out1, out out2);

out1 = new byte[] { 0x00, 0x01 };
out2 = "message";
return 1;
}

public int MixedParams(int inp1, out int out1, string inp2)
{
if (_mock != null)
return _mock.Object.MixedParams(inp1, out out1, inp2);

out1 = 24;
return 1;
}
}
}
78 changes: 78 additions & 0 deletions source/WcfClientProxyGenerator.Tests/ProxyTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Threading.Tasks;
using Moq;
Expand Down Expand Up @@ -173,5 +174,82 @@ public void Proxy_CanBeGeneratedForInheritingServiceInterface()

Assert.That(() => proxy.ChildMethod("test"), Is.EqualTo("OK"));
}

#region Out Parameter Support

[Test]
public void Proxy_CanBeGeneratedForOperationWithSingleOutParameter()
{
var mockTestService = new Mock<IOutParamTestService>();

byte[] expectedOutParam = { 0x00, 0x01 };
mockTestService
.Setup(m => m.SingleOutParam(out expectedOutParam))
.Returns(1);

var serviceHost = InProcTestFactory.CreateHost<IOutParamTestService>(new OutParamTestServiceImpl(mockTestService));

var proxy = WcfClientProxy.Create<IOutParamTestService>(c => c.SetEndpoint(serviceHost.Binding, serviceHost.EndpointAddress));

byte[] outParam;
int result = proxy.SingleOutParam(out outParam);

Assert.That(result, Is.EqualTo(1));
Assert.That(outParam, Is.EqualTo(expectedOutParam));
}

[Test]
public void Proxy_CanBeGeneratedForOperationWithMultipleOutParameters()
{
var mockTestService = new Mock<IOutParamTestService>();

byte[] expectedOut1Value = { 0x00, 0x01 };
string expectedOut2Value = "message";
mockTestService
.Setup(m => m.MultipleOutParams(out expectedOut1Value, out expectedOut2Value))
.Returns(1);

var serviceHost = InProcTestFactory.CreateHost<IOutParamTestService>(new OutParamTestServiceImpl(mockTestService));

var proxy = WcfClientProxy.Create<IOutParamTestService>(c => c.SetEndpoint(serviceHost.Binding, serviceHost.EndpointAddress));

byte[] out1Value;
string out2Value;
int result = proxy.MultipleOutParams(out out1Value, out out2Value);

Assert.That(result, Is.EqualTo(1));
Assert.That(out1Value, Is.EqualTo(expectedOut1Value));
Assert.That(out2Value, Is.EqualTo(expectedOut2Value));
}

[Test]
public void Proxy_CanBeGeneratedForOperationWithMixedInputAndOutputParams()
{
var mockTestService = new Mock<IOutParamTestService>();

int expectedOut1Value = 25;
mockTestService
.Setup(m => m.MixedParams(1, out expectedOut1Value, "test"))
.Returns(1);

var serviceHost = InProcTestFactory.CreateHost<IOutParamTestService>(new OutParamTestServiceImpl(mockTestService));

var proxy = WcfClientProxy.Create<IOutParamTestService>(c => c.SetEndpoint(serviceHost.Binding, serviceHost.EndpointAddress));

int out1Value;
int result = proxy.MixedParams(1, out out1Value, "test");

Assert.That(result, Is.EqualTo(1));
Assert.That(out1Value, Is.EqualTo(expectedOut1Value));
}

[DataContract]
public class TestObj : MarshalByRefObject
{
[DataMember]
public string Value { get; set; }
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DefineConstants>NET45</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
Expand Down Expand Up @@ -65,9 +65,11 @@
<Compile Include="Infrastructure\ChildServiceImpl.cs" />
<Compile Include="Infrastructure\IChildService.cs" />
<Compile Include="Infrastructure\ITestService2.cs" />
<Compile Include="Infrastructure\IOutParamTestService.cs" />
<Compile Include="Infrastructure\ITestServiceSingleEndpointConfig.cs" />
<Compile Include="Infrastructure\TestService2Impl.cs" />
<Compile Include="DelayPolicyTests.cs" />
<Compile Include="Infrastructure\OutParamTestServiceImpl.cs" />
<Compile Include="ProxyTests.cs" />
<Compile Include="Infrastructure\InProcTestFactory.cs" />
<Compile Include="Infrastructure\ITestService.cs" />
Expand Down
75 changes: 65 additions & 10 deletions source/WcfClientProxyGenerator/DynamicProxyTypeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public static Type GenerateType<TActionInvokerProvider>()
var moduleBuilder = DynamicProxyAssembly.ModuleBuilder;

var typeBuilder = moduleBuilder.DefineType(
"-proxy-" + typeof(TServiceInterface).Name,
"WcfClientProxyGenerator.DynamicProxy." + typeof(TServiceInterface).Name,
TypeAttributes.Public | TypeAttributes.Class,
typeof(TActionInvokerProvider));

Expand Down Expand Up @@ -111,14 +111,20 @@ private static void GenerateServiceProxyMethod(
methodInfo.ReturnType,
parameterTypes);

for (int i = 1; i <= parameterTypes.Length; i++)
methodBuilder.DefineParameter(i, ParameterAttributes.None, "arg" + i);

Type serviceCallWrapperType;
var serviceCallWrapperFields = GenerateServiceCallWrapperType(
methodInfo,
parameterTypes,
out serviceCallWrapperType);

FieldBuilder[] inputFields = serviceCallWrapperFields.Where(f => f.Name.StartsWith("arg")).ToArray();
FieldBuilder[] outputFields = serviceCallWrapperFields.Where(f => f.Name.StartsWith("out")).ToArray();

var ilGenerator = methodBuilder.GetILGenerator();
ilGenerator.DeclareLocal(typeof(RetryingWcfActionInvoker<TServiceInterface>));
ilGenerator.DeclareLocal(typeof(IActionInvoker<TServiceInterface>));

ilGenerator.DeclareLocal(methodInfo.ReturnType == typeof(void)
? typeof(Action<>).MakeGenericType(typeof(TServiceInterface))
Expand All @@ -139,8 +145,12 @@ private static void GenerateServiceProxyMethod(

for (int i = 0; i < serviceCallWrapperFields.Count; i++)
{
FieldBuilder field = serviceCallWrapperFields[i];
if (!inputFields.Contains(field))
continue;

ilGenerator.Emit(OpCodes.Ldarg, i + 1);
ilGenerator.Emit(OpCodes.Stfld, serviceCallWrapperType.GetField(serviceCallWrapperFields[i].Name));
ilGenerator.Emit(OpCodes.Stfld, serviceCallWrapperType.GetField(field.Name));

if (i < serviceCallWrapperFields.Count)
ilGenerator.Emit(OpCodes.Ldloc_2);
Expand Down Expand Up @@ -172,6 +182,27 @@ private static void GenerateServiceProxyMethod(
MethodInfo invokeMethod = GetIActionInvokerInvokeMethod(methodInfo);

ilGenerator.Emit(OpCodes.Callvirt, invokeMethod);

if (outputFields.Length > 0)
{
ilGenerator.Emit(OpCodes.Stloc_3);

for (int i = 0; i < serviceCallWrapperFields.Count; i++)
{
FieldBuilder field = serviceCallWrapperFields[i];
if (!outputFields.Contains(field))
continue;

ilGenerator.Emit(OpCodes.Ldarg, i + 1);
ilGenerator.Emit(OpCodes.Ldloc_2);
ilGenerator.Emit(OpCodes.Ldfld, serviceCallWrapperFields[i]);
ilGenerator.Emit(OpCodes.Stind_Ref);
}

ilGenerator.Emit(OpCodes.Ldloc_3);
}


ilGenerator.Emit(OpCodes.Ret);
}

Expand Down Expand Up @@ -216,19 +247,37 @@ private static IList<FieldBuilder> GenerateServiceCallWrapperType(
Type[] parameterTypes,
out Type generatedType)
{
Type[] byRefParameterTypes = parameterTypes
.Where(t => t.IsByRef)
.ToArray();

string typeName = string.Format(
"-call-{0}.{1}",
"WcfClientProxyGenerator.DynamicProxy.{0}Support.{1}",
typeof(TServiceInterface).Name,
methodInfo.Name);

var serviceCallTypeBuilder = DynamicProxyAssembly.ModuleBuilder.DefineType(typeName);

var fields = new List<FieldBuilder>(parameterTypes.Length);
for (int i = 0; i < parameterTypes.Length; i++)

int inputFields = 0;
int outputFields = 0;
foreach (Type parameterType in parameterTypes)
{
Type parameterType = parameterTypes[i];
string fieldName;
Type fieldType = parameterType;
if (parameterType.IsByRef)
{
fieldName = "out" + (outputFields++);
fieldType = parameterType.GetElementType();
}
else
{
fieldName = "arg" + (inputFields++);
}

fields.Add(
serviceCallTypeBuilder.DefineField("arg" + i, parameterType, FieldAttributes.Public));
serviceCallTypeBuilder.DefineField(fieldName, fieldType, FieldAttributes.Public));
}

var methodBuilder = serviceCallTypeBuilder.DefineMethod(
Expand All @@ -237,18 +286,24 @@ private static IList<FieldBuilder> GenerateServiceCallWrapperType(
methodInfo.ReturnType,
new[] { typeof(TServiceInterface) });

methodBuilder.DefineParameter(1, ParameterAttributes.None, "service");

var ilGenerator = methodBuilder.GetILGenerator();

if (methodInfo.ReturnType != typeof(void))
ilGenerator.DeclareLocal(methodInfo.ReturnType);

ilGenerator.Emit(OpCodes.Ldarg_1);

fields.ForEach(lf =>
for (int i = 0; i < parameterTypes.Length; i++)
{
bool isByRef = parameterTypes[i].IsByRef;

ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, lf);
});
ilGenerator.Emit(
isByRef ? OpCodes.Ldflda : OpCodes.Ldfld,
fields[i]);
}

ilGenerator.Emit(OpCodes.Callvirt, methodInfo);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<DefineConstants>NET45</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
Expand Down

0 comments on commit f6983c2

Please sign in to comment.