Hi,

Is this sample still available anywhere? I can't download from Alex's blog:

http://blog.alexyakunin.com/2010/04/new-aspnet-mvc-sample.html

Thanks,

asked Sep 18 '13 at 12:02

TinkererJim's gravatar image

TinkererJim
15113

Hi TinkererJim,

The sample eventually got outdated and therefore was removed. Are there any ASP.NET MVC-specific questions you want us to help you with?

(Sep 18 '13 at 12:50) Dmitri Maximov Dmitri%20Maximov's gravatar image

5 Answers:

Hello Jim,

let me explain some concepts around DO session management and their applications to ASP.NET. DataObjects.Net supports two standard ways of passing session to Entity constructor. Implicit and explicit.

The first one relies on implicit session available everywhere via call to Session.Demand(). Implicit session passing requires session to be activated. Default way of activation is storing reference to session in the internal thread-static field. For ASP.NET this apporach is not reliable because pipeline frequently changes threads during processing of a request. This is where SessionManager comes into play. It overrides standard way of storing an active session. Instead of thread-static field session is stored in HttpContext instance for current request. HttpContext is NOT available during Application_Start event this means your Build() method will not get implict session. However once this method is completed (and Domain is built) you will get activated session and transaction for each request.

Another option is to use explicit session passing. You need to change your persistent types constructors to take session parameter and call Entity constructor overload that also uses session parameter.

Here is a very simple example:

[HierarchyRoot]
public class Product : Entity
{
    [Key, Field]
    public long Id { get; private set; }

    public Product(Session session) : base(session) { }
}

With this approach it's also straightforward to put session into the dependency injection container to treat it as a dependency for controllers.

Some other random notes:

You should never dispose (or wrap in using) session returned by Session.Demand(). Those sessions are considered managed by session manager and if you dispose such session bad things will happen.

On contrary if you ever call Session.Activate() you should dispose its result. Otherwise session would be attached to current thread forever and thus will became a memory leak.

answered Sep 19 '13 at 04:13

Denis%20Krjuchkov's gravatar image

Denis Krjuchkov
179325

Thanks Dennis, this lucid explanation cleared all my confusions and my sample MVC4 application is working nicely now.

(Sep 19 '13 at 16:00) TinkererJim TinkererJim's gravatar image

OK, found the problem. I'm using VS2012 and IISExpress(iis7) so the module in web.config is in a separate location:

 <system.webServer>
   <modules>
      <add name="SessionManager" type="Xtensive.Orm.Web.SessionManager, Xtensive.Orm.Web"/>
    </modules>
  </system.webServer>

Now the SessionManager.DomainBuilder does get hooked. And I had to add session.Activate() in order for the code to get further and not give me "Active Session required..." error(why is that?) as following:

public static Xtensive.Orm.Domain Build()
{
    DomainConfiguration config = new DomainConfiguration("sqlserver://sa:taki314@localhost/storev5") { UpgradeMode = DomainUpgradeMode.Recreate };
    config.Types.Register(typeof(Product).Assembly);
    domain = Xtensive.Orm.Domain.Build(config);
    using (var session=domain.OpenSession())
    {
        session.Activate();
        using (var transactionScope = session.OpenTransaction())
        {
            new Product() { ProductID = 99, Name = "Lenovo X1 Laptop", Price = 1595.00M, Category = "Computers", Description = "Thin, Lightweight, Long Battery Life" };
            new Product() { ProductID = 100, Name = "Lenovo T430 Tower Server", Price = 795.00M, Category = "Servers", Description = "Low Cost, Efficient Office Work Horse" };
            transactionScope.Complete();
        }
    }
    return domain;
}

answered Sep 18 '13 at 15:30

TinkererJim's gravatar image

TinkererJim
15113

Thanks for your reply. I'm just trying to get started with DO4 on MVC4 and hoping to find some sample code. Is the web extension meant to work with MVC4? I've added the extension, added <httpmodule> for ServiceManager and my global_start looks like this:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using SportsStore.WebUI.Infrastructure;
using SportsStore.Domain.Entities;
using SportsStore.WebUI.Binders;
using Xtensive.Orm;
using Xtensive.Orm.Web;
using Xtensive.Orm.Configuration;

namespace SportsStore.WebUI
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {

        protected void Application_Start()
        {
            //setup DataObjects.net
            SessionManager.DomainBuilder= DomainBuilder.Build;

            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
            ModelBinders.Binders.Add(typeof(Cart), new CartModelBinder());

        }

    }

    internal static class DomainBuilder {
        private static Xtensive.Orm.Domain domain;

        public static Xtensive.Orm.Domain Build()
        {
            DomainConfiguration config = new DomainConfiguration("sqlserver://sa:taki314@localhost/storev5") { UpgradeMode = DomainUpgradeMode.Recreate };
            config.Types.Register(typeof(Product).Assembly);
            domain = Xtensive.Orm.Domain.Build(config);
            using (domain.OpenSession())
            {
                new Product() { ProductID = 99, Name = "Lenovo X1 Laptop", Price = 1595.00M, Category = "Computers", Description = "Thin, Lightweight, Long Battery Life" };
                new Product() { ProductID = 99, Name = "Lenovo T430 Tower Server", Price = 795.00M, Category = "Servers", Description = "Low Cost, Efficient Office Work Horse" };
            }
            return domain;
        }

    }
}

But the DomainBuilder.Build doesn't seem to get triggered. And I get this error

Active Session is required for this operation. Use Session.Open(...) to open it.

When execution reaches first DO code:

    IQueryable<Product> prods;
    using (Xtensive.Orm.Session.Demand())
    {
       prods = repository.Products.Where(p => category == null || p.Category == category).OrderBy(p => p.ProductID).Skip((page - 1) * PageSize).Take(PageSize);
    }

answered Sep 18 '13 at 13:13

TinkererJim's gravatar image

TinkererJim
15113

Could you please try SessionManager.Current.Session instead of Xtensive.Orm.Session.Demand() just to check whether SessionManager.Current is present?

(Sep 18 '13 at 13:32) Dmitri Maximov Dmitri%20Maximov's gravatar image

The SessionManager.DomainBuilder is just not being hooked up as I see the table has not been generated. I'm trying a more direct approach here bypassing SessionManager. I can see the table being generated in database, but still gives me error:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using SportsStore.WebUI.Infrastructure;
using SportsStore.Domain.Entities;
using SportsStore.WebUI.Binders;
using Xtensive.Orm;
using Xtensive.Orm.Web;
using Xtensive.Orm.Configuration;

namespace SportsStore.WebUI
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {

        protected void Application_Start()
        {
            //setup DataObjects.net
            DomainBuilder.Build();

            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
            ModelBinders.Binders.Add(typeof(Cart), new CartModelBinder());

        }

    }

    internal static class DomainBuilder {
        private static Xtensive.Orm.Domain domain;

        public static Xtensive.Orm.Domain Build()
        {
            DomainConfiguration config = new DomainConfiguration("sqlserver://sa:taki314@localhost/storev5") { UpgradeMode = DomainUpgradeMode.Recreate };
            config.Types.Register(typeof(Product).Assembly);
            domain = Xtensive.Orm.Domain.Build(config);
            using (Session.Open(domain))
            {
                using (var transactionScope = Transaction.Open())
                {
                    new Product() { ProductID = 99, Name = "Lenovo X1 Laptop", Price = 1595.00M, Category = "Computers", Description = "Thin, Lightweight, Long Battery Life" };
                    new Product() { ProductID = 99, Name = "Lenovo T430 Tower Server", Price = 795.00M, Category = "Servers", Description = "Low Cost, Efficient Office Work Horse" };
                    transactionScope.Complete();
                }
            }
            return domain;
        }

    }
}

Active Session is required for this operation. Use Session.Open(...) to open it.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: Active Session is required for this operation. Use Session.Open(...) to open it.

Source Error:

Line 53: using (Session.Open(domain)) Line 54:
{ Line 55: using (var transactionScope = Transaction.Open()) Line 56: { Line 57:
new Product() { ProductID = 99, Name = "Lenovo X1 Laptop", Price = 1595.00M, Category = "Computers", Description = "Thin, Lightweight, Long Battery Life" };

Source File: c:\workspace\dev\MVC4\SportsStore\SportsStore.WebUI\Global.asax.cs Line: 55

Stack Trace:

[InvalidOperationException: Active Session is required for this operation. Use Session.Open(...) to open it.]
Xtensive.Orm.Session.Demand() +54
Xtensive.Orm.Transaction.Open() +7
SportsStore.WebUI.DomainBuilder.Build() in c:\workspace\dev\MVC4\SportsStore\SportsStore.WebUI\Global.asax.cs:55 SportsStore.WebUI.MvcApplication.Application_Start() in c:\workspace\dev\MVC4\SportsStore\SportsStore.WebUI\Global.asax.cs:28

answered Sep 18 '13 at 13:46

TinkererJim's gravatar image

TinkererJim
15113

I think I'm a bit closer now. I modified as following, and now the code reaches Product:Ctor(), but still asking for an Active Session:

public static Xtensive.Orm.Domain Build()
{
    DomainConfiguration config = new DomainConfiguration("sqlserver://sa:taki314@localhost/storev5") { UpgradeMode = DomainUpgradeMode.Recreate };
    config.Types.Register(typeof(Product).Assembly);
    domain = Xtensive.Orm.Domain.Build(config);
    using (var session=domain.OpenSession())
    {
        using (var transactionScope = session.OpenTransaction())
        {
            new Product() { ProductID = 99, Name = "Lenovo X1 Laptop", Price = 1595.00M, Category = "Computers", Description = "Thin, Lightweight, Long Battery Life" };
            new Product() { ProductID = 99, Name = "Lenovo T430 Tower Server", Price = 795.00M, Category = "Servers", Description = "Low Cost, Efficient Office Work Horse" };
            transactionScope.Complete();
        }
    }
    return domain;
}

error:

Line 55: using (var transactionScope = session.OpenTransaction()) Line 56:
{ Line 57: new Product() { ProductID = 99, Name = "Lenovo X1 Laptop", Price = 1595.00M, Category = "Computers", Description = "Thin, Lightweight, Long Battery Life" }; Line 58: new Product() { ProductID = 99, Name = "Lenovo T430 Tower Server", Price = 795.00M, Category = "Servers", Description = "Low Cost, Efficient Office Work Horse" }; Line 59:
transactionScope.Complete();

Source File: c:\workspace\dev\MVC4\SportsStore\SportsStore.WebUI\Global.asax.cs Line: 57

Stack Trace:

[InvalidOperationException: Active Session is required for this operation. Use Session.Open(...) to open it.]
Xtensive.Orm.Session.Demand() +54
Xtensive.Orm.Persistent..ctor() +31
Xtensive.Orm.Entity..ctor() +35
SportsStore.Domain.Entities.Product..ctor() in :0
SportsStore.WebUI.DomainBuilder.Build() in c:\workspace\dev\MVC4\SportsStore\SportsStore.WebUI\Global.asax.cs:57 SportsStore.WebUI.MvcApplication.Application_Start() in c:\workspace\dev\MVC4\SportsStore\SportsStore.WebUI\Global.asax.cs:28

answered Sep 18 '13 at 14:04

TinkererJim's gravatar image

TinkererJim
15113

Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

Subscription:

Once you sign in you will be able to subscribe for any updates here

Tags:

×3
×2
×1
×1
×1

Asked: Sep 18 '13 at 12:02

Seen: 2,645 times

Last updated: Sep 19 '13 at 16:00

powered by OSQA