0

The given following example works fine:

namespace Test
{
    public class Program
    {
        static async Task Main(string[] args)
        {
            using var host = new HostBuilder()
                .UseOrleans(builder =>
                {
                    builder.UseLocalhostClustering();
                })
                .Build();

            await host.StartAsync();

            var grainFactory = host.Services.GetRequiredService<IGrainFactory>();
            var friend = grainFactory.GetGrain<ITestGrain<bool>>("friend");
            CancellationTokenSource ctSource = new();
            var test = await friend.Test(ctSource.Token);
            Console.WriteLine("Test: " + test);

            await host.StopAsync();
        }
    }

    public interface ITestGrain<TType> : IGrainWithStringKey
    {
        public Task<TType> Test(CancellationToken? cancellationToken = default);
    }

    public class TestGrain : Grain, ITestGrain<bool>
    {
        public Task<bool> Test(CancellationToken? cancellationToken = default) =>
        Task.FromResult(true);
    }
}

Imported packages in .csproj

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <ItemGroup>
        <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2" />
        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2" />
        <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.2" />
        <PackageReference Include="Microsoft.Orleans.Client" Version="9.1.2" />
        <PackageReference Include="Microsoft.Orleans.Core" Version="9.1.2" />
        <PackageReference Include="Microsoft.Orleans.Core.Abstractions" Version="9.1.2" />
        <PackageReference Include="Microsoft.Orleans.Server" Version="9.1.2" />
        <PackageReference Include="OrleansDashboard" Version="8.2.0" />
    </ItemGroup>
</Project>

This minimal example works and produces the expected output:

Test: True

When I switch to a webapplication builder I get the following exception.

var builder = WebApplication.CreateBuilder(args);
//using var host = new HostBuilder()
builder
    .UseOrleans(builder =>
    {
        builder.UseLocalhostClustering();
    });
    //.Build();

    var host = builder.Build();

Orleans.Serialization.CodecNotFoundException: 'Could not find a codec for type System.Threading.CancellationToken.'

I know that providing a CancellationToken to a .NET Orleans grain method doesn't make any sense. I don't want to rewrite my API (remove CancellationToken parameter) in case I am switching to another medium where CancellationTokens are supported.

Still I wondered what are the differences between running .NET Orleans on a console or web host? I heard that on a console application the grain call is executed locally and nothing has to be serialized, but still when switching to a web application the grain is still hosted inside the same process. Can I configure Orleans to make also the web application version work without throwing a exception?

1 Answer 1

0

By configuring Orleans to serialize also CancellationTokens with System.Text.Json, I made the webapplication version work and also produce the expected output.
For that the nuget package Microsoft.Orleans.Serialization.SystemTextJson must be installed.

builder
    .UseOrleans(siloBuilder =>
    {
        siloBuilder.UseLocalhostClustering();
        siloBuilder.Services.AddSerializer(serializerBuilder =>
        {
            serializerBuilder.AddJsonSerializer(isSupported: typeCand => typeCand == typeof(System.Threading.CancellationToken));
        });
    });

More details and other approaches can be found in the docs (https://learn.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/serialization-configuration?pivots=orleans-7-0#configure-orleans-to-use-systemtextjson).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.