Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Orleans direct client in ASP.NET Core project

Tags:

orleans

I am currently looking into Orleans as a backend for Asp.net core web api project, and was wondering if anyone has any experience with its new feature - "direct client". The orleans docs say "it allows co-hosting a client and silo in a way that let the client communicate more efficiently with not just the silo it's attached to, but the entire cluster", and I am aware that you can code something like this (and it works just fine in a console app):

var silo = new SiloHostBuilder()
               .UseLocalhostClustering()
               .EnableDirectClient()
               .Build();

await silo.StartAsync();

var client = silo.Services.GetRequiredService<IClusterClient>();

I am struggling trying to figure out where to put this type of code in an asp.net project that has its own webhost builder in "Main" (should it go to Startup class in "ConfigureServices"?). In the end, we are aiming for a separate client/server setup, but for faster development it would be useful to play with a simple setup, which direct client appears to allow for. Any pointers to resources and/or sample solutions containing direct client with asp.net core would be appreciated. Thanks.

EDIT: Here's the code that kinda works for me now, but I am not happy with he way the DI is set up

public static async Task Main(string[] args)
        {

            var silo = new SiloHostBuilder()
                    .UseLocalhostClustering()
                    .ConfigureServices(services =>
                    {
                        services.AddDbContext<UserDbSet>(o =>  o.UseSqlite("Data Source=UserTest.db"));
                        services.AddMediatR(typeof(Startup).Assembly);
                    })
                    .EnableDirectClient()
                    .Build();

            await silo.StartAsync();

            var client = silo.Services.GetRequiredService<IClusterClient>();

            await WebHost.CreateDefaultBuilder(args)
                        .UseConfiguration(new ConfigurationBuilder()
                            .AddCommandLine(args)
                            .Build())
                        .ConfigureServices(services =>
                            services
                             .AddSingleton<IGrainFactory>(client)
                             .AddSingleton<IClusterClient>(client))
                        .UseStartup<Startup>()
                        .Build()
                        .RunAsync();
        }

If I put registration of the DbContext and Mediatr in the StartUp class, grain code fails with an exception indicating failure to instantiate the required dependencies. Maybe I am doing something wrong when setting up the Webhost?

like image 306
Milogrim Avatar asked Jan 01 '23 06:01

Milogrim


1 Answers

For ASP.NET 2.x & Orleans below 2.3, I recommend creating & starting the silo before the Web host. When configuring the Web host, inject the IGrainFactory & IClusterClient instances from the silo (obtained via silo.Services):

var silo = new SiloHostBuilder()
    .UseLocalhostClustering()
    .EnableDirectClient()
    .Build();

await silo.StartAsync();

var client = silo.Services.GetRequiredService<IClusterClient>();

var webHost = new WebHostBuilder()
    .ConfigureServices(services =>
        services
            .AddSingleton<IGrainFactory>(client)
            .AddSingleton<IClusterClient>(client))
    .UseStartup<Startup>()
    // Other ASP.NET configuration...
    .Build();

For ASP.NET 3.0 & Orleans 2.3 or greater, the integration code becomes simpler due to the addition of Microsoft.Extensions.Hosting support in both frameworks:

var host = new HostBuilder()
    .ConfigureWebHost(builder =>
    {
        // Adding IGrainFactory, etc, is not necessary, since Orleans 
        // and ASP.NET share the same dependency injection container.
        builder.UseStartup<Startup>();
    })
    .UseOrleans(builder =>
    {
        // EnableDirectClient is no longer needed as it is enabled by default
        builder.UseLocalhostClustering();
    })
    .Build();

await host.StartAsync();
like image 165
Reuben Bond Avatar answered Feb 24 '23 13:02

Reuben Bond