设置上下文';的连接名称,具体取决于登录的用户

本文关键字:取决于 用户 登录 上下文 连接 设置 | 更新日期: 2023-09-27 18:19:58

这曾经是一个Web Forms应用程序,我正在MVC中重写它。

连接名称存储在用户的详细信息中,根据用户的不同,我需要传递不同的连接名称。

WebForms中,这是通过在Global.asax中设置Session变量来解决的,然后每次需要上下文时,我都会在using语句中创建上下文,在上下文构造函数中传递Session变量,如下所示:

using (IAccountContext db = new MainContext(Session["cn"]) { }

MVC中,我将上下文声明为一个字段:

public class ManageController : BaseController
{    
    private readonly IAccountContext _db = new MainContext(ConnectionName);
    // other actions
}

并且我不能传递非静态的CCD_ 7变量。我尝试使用其他控制器将继承的BaseController,并尝试在构造函数和Initialize方法中初始化ConnectionName,但都不起作用

public class BaseController : Controller
{
    public BaseController()
    {
        using (var db = new UserDbContext())
        {
            ConnectionName = (db.Users.Find(User.Identity.GetUserId())).ConnectionString; 
        }
    }
    public static string ConnectionName { get; set; }
    protected override void Initialize(RequestContext requestContext)
    {
        using (var db = new UserDbContext())
        {
            ConnectionName = (db.Users.Find(User.Identity.GetUserId())).ConnectionString;
        }
        base.Initialize(requestContext);
    }
}

我试图避免在每个Action中使用using子句,并依靠MVCDispose方法中处理上下文。

有什么想法可以让它发挥作用吗?

编辑:

Francesc Castells的答案看起来很有希望,但当使用BaseController时,User.Identity.GetUserID()调用会抛出一个NullReference异常。如果ManageController继承了原来的Controller,它就可以正常工作。我是不是忘记初始化其他东西了?

这是Stacktrace

[NullReferenceException: Object reference not set to an instance of an object.]
   TestProj.Web.Controllers.BaseController..ctor() in E:'TestProj.Web'Controllers'BaseController.cs:14
   TestProj.Web.Controllers.ManageController..ctor() in E:'TestProj.Web'Controllers'ManageController.cs:60
[TargetInvocationException: Exception has been thrown by the target of an invocation.]
   System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
   System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +119
   System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +232
   System.Activator.CreateInstance(Type type, Boolean nonPublic) +83
   System.Activator.CreateInstance(Type type) +11
   System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +55
[InvalidOperationException: An error occurred when trying to create a controller of type 'TestProj.Web.Controllers.ManageController'. Make sure that the controller has a parameterless public constructor.]
   System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +178
   System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +76
   System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +88
   System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +194
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +50
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +48
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +16
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +103
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

设置上下文';的连接名称,具体取决于登录的用户

Initialize()方法中使用RequestContext

public class BaseController : Controller
{
    protected string _connectionName;
    protected override void Initialize(RequestContext requestContext)
    {
        if(requestContext.HttpContext.User.Identity.IsAuthenticated)
        {
            using (var db = new UserDbContext())
            {
                _connectionName = db.Users.Find(
                    requestContext.HttpContext.User.Identity.GetUserId())
                    .ConnectionString;
            }
        }
        base.Initialize(requestContext);
    }
}

现在你可以简单地继承你的控制器:

public class ManageController : BaseController
{
    private IAccountContext _db          
    protected override void Initialize(RequestContext requestContext)
    {
        base.Initialize(requestContext);
        _db = new MainContext(_connectionName);
    }
    public ActionResult MyAction()
    {
        // now you have access _db variable
    }
    protected override void Dispose(bool disposing)
    {
        if(disposing)
        {
            _db.Dispose();
        }
        base.Dispose(disposing);
    }
}
执行BaseController构造函数并初始化ConnectionName之后,在构造函数中创建MainContext。
public class ManageController : BaseController
{    
    private readonly IAccountContext _db;
    public ManageController()
    {
          // Here the base constructor has already been executed, so ConnectionName has the right value
         _db = new MainContext(ConnectionName);
    }
   // other actions
 }

但我建议一种不同的方法:将依赖注入与IoC一起使用,例如Unity。向InjectionFactory注册您的IAccountContext,这将是一个简单的方法,它将运行您已经拥有的代码,以获得基于User.Identity.GetUserId()的连接字符串,并创建传递发现的连接字符串的AccountContext。

我不知道你是否熟悉我说的话。如果你需要,我可以写更详细的说明。