我从未使用过NHibernate或StructureMap,但我熟悉ORM和依赖注入。
我有一个新项目,它是传统ASP.NET Web窗体和更新的ASP.NET MVC视图和控制器的大杂烩。
我需要从我的代码后面调用一个控制器,我更愿意不要使用WebClient,Web Request等的HttpRequest。
我只想在后面的代码中创建一个控制器实例,并在控制器上调用一个方法。
我知道这不是一个好习惯,但这个小而轻微的项目使这个问题没有问题。
有关如何创建实例的任何建议,使用StructureMap.IContainer
解析此控制器与构造函数arugments,存储库)依赖注入?
以下是代码:
控制器:
[Authorize(Roles = RoleNames.UserManager)]
public partial class UsersController : BaseController
{
private readonly IUserRepository userRepository;
public UsersController(IApplicationSettings applicationSettings, IUserRepository userRepository)
:base(applicationSettings, userRepository)
{
this.userRepository = userRepository;
}
public void SendNewsPostNotification(NewsPostNotificationViewModel viewModel)
{
var users = userRepository.GetAllActiveUsers(); //this is null
foreach (var user in users)
{
if (user.Email == "theemail")
Utility.EmailNewsNotification(user.Email, viewModel.NewsPostId);
}
}
来电者背后的代码:
var viewModel = new NewsPostNotificationViewModel()
{
NewsPostId = newPostId
};
MVC.Users.SendNewsPostNotification(viewModel);
这是在Global.asax.cs.Application_Start()上调用的依赖注入工作:
public static void InitializeNHibernate()
{
HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize();
var mappingAssemblies = new List<Assembly> { typeof(MappingExtensions).Assembly };
var cfg = ConfigurationBuilder.CreateMsSql2005Configuration("tfsql", mappingAssemblies);
var coreRegistry = new CoreRegistry(cfg);
var container = new Container(i =>
{
i.AddRegistry(coreRegistry);
i.Scan(s =>
{
s.IncludeNamespaceContainingType<DashboardController>();
s.AddAllTypesOf<IController>();
});
i.ForSingletonOf<IApplicationSettings>()
.Use(x => new ApplicationSettings());
});
container.AssertConfigurationIsValid();
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory(container));
ConfigurationBuilder.SetBytecodeProvider(new StructureMapBackedBytecodeProvider(container));
MvcApplication.Container = container;
}
我可以进行调用,但UserRepository当然是null:
有用的是,容器设置为MvcApplication
上的属性:
public class MvcApplication : System.Web.HttpApplication
{
[System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
static extern IntPtr LoadLibrary(string lpFileName);
protected void Application_Start()
{
if (Environment.Version.Major >= 4)
{
string folder = HttpContext.Current.Server.MapPath("~/bin");
folder = Path.GetFullPath(folder);
LoadLibrary(Path.Combine(folder, "vjsnativ.dll"));
}
MvcBootstrapper.SetupApplication();
}
// Legacy Container reference for DomainRoleProvider
public static IContainer Container { get; set; }
}
所以我尝试使用以下代码在我的SendNewsPostNotification
控制器方法中获取我需要的UserRepository实例:
var myUserRepository = userRepository ?? MvcApplication.Container.GetInstance<IUserRepository>();
这会导致在NHibernate工作单元中抛出自定义异常消息:
尝试访问事务之外的数据库会话。请确保所有访问都在一个工作单元内进行
您可以在此处查看其代码:
public class NHibernateUnitOfWork : INHibernateUnitOfWork
{
private readonly ISessionFactory sessionFactory;
private ISession currentSession;
public NHibernateUnitOfWork(ISessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
public ISession Session
{
get
{
EnsureStarted();
return currentSession;
}
}
public void Start()
{
if (currentSession == null || !currentSession.Transaction.IsActive)
{
currentSession = sessionFactory.OpenSession();
currentSession.FlushMode = FlushMode.Commit;
currentSession.BeginTransaction();
}
}
public void Finish()
{
EnsureStarted();
currentSession.Transaction.Commit();
}
public void Abort()
{
EnsureStarted();
currentSession.Transaction.Rollback();
}
private void EnsureStarted()
{
if (currentSession == null || !currentSession.Transaction.IsActive)
throw new InvalidOperationException("An attempt was made to access the database session outside of a transaction. Please make sure all access is made within a unit of work.");
}
}
如果我尝试使用容器来获取我的UserController的实例,如下所示:
var viewModel = new NewsPostNotificationViewModel()
{
NewsPostId = newPostId
};
var userController = MvcApplication.Container.GetInstance<TFS.Web.Controllers.UsersController>();
userController.SendNewsPostNotification(viewModel);
我得到了NHibernate工作单元抛出的相同的自定义异常消息:
尝试访问事务之外的数据库会话。请确保所有访问都在一个工作单元内完成。
我还尝试确保使用此StructureMap代码获取IUserRepository的实际具体实例:
IEnumerable<InstanceRef> instances = MvcApplication.Container.Model.AllInstances.
Where(i => i.PluginType == typeof (IUserRepository));
foreach (var instanceRef in instances)
{
myUserRepository = instanceRef.Get<IUserRepository>();
}
但我仍然得到NHibernate工作单元抛出的相同自定义异常消息:
尝试访问事务之外的数据库会话。请确保所有访问都在一个工作单元内完成。
有趣的是,如果我在Code Behind页面中查找IController类型实例,我试图从中调用控制器,没有,请使用以下StructureMap代码进行检查:
IEnumerable<InstanceRef> instances = MvcApplication.Container.Model.AllInstances.
Where(i => i.PluginType == typeof(IController));
foreach (var instanceRef in instances)
{
var tt = instanceRef;
}