我有dll依赖项目,如下所示: DataAccessLayer(DAL)< - BusinessLogicLayer(BLL)< - MVC Web App(WEB)
项目需要通过单独的SQL登录连接数据库(每个SQL登录意味着不同的App用户,或者换句话说,现有的数据库用户和密码将用作app用户/登录)。因此,您无法使用默认连接。
我正在传递类“Connection”(类是在BLL上定义,所以DAL可以看到但是WEB不能)到我的Context类来连接数据库,如下所示:
public class WMSContext : DbContext
{
public WMSContext(Connection con)
: base(con.ContextOption)
{
}
public virtual DbSet<Users> Users { get; set; }
public virtual DbSet<Groups> Groups { get; set; }
public virtual DbSet<UsersConfig> UsersConfig { get; set; }
public virtual DbSet<UsersGroup> UsersGroup { get; set; }
public virtual DbSet<UsersGroupConfig> UsersGroupConfig { get; set; }
public virtual DbSet<ShipmentVehicles> ShipmentVehicles { get; set; }
public virtual DbSet<VSHIPMENTS> VSHIPMENTS { get; set; }
public virtual DbSet<VShipmentsDetails> VShipmentsDetails { get; set; }
}
public class Connection
{
public string Login { get; private set; }
public string Password { get; private set; }
public string Server { get; private set; }
public string Database { get; private set; }
public DbContextOptions<WMSContext> ContextOption { get; private set; }
public Connection(string servAddr, string dbName, string login, string pass)
{
Login = login;
Password = pass;
Server = servAddr;
Database = dbName;
string connStr = "Data Source = " + servAddr + "; Initial Catalog = "+ dbName + "; Persist Security Info = True; User ID = "+ login + "; Password = "+ pass+ "";
var optBuild = new DbContextOptionsBuilder<WMSContext>();
optBuild.UseSqlServer(connStr);
ContextOption = optBuild.Options;
}
}
问题是Connection类的实例应该在用户会话期间存储在某处以执行对某些SQL用户的其他请求。我的第一个想法是将Connection的实例分配给Session。如下所示:
Connection = new Connection(){some login data} HttpContext.Session.SetString(“登录数据”,连接);
但在这种情况下,我必须将DAL设置为依赖于WEB,它似乎不是优雅的解决方案。当然我可以将Connection类提取到将由所有项目共享的类liblary,但我很好奇是否有某种方法只在BLL中存储数据而且只是临时的并且在WEB用户会话结束时删除它们? 或者除了使用Sessions之外还有其他方式吗?
答案 0 :(得分:1)
I suggest you create a context object with an interface that you can inject into the DAL. That way the DAL will depend on your interface but not on any web-specific APIs.
For example
interface IDatabaseAuthenticationContext
{
string DatabaseUserName { get; set; }
string DatabasePassword { get; set ; }
}
class AuthenticationContext: IDatabaseAuthenticationContext
{
private readonly HttpContextBase _httpContext;
public AuthenticationContext(HttpContextbase httpContext)
{
_httpContext = httpContext;
}
public string DatabaseUserName
{
get
{
return _httpContext.Session["DatabaseUserName"];
}
set
{
_httpContext.Session["DatabaseUserName"] = value;
}
}
public string DatabasePassword
{
get
{
return _httpContext.Session["DatabasePassword"];
}
set
{
_httpContext.Session["DatabasePassword"] = value;
}
}
}
Then in your DAL:
class DataAccessLayer : IDataAccessLayer
{
private readonly IDatabaseAuthenticationContext _dbAuthenticationContext;
public DataAccessLayer(IDatabaseAuthenticationContext context)
{
_dbAuthenticationContext = context; //Injected
}
public void ExecuteSomeCommand()
{
using (var conn = new SqlConnection(this.CreateConnectionString()))
{
var cmd = new SqlCommand("SomeCommand");
cmd.CommandType = StoredProcedure;
cmd.Connection = conn;
cmd.ExecuteNonQuery();
}
}
private string CreateConnectionString()
{
return String.Format("Server={0};UID={1};PWD={2}", this.GetServerName(),
_dbAuthenticationContext.DatabaseUserName,
_dbAuthenticationContext.Databasepassword);
}
Then in your composition root:
container.RegisterType<IDatabaseAuthenticationContext, AuthenticationContext>();
container.RegisterType<HttpContextBase, () => new HttpContextWrapper(HttpContext.Current));
container.RegisterType<IDataAccessLayer, DataAccessLayer>();
This way you can pass what you need to the DAL without requiring the DAL to know anything about HttpContext
or other web-specific APIs. If you ever write a console application (or other program without a reference to System.Web), you just need to write a different implementation of AuthenticationContext
that implements IDatabaseAuthenticationContext
.