Also habe ich endlich alles ausgearbeitet.Ich gab die Fabrikidee auf, weil ich mich nicht wohl fühle mit , um Zeit damit zu verbringen, es auszuarbeiten & Ich rase kopfüber in eine Frist, so dass die schnelleren Optionen jetzt die besseren sind und ich immer Zeit finde um zu refaktorieren der Code später (lol).
Meine appsettings.json
Datei enthält derzeit nur die folgenden (das entsprechende Bit von appsettings.Developments.json
identisch ist):
{
"ConnectionStrings" : {
"Accounts": "Server=testserver;Database=Accounts;Trusted_Connection=True;",
"Client": "Server=testserver;Database={CLIENT_DB};Trusted_Connection=True;",
"Configuration": "Server=testserver;Database=Configuration;Trusted_Connection=True;"
},
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
ich entschieden habe, die beiden statischen Datenbanken in den ConfigureServices Methode von StartUp, zu konfigurieren Diese sollten konfiguriert und einsatzbereit sein, wenn die Anwendung dazu übergeht, etwas zu tun. Der Code dort ist nett & sauber.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.Configure<MvcOptions>(options =>
{
//options.Filters.Add(new RequireHttpsAttribute());
});
services.AddDbContext<AccountsContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("Accounts"))
);
services.AddDbContext<ConfigContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("Configuration"))
);
services.AddSingleton(
Configuration.GetSection("ConnectionStrings").Get<ConnectionStrings>()
);
}
Es stellt sich heraus, dass man die Qual der Wahl werden kann, wie in der appsettings.json
gesetzt über den Zugriff auf die Konfigurationsoptionen zu gehen, ich bin derzeit zu arbeiten versuchen, wie ich habe es geschafft, es zu dem wechseln zu erhalten Release-Version statt der Entwicklungsversion. Ich kann nicht denken, was ich getan habe, um das zu schalten ...
Um die Platzhalter-Konfigurationseinstellung zu erhalten, verwende ich einen Singleton, um den Zeichenfolgenwert zu halten. Dies taucht nur in die Gruppe "ConnectionStrings" ein und stopft diesen Json in das Objekt "ClientConnection" (siehe unten).
services.AddSingleton(
Configuration.GetSection("ConnectionStrings").Get<ClientConnection>()
);
Welche der folgenden Struktur auffüllt (die ich gerade in einer eigenen Datei aus bunged haben):
[DataContract(Name = "ConnectionStrings")]
public class ClientConnection
{
[DataMember]
public string Client { get; set; }
}
nur ich diese die Verbindungszeichenfolge für die dynamisch zugewiesene Datenbank halten wollen, so ist es nicht zu jazzig. Der "Client" DataMember ist, was den richtigen Schlüssel in der JSON auswählt, wenn ich einen anderen benannten Knoten in der JSON wollte, würde ich ihn zum Beispiel in "Konten" umbenennen.
Noch ein paar Optionen, die ich getestet, bevor sie auf die Option Singleton Absetzen, sind:
services.Configure<ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));
und
var derp = Configuration.GetSection("ConnectionStrings:Client");
Was ich diskontiert, aber es lohnt sich andere Optionen zu kennen (sie werden wahrscheinlich nützlich sein, um später andere Konfigurationsoptionen zu laden.
Ich bin nicht scharf darauf, wie die Controller-Abhängigkeiten in ASP.Net Core 2 arbeiten, ich hatte gehofft, dass ich sie in einem BaseController verstecken könnte, damit sie nicht in jedem einzelnen Controller angegeben werden müssten Ich knock out, aber ich habe keinen Weg gefunden, dies zu tun ja. Die Abhängigkeiten, die in den Controllern benötigt werden, werden im Konstruktor übergeben, diese haben mich für eine Weile irritiert, weil sie automatisch magisch injiziert werden.
My Basecontroller eingerichtet ist, wie folgt:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.EntityFrameworkCore.Internal;
using ServiceLayer.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ServiceLayer.Controllers
{
public class BaseController : Controller
{
private readonly ClientConnection connectionStrings;
private readonly AccountsContext accountsContext;
private readonly ConfigurationContext configContext;
public ClientTemplateContext clientContext;
private DbContextServices DbContextServices { get; set; }
public BaseController(AccountsContext accounts, ConfigContext config, ClientConnection connection) : base()
{
accountsContext = accounts;
configContext = config;
connectionStrings = connection;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
}
}
}
Der Code für die Auswahl der Datenbank geht dann in den "OnActionExecuting()" Methode; dies erwies sich auch ein wenig nervig sein, um sicherzustellen versuchen, dass die dbcontext richtig, ich ließ sich in dem Ende eingesetzt wurde:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ServiceLayer.Controllers
{
public class BaseController : Controller
{
private readonly ClientConnection connectionStrings;
private readonly AccountsContext accountsContext;
private readonly ConfigurationContext configContext;
public ClientTemplateContext clientContext;
private DbContextServices DbContextServices { get; set; }
public BaseController(AccountsContext accounts, ConfigurationContext config, ClientConnection connection) : base()
{
accountsContext = accounts;
configContext= config;
connectionStrings = connection;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
// Temporary selection identifier for the company
Guid cack = Guid.Parse("827F79C5-821B-4819-ABB8-819CBD76372F");
var dataSource = (from c in configContext.Clients
where c.Cack == cack
join ds in configContext.DataStorage on c.CompanyId equals ds.CompanyId
select ds.Name).FirstOrDefault();
// Proto-connection string
var cs = connectionStrings.Client;
if (!string.IsNullOrEmpty(cs) && !string.IsNullOrEmpty(dataSource))
{
// Populated ConnectionString
cs = cs.Replace("{CLIENT_DB}", dataSource);
clientContext = new ClientTemplateContext().Initialise(cs);
}
base.OnActionExecuting(context);
}
}
}
new ClientTemplateContext().Initialise()
ein bisschen chaotisch, aber ich werde es aufzuräumen, wenn Ich refaktoriere alles andere. "ClientTemplateContext" ist die entity-framework-core generierte Klasse, die alle generierten Entitäten miteinander verbindet. Ich habe der Klasse den folgenden Code hinzugefügt (ich habe versucht, sie in eine separate Datei zu schreiben, aber das funktioniert nicht, also bleibt sie dort für den Moment) ...
public ClientTemplateContext() {}
private ClientTemplateContext(DbContextOptions options) : base(options) {}
public ClientTemplateContext Initialise(string connectionString)
{
return new ClientTemplateContext().CreateDbContext(new[] { connectionString });
}
public ClientTemplateContext CreateDbContext(string[] args)
{
if (args == null && !args.Any())
{
//Log error.
return null;
}
var optionsBuilder = new DbContextOptionsBuilder<ClientTemplateContext>();
optionsBuilder.UseSqlServer(args[0]);
return new ClientTemplateContext(optionsBuilder.Options);
}
ich habe auch using Microsoft.EntityFrameworkCore.Design;
und hinzugefügt, um die IDesignTimeDbContextFactory<ClientTemplateContext>
Schnittstelle zur Klasse. So sieht es wie folgt aus:
public partial class ClientTemplateContext : DbContext, IDesignTimeDbContextFactory<ClientTemplateContext>
Hier wird die CreateDbContext(string[] args)
von & kommt es uns eine neue Instanz einer abgeleiteten Kontext zur Entwurfszeit erstellen können.
Schließlich ist der Code für meinen Test-Controller wie folgt:
using Microsoft.AspNetCore.Mvc;
using ServiceLayer.Entities;
using System.Collections.Generic;
using System.Linq;
namespace ServiceLayer.Controllers
{
[Route("api/[controller]")]
public class ValuesController : BaseController
{
public ValuesController(
AccountsContext accounts,
ConfigurationContext config,
ClientConnection connection
) : base(accounts, config, connection) {}
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
var herp = (from c in clientContext.Usage
select c).FirstOrDefault();
return new string[] {
herp.TimeStamp.ToString(),
herp.Request,
herp.Payload
};
}
}
}
Dieses erfolgreich liefert Daten aus der Datenbank dynamisch aus der Datasource Tabelle in der DatenbankKonfiguration ausgewählt!
["01/01/2017 00:00:00","derp","derp"]
Wenn jemand Verbesserungen meiner Lösung vorschlagen kann ich sie gerne sehen würde, ist meine Lösung püriert zusammen, wie es steht & ich es so bald Refactoring wollen, wie ich ich bin kompetent genug fühlen, dies zu tun .