* Getting started with Actor testability
* Added unitests against the Actor Class.
This is to verify that there are no breaking changes, and that the actor class can take any ActorStateManager.
* removed the private constructor
* resolving an issue with causing a null reference exception.
This was caused by an incorrect order of assignment in the constructor.
* Getting started with Actor testability
* Added unitests against the Actor Class.
This is to verify that there are no breaking changes, and that the actor class can take any ActorStateManager.
* removed the private constructor
* Updated samples/Actor to show Timer and Reminder functionality
* Updated ActorClient. Changed deregistration of TImer and Reminder at the end of the program
Co-authored-by: Leon Mai <lemai@microsoft.com>
Co-authored-by: Aman Bhardwaj <amanbha@users.noreply.github.com>
* The .NET API states that passing `period: TimeSpan.FromMilliseconds(-1)` to `RegisterReminderAsync` should mean that the riminder never triggers on a recurrence.
When doing so, the serialization of the reminder means that
`IRemindable.ReceiveReminderAsync()` will be called with the dueTime value passed in the state parameter.
I figured that out because I passed an UTF8 JSON string as state, and `IRemindable.ReceiveReminderAsync()` received "0h0m0s1ms" as state, instead of my own value.
## Repro
```csharp
namespace Core.Application.Common.ActorImplementations
{
using System;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Dapr.Actors;
using Dapr.Actors.Runtime;
using Core.Domain;
public class FlightServiceQueryActorState
{
public string CoordinatorId { get; set; }
public byte[] ToBytes() => Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(this));
public static FlightServiceQueryActorState FromBytes(byte[] bytes) => JsonConvert.DeserializeObject<FlightServiceQueryActorState>(Encoding.UTF8.GetString(bytes));
}
[Actor(TypeName = ActorNames.FlightServiceQueryActor)]
public class FlightServiceQueryActor : Actor, IRemindable, IFlightServiceQueryActor
{
public FlightServiceQueryActor(ActorService actorService, ActorId actorId) : base(actorService, actorId) { }
const string AfterTickReminder = "AfterTick";
static readonly TimeSpan Never = TimeSpan.FromMilliseconds(-1);
async Task IFlightServiceQueryActor.Tick(string senderId, int duration)
{
var state = new FlightServiceQueryActorState { CoordinatorId = senderId };
await base.RegisterReminderAsync(
reminderName: AfterTickReminder,
state: state.ToBytes(),
dueTime: TimeSpan.FromMilliseconds(1),
period: Never);
await Console.Out.WriteLineAsync($"Tick tock {this.Id.GetId()}");
}
async Task IRemindable.ReceiveReminderAsync(string reminderName, byte[] stateBytes, TimeSpan dueTime, TimeSpan period)
{
var state = FlightServiceQueryActorState.FromBytes(stateBytes);
var coordinator = ActorProxies.CreateFlightTravelCoordinationFor(state.CoordinatorId);
await Console.Out.WriteLineAsync($"Reminder {this.Id.GetId()} -- {state.CoordinatorId}");
}
}
}
```
## Result
```text
time="2020-01-25T11:37:35+01:00" level=error msg="error executing reminder: error from actor service: "
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HLT1GA8OGV6N", Request id "0HLT1GA8OGV6N:00000006": An unhandled exception was thrown by the application.
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
at Dapr.Actors.Runtime.ConverterUtils.ConvertTimeSpanFromDaprFormat(String valueString) in C:\github\dapr\dotnet-sdk\src\Dapr.Actors\Runtime\ConverterUtils.cs:line 28
at Dapr.Actors.Runtime.ReminderInfo.DeserializeAsync(Stream stream) in C:\github\dapr\dotnet-sdk\src\Dapr.Actors\Runtime\ReminderInfo.cs:line 56
at Dapr.Actors.Runtime.ActorManager.FireReminderAsync(ActorId actorId, String reminderName, Stream requestBodyStream, CancellationToken cancellationToken) in C:\github\dapr\dotnet-sdk\src\Dapr.Actors\Runtime\ActorManager.cs:line 162
at Dapr.Actors.AspNetCore.RouterBuilderExtensions.<>c.<<AddReminderRoute>b__4_0>d.MoveNext() in C:\github\dapr\dotnet-sdk\src\Dapr.Actors.AspNetCore\RouterBuilderExtensions.cs:line 101
```
* Serializes DueTime and Period only when non-negative
* Empty values become default
* Not checking dueTime for negative values. Missing reminder attributes or empty string reminders are equal to "never".
Co-authored-by: Aman Bhardwaj <amanbha@users.noreply.github.com>
* Including state Store name in the APIs to support multi state store scenario in SDK
* correcting the typo in the comment.
* Respective Changes to the tests
* Changes in StateAttribute and Binder classes to support state store name
* Changes in StateEntryModelBinderTests
* StoreName changes in the Integration test app
* fixing build issues
* Fixing integration tests
* Addressing review comments.
* Addressing review comments
* Updating samples to use correct state store name as generated by dapr cli.
Co-authored-by: Aman Bhardwaj <amanbha@users.noreply.github.com>
* Placing new proto file from dapr repo, generated from multistate store change
* Resolving code review comments - fixing the sample code.
Tested the sample with the changes.
Fixes: #192
We were missing tests for the case where the HttpClient has a
BaseAddress set. In these case we'd generate an incorrect URL.
Co-authored-by: Aman Bhardwaj <amanbha@users.noreply.github.com>
* Add InvokeClient and InvokeHttpClient dapr #184
* Add tests for InvokeHttpClient dapr#184
* Update namespace of InvokeHttpClient dapr#184
* Add DI of InvokeHttpClient dapr#184
* Resolve code format issues dapr#184
* Remove InvokeEnvelope and add params to InvokeMethod dapr#184
* Update method signature to use generic types for Request/Response dapr#184
* Update parameter in data null check dapr#184
* Making Serialization, Deserialization of ReminderInfo, Timer async and using System.Text.Json for Reminder, Timer and State,
* Updating tests.
* Addressing review comment: Passing stream directly to serializer.
* Removing dependency on Newtonsoft.Json
* Revert "Removing dependency on Newtonsoft.Json"
This reverts commit 0315781bd0.
* Refactored ActorRuntime to allow testing.
* Add test for inferred actor type.
* Add RegisterActor() overload.
* Consolidate RegisterActor() implementations.
* Refactor to make type still intrinsic to actor implementation.
* Update docs.
* Revert error codes change.
* Updates per PR feedback.
* Add warning to ActorRuntime constructor.