1

How do I connect to multiple database instances from a Blazor WebAssembly project, where I have also added the ASP.NET Core hosted?

My thought was to initiate the DBContexts into the `Startup.cs`` (from Blazor.Server Application which has a reference to Blazor.Client Application):

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<DatabaseContext>(options =>
            options.UseSqlite(
                "connection string holder ..."));
}

like this but I want to let the user choose in my View if they want to do a test run of the App where the SQLite database instance will be created. The regular run will be an instance to SQL Server database. How can I do this in the ConfigureServices method?

Right now I am building the DBContexts classes, are these effected too?

The controllers are not done yet, are ASP.NET Core MVC controllers the right choice?

Maytham Fahmi
  • 31,138
  • 14
  • 118
  • 137
brstkr
  • 1,423
  • 3
  • 18
  • 28
  • blazor is not MVC, do not mix razor and blazor (https://learn.microsoft.com/en-us/aspnet/core/blazor/?view=aspnetcore-3.1) – Maytham Fahmi May 30 '20 at 10:31
  • 1
    regarding multiple database, it is not thing to do with blazor, check this https://stackoverflow.com/questions/43767933/entity-framework-core-using-multiple-dbcontexts – Maytham Fahmi May 30 '20 at 10:33
  • 1
    There is nothing about multiple DB connections in Blazor WASM app.. Blazor WASM is an UI framework just like any frontend framework. For DB operations, you will have to create a Web API and create multiple DbContexts for multiple DB connections. – Rahul May 30 '20 at 12:22
  • @Rahul Well that was what I have done with the "WebAssembly ASP.NET Core Hosted" meant. My Project structure is now Blazor.Client , Blazor.Server and Blazor.Shared Lib. So now I have the Startup.cs in the Server Project where I will put my Controllers in. Why is the multiple DB connection not possible? I didn't understand that yet. – brstkr May 30 '20 at 12:27
  • @maytham-ɯɐɥʇʎɐɯ can't I do it in the Blazor.Server Project? Which was created when I checked the ASP.NET Core Hosted option before creating the WebAssembly. – brstkr May 30 '20 at 12:28
  • there is no white or black solution, I guess in your case you have created a blazor template created by visual studio, and it contains 3 elements blazor client for front end. blazor server which is pure api (dont get confused by Blazor.Server in this case) with has "controllers" which you should use for your multiple database connetion etc. and common is what ever shared for back (server) and front (client) end. In blazor that are some thing which can also confuse, Blazor server-side vs client-side (WebAssembly) What's the Difference check this video https://www.youtube.com/watch?v=HFvPKmS2gig – Maytham Fahmi May 30 '20 at 12:42
  • The Blazor angle here is the DI. – H H May 30 '20 at 14:37

3 Answers3

2

You can implement that using 2 DB contexts, one interface and a service choosing the context from data sent in API requests:

DB context interface

public interface IDatabaseContext
{
// add all DbSet declaration here
}

db context

public class DatabaseContext : IDatabaseContext
{
// db context implementation
}

Test db context

public class TestDatabaseContext: DatabaseContext
{
// add your constructor
}

DbContext resolver service

public class DbContextResolver
{
    public bool IsTest { get; set; }

Server side DI setup

services.AddDbContext<DatabaseContext>(options =>
            options.UseSqlServer(
                "SqlServer connection string holder ..."))
        .AddDbContext<TestDatabaseContext>(options =>
            options.UseSqlite(
                "Sqlite connection string holder ..."))
        .AddScoped<DbContextResolver>())
        .AddScoped<IDatabaseContext>(p =>
        {
            var resolver = p.GetRequiredService<DbContextResolver>();
            if (resolver.IsTest)
            {
                retrun p.GetRequiredService<TestDatabaseContext>();
            }
            return p.GetRequiredService<DatabaseContext>();
        }));

Select the DB Context from request

public void Configure(IApplicationBuilder app)
{
     app.Use((context, next) =>
     {
          var resolver = context.RequestServices.GetRequiredService<DbContextResolver>();
          resolver.IsTest = context.Request.Query.ContainsKey("test"); // here the context is choosed by query string but you can choose to send an header instead
          return next();
     }
}

use the chosen DB context in controller or a service

public class MyController : Controller
{
     public MyController(IDatabaseContext context)
...
}
agua from mars
  • 16,428
  • 4
  • 61
  • 70
  • Have not been able to implement that yet but is it possible to change the resolver while in runtime? And also how do I change the resolver state? Like is it possible to do it via inject in the UI and set the bool value via a button click? Sorry I am kinda new to this ASP.NET Core web stuff and wanna learn. – brstkr Jun 16 '20 at 19:40
0

I haven't tried but you can try something like this-

In Blazor client Program.cs -

builder.Services.AddDatabaseStorage();

In Blazor server Startup.cs -

   public void ConfigureServices(IServiceCollection services)
    {
        services.AddDatabaseStorage();
    }

Create a static class and add all the DB storage interfaces and their implementations-

public static class StorageServiceCollections
{
    public static IServiceCollection AddDatabaseStorage(this IServiceCollection 
 services)
    {
  //you may also return DB service based on certain condition here. Like factory, singleton pattern.
        return services
            .AddSingleton<IDBStorageService, SQLStorageService>()
            .AddSingleton<IMongoDBStorageService, MongoStorageService>();
    }
}

Stablish DB connections and their implementation classes e.g. SQLStorageService, MongoStorageService Something like this -

  public MongoStorageService()
    {
        var client = new MongoClient("mongodb://localhost:23456");
        _mongoDatabase = client.GetDatabase("DB");
    }

Inject in razor components to call them -

@inject IDBStorageService dbStorage
0

Server side Blazor :

services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
services.AddDbContext<ApplicationDbContext>(options => options.UseFirebird(Configuration.GetConnectionString("FirebirdConnection"));

Then register your service:

services.AddSingleton<SalesService>();

where your service has a model you can return using any connection:

public Task<Sales[]> GetSalesRangeAsync(DateTime StartDate, DateTime EndDate)
{
    IDbConnection db = new FbConnection(Startup.FirebirdDatabase);
    
    // QUERY
    return Task.FromResult(Enumerable.Range(0, 1).Select(index => new Sales
    {
        // RESULTS
    }).ToArray());
}
Johan Aspeling
  • 765
  • 1
  • 13
  • 38
Jez
  • 1
  • 1