创建我自己的使用StructureMap

时间:2015-10-15 00:01:26

标签: c# asp.net-mvc nhibernate dependency-injection structuremap

我从未使用过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: enter image description here

有用的是,容器设置为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;
        }

0 个答案:

没有答案