以前是Web Forms
应用程序,我在MVC中重写它。
连接名称存储在用户的详细信息中,根据用户的不同,我需要传递不同的连接名称。
在WebForms
中,这是通过在Session
中设置Global.asax
变量来解决的,然后每次需要上下文时,我都会在using语句中创建上下文,并通过上下文构造函数中的Session
变量如下:
using (IAccountContext db = new MainContext(Session["cn"]) { }
在MVC
中,我将上下文声明为字段:
public class ManageController : BaseController
{
private readonly IAccountContext _db = new MainContext(ConnectionName);
// other actions
}
我无法传递非静态Session
变量。我尝试使用其他控制器将继承的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);
}
}
我试图避免在每个using
中使用Action
子句,并依赖MVC
在Dispose
方法中处理上下文。
关于如何使这项工作的任何想法?
修改
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
答案 0 :(得分:1)
在RequestContext
方法中使用Initialize()
。
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);
}
}
答案 1 :(得分:0)
在执行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。
我不知道你是否熟悉我在说什么。如果您需要,我可以写更详细的说明。