在会话

时间:2017-07-14 14:58:30

标签: c# asp.net asp.net-mvc session asp.net-core

我有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之外还有其他方式吗?

1 个答案:

答案 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.