Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
9952004
Added methods in status API supports for direct storage and reading o…
divzi-p Jun 29, 2023
37b5f7d
Changed SaveStateByteAsync,TrySaveStateByteAsync to use ReadOnlyMemor…
divzi-p Aug 26, 2023
5ffb173
[Workflow] Fix issue with ignored external event payload (#1119)
cgillum Jul 6, 2023
f3d6405
Rev'ed Grpc.Net.Client PackageReference version for Dapr dotnet-sdk (…
MonkeyTennis Jul 18, 2023
b8110ec
Add support to DAPR_HTTP_ENDPOINT and DAPR_GRPC_ENDPOINT env. (#1124)
artursouza Jul 18, 2023
2065570
Add cascading metadata (#1128)
Jul 18, 2023
34241a6
remove invalid code line (#1127)
hhunter-ms Jul 18, 2023
d5131bc
adding get actor reminder API in docs (#1113)
shivamkm07 Jul 21, 2023
d5959c2
Inroduce OnActorMethodFailedAsync virtual method for overriding (#1014)
vlardn Aug 16, 2023
b067162
Remove .NET Core 3.1 support and standardize on .NET 6 (#1045)
yash-nisar Aug 24, 2023
b99b4b1
Proof-of-concept serialization of advanced JSON types, records (#1073)
onionhammer Sep 5, 2023
a9d4b94
Type change from byte[] -> ReadOnlyMemory<byte>
divzi-p Jan 9, 2024
a0d1d37
Changed method names to sync with naming conventions
divzi-p Jan 13, 2024
132f822
Implememted review comments to add proper comments and remove comment…
divzi-p Apr 30, 2024
6ec96a6
Removed commented code.
divzi-p Apr 30, 2024
1020e9f
Updating workflow collection to allow for use of API Token validation…
RyanLettieri Sep 7, 2023
09a855d
set dapr-api-token to healthz requests when needed (#1145)
famarting Sep 7, 2023
254b399
Adding in new test for parallel raise events in workflow (#1155)
RyanLettieri Oct 6, 2023
eb827d6
Consolidate C# language version to 10. (#1180)
philliphoff Nov 13, 2023
c4eb2f1
Update actor reminder example. (#1179)
philliphoff Nov 13, 2023
97cbd21
Initial implementation for workflow log tracing (#1176)
RyanLettieri Nov 14, 2023
703340b
.NET 8 Support (#1188)
philliphoff Nov 15, 2023
8d7d72b
Modify broken links in README (#1190)
MregXN Nov 28, 2023
254c3d7
Added unit test to prove out enum serialization working as expected d…
WhitWaldo Nov 28, 2023
dc45a01
modify readme (#1192)
MregXN Nov 29, 2023
89d2c6d
Updates Dapr to 1.12 in GitHub actions itest (#1185)
JoshVanL Nov 29, 2023
423bc5d
Add holopin.yml config (#1147)
marcduiker Nov 29, 2023
a51c12c
Correct spelling of "identified" (#1159)
frankbuckley Nov 29, 2023
1dd74e7
Adding cancel to workflow example and updating api references to beta…
RyanLettieri Nov 29, 2023
6b3970f
Enable `CancellationToken` for non-remoting actor implementations (#1…
philliphoff Jan 6, 2024
3f924a1
Fix example dotnet-actors-howto.md (#1218)
henrikkarstrom Jan 6, 2024
48550c4
Update _index.md by fixing broken link (#1221)
farshaddavoudi Jan 6, 2024
a737137
use daprWorkflowClient (#1212)
MregXN Jan 8, 2024
d8376d8
Actor State TTL (#1164)
JoshVanL Jan 8, 2024
a41915c
Added documentation detailing how serialization works using the DataC…
WhitWaldo Jan 26, 2024
3a05d53
Weakly typed actor polymorphic and null responses (#1214)
RemcoBlok Jan 31, 2024
f7a66d8
Implementing Cryptography building block in .NET (#1217)
WhitWaldo Feb 14, 2024
38bc34b
Handle the case where appid contains at least one upperletter (#1233)
TWEESTY Feb 16, 2024
7bf1fae
Enable vault name mapping and error suppression (#1231)
jamesmcroft Feb 16, 2024
59a9be0
Add overload to deserialize GetBulkStateAsync item values (#1173)
WhitWaldo Feb 16, 2024
81ab50c
Use TryAddSingleton() for registering services. (#1238)
philliphoff Feb 16, 2024
61fd4bc
Source generated actor clients (#1165)
philliphoff Feb 16, 2024
e1a42d8
Merge 1.13 release branch back to master (#1247)
philliphoff Mar 8, 2024
38c32de
Updated to reflect latest guidance to register endpoints via top-leve…
WhitWaldo Apr 8, 2024
4fbfe71
Adds an option to set a timeout for service invocation (#1252)
elena-kolevska Apr 8, 2024
2986d41
Updating Workflow XML comment for accuracy (#1260)
WhitWaldo Apr 8, 2024
e0d359b
Updated property on type to reflect the fact that it can return a nul…
WhitWaldo Apr 8, 2024
a96cee4
#1239 remove polyfill packages (#1258)
thompson-tomo Apr 8, 2024
11dfdcd
Updated .github/holopin.yml. Fixes #1270 (#1276)
cmendible Apr 23, 2024
953e041
Update README.md (#1284)
m3nax May 13, 2024
7c50d04
restored missing title in readme (#1286)
m3nax May 14, 2024
10a5d32
Fixed badge broken links (#1290)
m3nax May 22, 2024
ba0d11b
Removed non-existent project, correct path of the generator project. …
m3nax Jun 5, 2024
9ad3692
Added overload for DaprClient DI registration (#1289)
WhitWaldo Jun 25, 2024
d2540ce
Merge `release-1.13` back into `master` (#1285)
philliphoff Jun 25, 2024
20fe0cb
Samples - Add k8s deployment yaml to DemoActor sample (#1308)
m3nax Jun 26, 2024
d4531ba
Added ActorReference creation from the ActorBase class informations (…
m3nax Jun 26, 2024
8479a9d
Added overload to support SDK supplying query string on invoked URL (…
WhitWaldo Jul 3, 2024
a3d476a
fix (#1329)
hhunter-ms Jul 23, 2024
b866eeb
link to non-dapr endpoint howto (#1335)
hhunter-ms Aug 9, 2024
da74dac
Added unit test to prove out concern raised on Discord
WhitWaldo Sep 13, 2024
89e271c
Removed unused using
WhitWaldo Sep 19, 2024
aa4cfed
Merge 1.14 release branch back into `master`. (#1337)
philliphoff Aug 22, 2024
8cc47f5
Added missing workflow status branch (#1348)
WhitWaldo Sep 13, 2024
f5129f9
Consolidated version of coverlet.msbuild, coverlet.collector, xunit, …
m3nax Jun 26, 2024
d3421bf
Added unit test to validate that headers aren't being stripped off re…
WhitWaldo Oct 7, 2024
20bc8f5
Fixed spelling typo
WhitWaldo Oct 7, 2024
fb42f81
Added fix to handle null return values
WhitWaldo Oct 6, 2024
62765d7
Removed unnecessary null check
WhitWaldo Oct 11, 2024
d126e1a
Removed deprecated methods from DaprClient and tests as well as unuse…
WhitWaldo Sep 3, 2024
6f84f17
Removed unused (and invalid) reference
WhitWaldo Sep 3, 2024
781fe32
Removed E2E workflow test as it validated DaprClient and the function…
WhitWaldo Oct 11, 2024
906f44e
Adding instance-based CreateInvokableHttpClient (#1319)
WhitWaldo Oct 14, 2024
a1a6f9c
Fixed security advisory updates across dependencies (transitive and d…
WhitWaldo Oct 15, 2024
dd1bcd0
Removes floating classes and introduces Dapr.Common project (#1365)
WhitWaldo Oct 16, 2024
0c1944b
Extracted Protos out to common project (#1367)
WhitWaldo Oct 16, 2024
3209c91
Improvement of the dotnet-contributing files (#1330)
Shubhdeep02 Oct 16, 2024
77dfe1e
Support case insensitive cloudevent payloads and forward cloudevent p…
iliaspoli Oct 17, 2024
ab6f508
Updating actor serialization documentation (#1371)
WhitWaldo Oct 18, 2024
47951b7
Prioritize retrieval of environment variables from IConfiguration ins…
WhitWaldo Oct 18, 2024
04d47e6
cleanup: Removed Serilog nuget from Directory.Packages.props (#1376)
m3nax Oct 22, 2024
cde2f0f
Removed sample folder (#1375)
m3nax Oct 22, 2024
1e727dd
Remove unused variables (#1314)
RafaelJCamara Oct 24, 2024
34d16ef
Remove unused using statements. (#1313)
RafaelJCamara Oct 24, 2024
094d757
Incremental source generator for actors (#1334)
m3nax Oct 28, 2024
fcfb7e1
Add .NET client for Dapr Jobs API (#1384)
WhitWaldo Nov 1, 2024
7b1e898
Updated prereqs to specify .NET 6 and .NET 8 in v1.15 (#1398)
WhitWaldo Nov 1, 2024
a0a95d9
Refactor DaprWorkflowClientBuilderFactory and WorkflowRuntimeOptions …
neworange-ruud Nov 4, 2024
180f622
Fix for DI registration not completing as expected (#1386)
WhitWaldo Nov 5, 2024
6964033
Add .NET client for pub/sub support - streaming subscriptions (#1381)
WhitWaldo Nov 5, 2024
ec505e2
ci: set fail-fast to false (#1405)
mikeee Nov 12, 2024
180447c
Added async operations workflow sample (#1394)
WhitWaldo Nov 12, 2024
d71f398
Added workflow example: Fan out/fan in (#1396)
WhitWaldo Nov 13, 2024
c0def6c
Added workflow sample: Sub-workflows (#1395)
WhitWaldo Nov 14, 2024
6d75abf
Added workflow sample: Task chaining (#1387)
WhitWaldo Nov 14, 2024
d7967c0
Added workflow sample: Monitor (#1388)
WhitWaldo Nov 14, 2024
aa4f494
Added workflow example: External interaction (#1389)
WhitWaldo Nov 18, 2024
3c4271a
Optional DI lifecycle change (#1408)
WhitWaldo Nov 21, 2024
be460e4
Additional lifecycle registration changes (#1410)
WhitWaldo Nov 24, 2024
132d072
Preserve comparer of the original dictionary from ConfigurationProvid…
tomhreb Nov 30, 2024
7965359
Bug/476 multiple methods per interface with JSON serialization doesn´…
paule96 Dec 3, 2024
47458cd
Support .NET 9 (#1404)
WhitWaldo Dec 4, 2024
7ff85d3
update .net workflow docs to stable (#1418)
hhunter-ms Dec 4, 2024
1b7e65c
FIX: Actor source generator generates invalid code for generic interf…
m3nax Dec 5, 2024
14c095e
added system.text and fixed bull check in test
divzi-p Dec 10, 2024
1d5cc35
Merge branch 'master' into feature_upgrade_statusapi_1.0.0
WhitWaldo Dec 11, 2024
f4810f4
Merge branch 'master' into feature_upgrade_statusapi_1.0.0
WhitWaldo Dec 11, 2024
9c2a061
Fixed two merge misses
WhitWaldo Dec 11, 2024
eeaa842
Merge remote-tracking branch 'divzi-p/feature_upgrade_statusapi_1.0.0…
WhitWaldo Dec 11, 2024
f72eadf
Fixed errors in unit tests
WhitWaldo Dec 11, 2024
6e98a19
Removed duplicate method
WhitWaldo Dec 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Bug/476 multiple methods per interface with JSON serialization doesn´…
…t work (#1343)

* update devcontainer

Signed-off-by: paule96 <paul-jeschke@outlook.com>

* update test setup

Signed-off-by: paule96 <paul-jeschke@outlook.com>

* Now the json serialization should work with multiple methods in an interface

Signed-off-by: paule96 <paul-jeschke@outlook.com>

* fixed devcontainer to run actors

Now the devcontainer uses docker in docker, so you can reach the dapr setup after you did run dapr init. This will then only affect the dev container, without compromising the host of the devcontainer

Signed-off-by: paule96 <paul-jeschke@outlook.com>

* fix bugs with the current implementation

Signed-off-by: paule96 <paul-jeschke@outlook.com>

* add a test that checks excatly the behavior

Signed-off-by: paule96 <paul-jeschke@outlook.com>

* fix devcontainer post creatd command

Signed-off-by: paule96 <paul-jeschke@outlook.com>

* change the default to dotnet 8.0

Signed-off-by: paule96 <paul-jeschke@outlook.com>

* I don't know what is different but we commit.

Maybe it resolves the need of chmod for it 🤷‍♀️

Signed-off-by: paule96 <paul-jeschke@outlook.com>

* make it easier to see why the application of an E2E test couldn't start

Signed-off-by: paule96 <paul-jeschke@outlook.com>

* make the exception in E2E more percise

Signed-off-by: paule96 <paul-jeschke@outlook.com>

* fix exception message

Signed-off-by: paule96 <paul-jeschke@outlook.com>

---------

Signed-off-by: paule96 <paul-jeschke@outlook.com>
Co-authored-by: Yaron Schneider <schneider.yaron@live.com>
Co-authored-by: Whit Waldo <whit.waldo@innovian.net>
Signed-off-by: Divya Perumal <divzi.perumal@gmail.com>
  • Loading branch information
3 people authored and divzi-p committed Dec 10, 2024
commit 7965359d2cbb8f270f086acd6583fd7bf4f35644
20 changes: 12 additions & 8 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@
"ghcr.io/devcontainers/features/azure-cli:1": {
"version": "2.38"
},
"ghcr.io/devcontainers/features/docker-from-docker:1": {
"version": "20.10"
"ghcr.io/devcontainers/features/docker-in-docker": {
"version": "latest"
},
"ghcr.io/devcontainers/features/dotnet:1": {
"version": "6.0"
"ghcr.io/devcontainers/features/dotnet": {
"version": "8.0",
"additionalVersions": [
"6.0",
"7.0"
]
},
"ghcr.io/devcontainers/features/github-cli:1": {
"version": "2"
Expand All @@ -32,7 +36,8 @@
"ms-dotnettools.csharp",
"ms-dotnettools.vscode-dotnet-runtime",
"ms-azuretools.vscode-dapr",
"GitHub.copilot"
"GitHub.copilot",
"ms-dotnettools.csdevkit"
],
"forwardPorts": [
3000,
Expand All @@ -42,10 +47,9 @@
5000,
5007
],
"postCreateCommand": ".devcontainer/localinit.sh",
"postCreateCommand": "chmod +x .devcontainer/localinit.sh && .devcontainer/localinit.sh",
"remoteUser": "vscode",
"hostRequirements": {
"memory": "8gb"
}
}

}
Empty file modified .devcontainer/localinit.sh
100644 → 100755
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,10 @@ public MemoryStreamMessageBodySerializer(
{
var _methodRequestParameterTypes = new List<Type>(methodRequestParameterTypes);
var _wrappedRequestMessageTypes = new List<Type>(wrappedRequestMessageTypes);

if(_wrappedRequestMessageTypes.Count > 1){
throw new NotSupportedException("JSON serialisation should always provide the actor method (or nothing), that was called" +
" to support (de)serialisation. This is a Dapr SDK error, open an issue on GitHub.");
}
this.serializerOptions = new(serializerOptions)
{
// Workaround since WrappedMessageBody creates an object
Expand Down
44 changes: 33 additions & 11 deletions src/Dapr.Actors/Communication/ActorMessageSerializersManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ namespace Dapr.Actors.Communication
{
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Dapr.Actors.Builder;

internal class ActorMessageSerializersManager
{
private readonly ConcurrentDictionary<int, CacheEntry> cachedBodySerializers;
private readonly ConcurrentDictionary<(int, string), CacheEntry> cachedBodySerializers;
private readonly IActorMessageHeaderSerializer headerSerializer;
private readonly IActorMessageBodySerializationProvider serializationProvider;

Expand All @@ -38,7 +41,7 @@ public ActorMessageSerializersManager(
}

this.serializationProvider = serializationProvider;
this.cachedBodySerializers = new ConcurrentDictionary<int, CacheEntry>();
this.cachedBodySerializers = new ConcurrentDictionary<(int, string), CacheEntry>();
this.headerSerializer = headerSerializer;
}

Expand All @@ -52,19 +55,19 @@ public IActorMessageHeaderSerializer GetHeaderSerializer()
return this.headerSerializer;
}

public IActorRequestMessageBodySerializer GetRequestMessageBodySerializer(int interfaceId)
public IActorRequestMessageBodySerializer GetRequestMessageBodySerializer(int interfaceId, [AllowNull] string methodName = null)
{
return this.cachedBodySerializers.GetOrAdd(interfaceId, this.CreateSerializers).RequestMessageBodySerializer;
return this.cachedBodySerializers.GetOrAdd((interfaceId, methodName), this.CreateSerializers).RequestMessageBodySerializer;
}

public IActorResponseMessageBodySerializer GetResponseMessageBodySerializer(int interfaceId)
public IActorResponseMessageBodySerializer GetResponseMessageBodySerializer(int interfaceId, [AllowNull] string methodName = null)
{
return this.cachedBodySerializers.GetOrAdd(interfaceId, this.CreateSerializers).ResponseMessageBodySerializer;
return this.cachedBodySerializers.GetOrAdd((interfaceId, methodName), this.CreateSerializers).ResponseMessageBodySerializer;
}

internal CacheEntry CreateSerializers(int interfaceId)
internal CacheEntry CreateSerializers((int interfaceId, string methodName) data)
{
var interfaceDetails = this.GetInterfaceDetails(interfaceId);
var interfaceDetails = this.GetInterfaceDetails(data.interfaceId);

// get the service interface type from the code gen layer
var serviceInterfaceType = interfaceDetails.ServiceInterfaceType;
Expand All @@ -74,10 +77,29 @@ internal CacheEntry CreateSerializers(int interfaceId)

// get the known types from the codegen layer
var responseBodyTypes = interfaceDetails.ResponseKnownTypes;
if (data.methodName is null)
{
// Path is mainly used for XML serialization
return new CacheEntry(
this.serializationProvider.CreateRequestMessageBodySerializer(serviceInterfaceType, requestBodyTypes, interfaceDetails.RequestWrappedKnownTypes),
this.serializationProvider.CreateResponseMessageBodySerializer(serviceInterfaceType, responseBodyTypes, interfaceDetails.ResponseWrappedKnownTypes));
}
else
{
// This path should be used for JSON serialization
var requestWrapperTypeAsList = interfaceDetails.RequestWrappedKnownTypes.Where(r => r.Name == $"{data.methodName}ReqBody").ToList();
if(requestWrapperTypeAsList.Count > 1){
throw new NotSupportedException($"More then one wrappertype was found for {data.methodName}");
}
var responseWrapperTypeAsList = interfaceDetails.ResponseWrappedKnownTypes.Where(r => r.Name == $"{data.methodName}RespBody").ToList();
if(responseWrapperTypeAsList.Count > 1){
throw new NotSupportedException($"More then one wrappertype was found for {data.methodName}");
}
return new CacheEntry(
this.serializationProvider.CreateRequestMessageBodySerializer(serviceInterfaceType, requestBodyTypes, requestWrapperTypeAsList),
this.serializationProvider.CreateResponseMessageBodySerializer(serviceInterfaceType, responseBodyTypes, responseWrapperTypeAsList));
}

return new CacheEntry(
this.serializationProvider.CreateRequestMessageBodySerializer(serviceInterfaceType, requestBodyTypes, interfaceDetails.RequestWrappedKnownTypes),
this.serializationProvider.CreateResponseMessageBodySerializer(serviceInterfaceType, responseBodyTypes, interfaceDetails.ResponseWrappedKnownTypes));
}

internal InterfaceDetails GetInterfaceDetails(int interfaceId)
Expand Down
4 changes: 2 additions & 2 deletions src/Dapr.Actors/DaprHttpInteractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public async Task<IActorResponseMessage> InvokeActorMethodWithRemotingAsync(Acto
var serializedHeader = serializersManager.GetHeaderSerializer()
.SerializeRequestHeader(remotingRequestRequestMessage.GetHeader());

var msgBodySeriaizer = serializersManager.GetRequestMessageBodySerializer(interfaceId);
var msgBodySeriaizer = serializersManager.GetRequestMessageBodySerializer(interfaceId, methodName);
var serializedMsgBody = msgBodySeriaizer.Serialize(remotingRequestRequestMessage.GetBody());

// Send Request
Expand Down Expand Up @@ -170,7 +170,7 @@ HttpRequestMessage RequestFunc()

// Deserialize Actor Response Message Body
// Deserialize to ActorInvokeException when there is response header otherwise normal path
var responseBodySerializer = serializersManager.GetResponseMessageBodySerializer(interfaceId);
var responseBodySerializer = serializersManager.GetResponseMessageBodySerializer(interfaceId, methodName);

// actorResponseMessageHeader is not null, it means there is remote exception
if (actorResponseMessageHeader != null)
Expand Down
10 changes: 5 additions & 5 deletions src/Dapr.Actors/Runtime/ActorManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ internal async Task<Tuple<string, byte[]>> DispatchWithRemotingAsync(ActorId act
var interfaceId = actorMessageHeader.InterfaceId;

// Get the deserialized Body.
var msgBodySerializer = this.serializersManager.GetRequestMessageBodySerializer(actorMessageHeader.InterfaceId);

var msgBodySerializer = this.serializersManager.GetRequestMessageBodySerializer(actorMessageHeader.InterfaceId, actorMethodContext.MethodName);
IActorRequestMessageBody actorMessageBody;
using (var stream = new MemoryStream())
{
Expand All @@ -130,7 +130,7 @@ async Task<Tuple<string, byte[]>> RequestFunc(Actor actor, CancellationToken ct)
this.messageBodyFactory,
ct);

return this.CreateResponseMessage(responseMsgBody, interfaceId);
return this.CreateResponseMessage(responseMsgBody, interfaceId, actorMethodContext.MethodName);
}

return await this.DispatchInternalAsync(actorId, actorMethodContext, RequestFunc, cancellationToken);
Expand Down Expand Up @@ -386,12 +386,12 @@ private async Task<T> DispatchInternalAsync<T>(ActorId actorId, ActorMethodConte
return retval;
}

private Tuple<string, byte[]> CreateResponseMessage(IActorResponseMessageBody msgBody, int interfaceId)
private Tuple<string, byte[]> CreateResponseMessage(IActorResponseMessageBody msgBody, int interfaceId, string methodName)
{
var responseMsgBodyBytes = Array.Empty<byte>();
if (msgBody != null)
{
var responseSerializer = this.serializersManager.GetResponseMessageBodySerializer(interfaceId);
var responseSerializer = this.serializersManager.GetResponseMessageBodySerializer(interfaceId, methodName);
responseMsgBodyBytes = responseSerializer.Serialize(msgBody);
}

Expand Down
2 changes: 2 additions & 0 deletions test/Dapr.E2E.Test.Actors/ISerializationActor.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
Expand All @@ -10,6 +11,7 @@ namespace Dapr.E2E.Test.Actors
public interface ISerializationActor : IActor, IPingActor
{
Task<SerializationPayload> SendAsync(string name, SerializationPayload payload, CancellationToken cancellationToken = default);
Task<DateTime> AnotherMethod(DateTime payload);
}

public record SerializationPayload(string Message)
Expand Down
5 changes: 5 additions & 0 deletions test/Dapr.E2E.Test.App/Actors/SerializationActor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

using System;
using System.Threading;
using System.Threading.Tasks;
using Dapr.Actors.Runtime;
Expand All @@ -22,5 +23,9 @@ public Task<SerializationPayload> SendAsync(string name,
{
return Task.FromResult(payload);
}

public Task<DateTime> AnotherMethod(DateTime payload){
return Task.FromResult(payload);
}
}
}
27 changes: 27 additions & 0 deletions test/Dapr.E2E.Test/Actors/E2ETests.CustomSerializerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,32 @@ public async Task ActorCanSupportCustomSerializer()
Assert.Equal(JsonSerializer.Serialize(kvp.Value), JsonSerializer.Serialize(value));
}
}

/// <summary>
/// This was actually a problem that is why the test exists.
/// It just checks, if the interface of the actor has more than one method defined,
/// that if can call it and serialize the payload correctly.
/// </summary>
/// <remarks>
/// More than one methods means here, that in the exact interface must be two methods defined.
/// That excludes hirachies.
/// So <see cref="IPingActor.Ping"/> wouldn't count here, because it's not directly defined in
/// <see cref="ISerializationActor"/>. (it's defined in the base of it.)
/// That why <see cref="ISerializationActor.AnotherMethod(DateTime)"/> was created,
/// so there are now more then one method.
/// </remark>
[Fact]
public async Task ActorCanSupportCustomSerializerAndCallMoreThenOneDefinedMethod()
{
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));
var proxy = this.ProxyFactory.CreateActorProxy<ISerializationActor>(ActorId.CreateRandom(), "SerializationActor");

await ActorRuntimeChecker.WaitForActorRuntimeAsync(this.AppId, this.Output, proxy, cts.Token);

var payload = DateTime.MinValue;
var result = await proxy.AnotherMethod(payload);

Assert.Equal(payload, result);
}
}
}
85 changes: 80 additions & 5 deletions test/Dapr.E2E.Test/DaprCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ namespace Dapr.E2E.Test
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading;
using Xunit.Abstractions;

public class DaprCommand
{
private readonly ITestOutputHelper output;
private readonly CircularBuffer<string> logBuffer = new CircularBuffer<string>(1000);

public DaprCommand(ITestOutputHelper output)
{
Expand Down Expand Up @@ -66,7 +68,12 @@ public void Run()
var done = outputReceived.WaitOne(this.Timeout);
if (!done)
{
throw new Exception($"Command: \"{this.Command}\" timed out while waiting for output: \"{this.OutputToMatch}\"");
var ex = new Exception($"Command: \"{this.Command}\" timed out while waiting for output: \"{this.OutputToMatch}\"{System.Environment.NewLine}" +
"This could also mean the E2E app had a startup error. For more details see the Data property of this exception.");
// we add here the log buffer of the last 1000 lines, of the application log
// to make it easier to debug failing tests
ex.Data.Add("log", this.logBuffer.ToArray());
throw ex;
}
}

Expand All @@ -79,8 +86,7 @@ private void CheckOutput(object sendingProcess, DataReceivedEventArgs e)

try
{
// see: https://github.com/xunit/xunit/issues/2146
this.output.WriteLine(e.Data.TrimEnd(Environment.NewLine.ToCharArray()));
WriteLine(e.Data);
}
catch (InvalidOperationException)
{
Expand All @@ -101,12 +107,81 @@ private void OnErrorOutput(object sender, DataReceivedEventArgs e)

try
{
// see: https://github.com/xunit/xunit/issues/2146
this.output.WriteLine(e.Data.TrimEnd(Environment.NewLine.ToCharArray()));
WriteLine(e.Data);
}
catch (InvalidOperationException)
{
}
}

private void WriteLine(string message)
{
// see: https://github.com/xunit/xunit/issues/2146
var formattedMessage = message.TrimEnd(Environment.NewLine.ToCharArray());
this.output.WriteLine(formattedMessage);
this.logBuffer.Add(formattedMessage);
}
}

/// <summary>
/// A circular buffer that can be used to store a fixed number of items.
/// When the buffer is full, the oldest item is overwritten.
/// The buffer can be read in the same order as the items were added.
/// More information can be found <see href="https://en.wikipedia.org/wiki/Circular_buffer">here</see>.
/// </summary>
/// <remarks>
/// The buffer gets initialized by the call to the constructor and will allocate,
/// the memory for the buffer. The buffer is not resizable.
/// That means be carefull with <see cref="size"/>, because it can cause an <see cref="OutOfMemoryException"/>.
/// </remarks>
/// <typeparam name="T">The type of what the cicular buffer is off.</typeparam>
internal class CircularBuffer<T>{
private readonly int size;
private readonly T[] buffer;
private int readPosition = 0;
private int writePosition = 0;
/// <summary>
/// Initialize the buffer with the buffer size of <paramref name="size"/>.
/// </summary>
/// <param name="size">
/// The size the buffer will have
/// </param>
public CircularBuffer(int size)
{
this.size = size;
buffer = new T[size];
}
/// <summary>
/// Adds an item and move the write position to the next value
/// </summary>
/// <param name="item">The item that should be written.</param>
public void Add(T item)
{
buffer[writePosition] = item;
writePosition = (writePosition + 1) % size;
}
/// <summary>
/// Reads on value and move the position to the next value
/// </summary>
/// <returns></returns>
public T Read(){
var value = buffer[readPosition];
readPosition = (readPosition + 1) % size;
return value;
}
/// <summary>
/// Read the full buffer.
/// While the buffer is read, the read position is moved to the next value
/// </summary>
/// <returns></returns>
public T[] ToArray()
{
var result = new T[size];
for (int i = 0; i < size; i++)
{
result[i] = Read();
}
return result;
}
}
}