所以,我终于解决了所有问题。我放弃了工厂的想法,因为我对asp.net-core-2.0 不够满意,无法花时间解决它,而且我正匆匆赶到最后期限,所以现在更快的选择是更好的选择,我总能找到时间稍后重构代码(大声笑)。
我的appsettings.json 文件目前只包含以下内容(appsettings.Developments.json 的相关位相同):
{
"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"
}
}
}
}
我已选择在 StartUp 的 ConfigureServices 方法中配置两个静态数据库,这些都应该在应用程序开始时配置并准备好使用不得不做任何事情。那里的代码很好很干净。
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>()
);
}
事实证明,在如何访问appsettings.json 中设置的配置选项方面可能会被宠坏,我目前正在尝试弄清楚我是如何设法让它切换到发布版本的而不是开发的。我想不出我做了什么来切换它...
为了获得占位符配置设置,我使用单例来保存字符串值。这只是浸入“ConnectionStrings”组并将该 Json 填充到“ClientConnection”对象中(详述如下)。
services.AddSingleton(
Configuration.GetSection("ConnectionStrings").Get<ClientConnection>()
);
它填充了以下结构(我刚刚在它自己的文件中删除了):
[DataContract(Name = "ConnectionStrings")]
public class ClientConnection
{
[DataMember]
public string Client { get; set; }
}
我只希望它保存动态分配数据库的连接字符串,所以它不会太花哨。 “Client”DataMember 是在 Json 中选择正确键的原因,例如,如果我想在 Json 中使用不同的命名节点,我会将其重命名为“Accounts”。
在确定单例选项之前,我测试的另外几个选项是:
services.Configure<ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));
和
var derp = Configuration.GetSection("ConnectionStrings:Client");
我打了折扣,但值得了解其他选项(它们可能对稍后加载其他配置选项有用)。
我并不热衷于控制器依赖项在 ASP.Net Core 2 中的工作方式,我希望能够将它们隐藏在 BaseController 中,这样就不必在我的每个控制器中指定它们淘汰,但我还没有找到办法做到这一点是的。控制器中所需的依赖项在构造函数中传递,这些让我有些奇怪,因为它们是自动注入的。
我的BaseController设置如下:
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);
}
}
}
然后选择数据库的代码进入“OnActionExecuting()”方法;事实证明这也有点痛苦,试图确保 dbcontext 设置正确,最后我决定:
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() 有点乱,但我会在重构其他所有内容时清理它。 “ClientTemplateContext”是entity-framework-core 生成的类,它将它生成的所有实体联系在一起,我已将以下代码添加到该类中(我确实尝试将它放在一个单独的文件中但无法使其正常工作,所以它保持不变暂时在里面)...
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);
}
我还包括using Microsoft.EntityFrameworkCore.Design; 并将IDesignTimeDbContextFactory<ClientTemplateContext> 接口添加到类中。所以它看起来像这样:
public partial class ClientTemplateContext : DbContext, IDesignTimeDbContextFactory<ClientTemplateContext>
这就是CreateDbContext(string[] args) 的来源,它允许我们在设计时创建派生上下文的新实例。
最后,我的测试控制器的代码如下:
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
};
}
}
}
这成功地从 Configuration 数据库中的 DataSource 表中动态选择的数据库中生成数据!
["01/01/2017 00:00:00","derp","derp"]
如果有人可以对我的解决方案提出改进建议,我很乐意看到他们,我的解决方案将按原样组合在一起,并且我想在我觉得自己有足够能力这样做时立即对其进行重构。