ASP.NET, Ninject and MVC: Performance Load problems - asp.net-mvc

problem description: This model works fine with one user at a time. As soon as I get multiple users at once, I get a serious of errors relating to not closing my SqlDataReader. When i turn off lazy loading like this:
persistenceModel.Conventions.OneToManyConvention = (prop => prop.SetAttribute("lazy", "false"));
It's fine, yet performance is slow. This uses MVC Beta 1
Any thoughts?
Below I have a snippet of my global ASAX as well as my SessionFactory inialization code.
*********** THIS IS IN MY GLOBAL.ASAX ********
public class MvcApplication : NinjectHttpApplication
{
public static IKernel Kernel { get; set; }
protected override void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//routes.IgnoreRoute("WebServices/*.asmx");
routes.MapRoute("CreateCategoryJson", "Admin/CreateCategoryJson/{categoryName}");
routes.MapRoute("User", "Admin/User/{username}", new { controller="Admin", action="user" });
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
protected void Session_Start(object sender, EventArgs e)
{
if (Session["rSkillsContext"] == null)
{
string logonName = this.User.Identity.Name.Replace("NUSOFTCORP\\", string.Empty);
rSkillsContext context = new rSkillsContext(logonName);
Session.Add("rSkillsContext", context);
}
}
protected override IKernel CreateKernel()
{
log4net.Config.XmlConfigurator.Configure();
Kernel = new StandardKernel(new RepositoryModule(), new AutoControllerModule(Assembly.GetExecutingAssembly()), new Log4netModule());
return Kernel;
}
}
***** This is my NHibernateHelper.cs ******
private ISessionFactory CreateSessionFactory()
{
var configuration = MsSqlConfiguration
.MsSql2005
.ConnectionString.FromConnectionStringWithKey("ConnectionString")
.ShowSql()
.Raw("current_session_context_class", "web")
.ConfigureProperties(new Configuration());
var persistenceModel = new PersistenceModel();
persistenceModel.Conventions.GetForeignKeyName = (prop => prop.Name + "ID");
persistenceModel.Conventions.GetForeignKeyNameOfParent = (prop => prop.Name + "ID");
// HACK: changed lazy loading
persistenceModel.Conventions.OneToManyConvention = (prop => prop.SetAttribute("lazy", "false"));
persistenceModel.addMappingsFromAssembly(Assembly.Load(Assembly.GetExecutingAssembly().FullName));
persistenceModel.Configure(configuration);
return configuration.BuildSessionFactory();
}

It looks like that you didn't dispose your Session correctly (I had the same error with Ninject and NHibernate a month ago). It should be started at the start of request and should be disposed at the end. Could you please provide pieces of code where you starting and disposing your nhibernate session?

Related

In ASP.NET MVC, the ProcessRequest in my own MyHttpHanler just cannot be fired

I am trying to add some Routing rule in Global.ascx im my ASP.NET MVC application. I extend the IRouteHanlder, MVCHandler and registe the rule just as follow.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//routes.MapRoute(
// "DefaultTT", // Route name
// "test", // URL with parameters
// new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
//);
RouteValueDictionary defaults = new RouteValueDictionary();
RouteValueDictionary constraints = new RouteValueDictionary();
RouteValueDictionary tokens = new RouteValueDictionary();
defaults.Add("controller", "home");
defaults.Add("action", "index");
defaults.Add("data", string.Empty);
constraints.Add("data", #"[a-zA-Z0-9\-]*");
tokens.Add("pageId", 0);
routes.Add(new Route("", defaults, constraints, tokens, new MyRouteHandler()));
}
public class MyRouteHandler : IRouteHandler
{
public System.Web.IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
{
return new MyMVCHanlder(requestContext);
}
}
public class MyMVCHanlder : MvcHandler
{
public MyMVCHanlder(RequestContext requestContext)
: base(requestContext)
{
}
protected override void ProcessRequest(HttpContext httpContext)
{
int i = 1;
int j = i + 1;
base.ProcessRequest(httpContext);
}
protected override void ProcessRequest(HttpContextBase httpContext)
{
int i = 1;
int j = i + 1;
base.ProcessRequest(httpContext);
}
}
But when I visit localhost:50112/ in my browser, the ProcessRequest method cannot be fired. I don't know why. Do you have any thought? Thank you.

ASP MVC 2 Ninject

I'm trying to learn a bit about MVC and have come across a problem when using Ninject. I want to bind repositories but keep getting the 'Object reference not set to an instance of an object' error.
I have created my NinjectControllerFactory:
public class NinjectControllerFactory : DefaultControllerFactory
{
// A Ninject "kernel" is the thing that can supply object instances
private IKernel kernel = new StandardKernel(new SportsShopServices());
// ASP .NET MVC calls this to get the controller for each request
protected override IController GetControllerInstance(RequestContext context, Type controllerType)
{
if (controllerType == null)
return null;
return (IController) kernel.Get(controllerType);
}
// Configure how abstract sevice types are mapped to concrete implementations
private class SportsShopServices : NinjectModule
{
public override void Load()
{
Bind<IProductRepository>().To<SqlProductsRepository>()
.WithConstructorArgument("connectionString",
ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString);
}
}
}
and my controller :
public class ProductsController : Controller
{
private IProductRepository productsRepository;
// Constructor used with Ninject
public ProductsController(IProductRepository _productsRepository)
{
this.productsRepository = _productsRepository;
}
public ViewResult List()
{
return View(productsRepository.Products.ToList());
}
}
I have modified the Web.config file to provide the db connection string and the Global.asax file Application_Start() method to include:
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
I am working on an example from the PRO ASP .NET MVC 2 book but just can't get this work, been trying all day.
If you just want out-out-the-box ninject functionality, you are doing too much by creating your own controller factory.
all you need is the following in global.asax
public class MvcApplication : NinjectHttpApplication
{
protected override IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new ServiceModule()
};
return new StandardKernel(modules);
}
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
RegisterAllControllersIn(Assembly.GetExecutingAssembly());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
internal class ServiceModule : NinjectModule
{
public override void Load()
{
// controllers
this.Bind<Controllers.AccountController>().ToSelf();
this.Bind<Controllers.HomeController>().ToSelf();
// Repository
Bind<Controllers.IFormsAuthentication>().To<Controllers.FormsAuthenticationService>();
Bind<Controllers.IMembershipService>().To<Controllers.AccountMembershipService>();
}
}
}

how to use AsyncController in MVC application using Ninject for DI?

Does anyone know how to use an AsyncController in a mvc application that uses Ninject for DI?
AsyncController works fine when i dont use ninject but i cant make them work together.
I added following in my sitemodule but no go.
Bind<IAsyncController>( ).To<AsyncController>( ).InSingletonScope( );
sorry for not explaining this in details.
my controller looks like this
[HandleError]
public class HomeController : AsyncController
{
public void IndexAsync( )
{
AsyncManager.OutstandingOperations.Increment( );
RssFeed feed = new RssFeed( );
feed.GetRssFeedAsyncCompleted += ( s, e ) =>
{
AsyncManager.Parameters[ "items" ] = e.Items;
AsyncManager.OutstandingOperations.Decrement( );
};
feed.GetRssFeedAsync( "http://feeds.abcnews.com/abcnews/topstories" );
}
public ActionResult IndexCompleted( IEnumerable<SyndicationItem> items )
{
ViewData[ "SyndicationItems" ] = items;
return View( );
}
}
and my global.asax looks like this
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
protected void Application_Start( )
{
AreaRegistration.RegisterAllAreas( );
RegisterRoutes( RouteTable.Routes );
}
}
this works fine. but as soon as i use ninject (ninject 2.0 ) i get 404 page not found error when i try to access the index page. this is how i am configuring ninject
public class MvcApplication : NinjectHttpApplication //System.Web.HttpApplication
{
#region IOC
static IKernel container;
public static IKernel Container
{
get
{
if ( container == null ) { container = new StandardKernel( new SiteModule( ) ); }
return container;
}
}
protected override IKernel CreateKernel( )
{
return Container;
}
#endregion
public static void RegisterRoutes( RouteCollection routes )
{
routes.IgnoreRoute( "{resource}.axd/{*pathInfo}" );
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
//protected void Application_Start()
//{
// AreaRegistration.RegisterAllAreas();
// RegisterRoutes(RouteTable.Routes);
//}
protected override void OnApplicationStarted( )
{
AreaRegistration.RegisterAllAreas( );
RegisterRoutes( RouteTable.Routes );
}
}
public class SiteModule : NinjectModule
{
public override void Load( )
{
}
}
Do i need to bind anything on my sitemodule?
BTW i am using Jeff Prosise's example which he posted in his blog Here
you can download his demo application and try Ninject-ify it :)
Any help appreciated.
It appears it's not working because the standard NinjectControllerFactory inserts a NinjectActionInvoker into the controller's ActionInvoker property. The NinjectActionInvoker is derived from ControllerActionInvoker. An AsyncController, however, uses ActionInvokers derived from AsyncControllerActionInvoker. for some reason, this causes the controller to not match the route, and it returns a 404.
The real fix would be a patch to Ninject to support construction of AsyncController with AsyncControllerActionInvokers.
However, in the meantime, here is a workaround:
in your Global.asax, add this override:
protected override Ninject.Web.Mvc.NinjectControllerFactory CreateControllerFactory()
{
return new MyNinjectControllerFactory( kernel );
}
and then add this class for MyNinjectControllerFactory:
public class MyNinjectControllerFactory : Ninject.Web.Mvc.NinjectControllerFactory
{
public MyNinjectControllerFactory( IKernel kernel ) : base( kernel ) { }
protected override IController GetControllerInstance( RequestContext requestContext, Type controllerType )
{
if ( controllerType == null )
{
// let the base handle 404 errors with proper culture information
return base.GetControllerInstance( requestContext, controllerType );
}
var controller = Kernel.TryGet( controllerType ) as IController;
if ( controller == null )
return base.GetControllerInstance( requestContext, controllerType );
//var standardController = controller as Controller;
//if ( standardController != null )
// standardController.ActionInvoker = CreateActionInvoker();
return controller;
}
}
this is a copy of the NinjectControllerFactory that leaves out the assignment of the ActionInvoker.
IF you have code that depends on dependencies being injected into your ActionFilters, you will need to create your own ActionInvoker that returns an AsyncControllerActionInvoker that uses Ninject. Look at the Ninject.Web.Mvc source for the NinjectActionInvoker.
Like dave pointed out a patch is needed for Ninject to support async controller and Remo says he'll work on it as soon as he has sometime. meantime you can use dave's workaround or try this. this is straight from horse's mouth. i posted a msg in ninject group and Remo responded with this .
AsyncControllers are currently not
supported. I'll add this as soon as I
have the time to implement it
properly. In the mean time you can use
apply the following changes to the
sources to add the support:
Make a copy of NinjectActionInvoker name it NinjectAsyncActionInvoker and
change base type to
AsyncControllerActionInvoker
Apply the following changes to NinjectControllerFactory diff --git
"a/C:\Users\REMOGL~1\AppData\Local\Temp\
\NinjectControllerFactory_HEAD.cs"
"b/C:\Projects\Ninject\
\ninject.web.mvc\mvc2\src\Ninject.Web.Mvc\
\NinjectControllerFactory.cs" index
2c225a1..3916e4c 100644
--- "a/C:\Users\REMOGL~1\AppData\Local\Temp\
\NinjectControllerFactory_HEAD.cs"
+++ "b/C:\Projects\Ninject\ninject.web.mvc\mvc2\src\
\Ninject.Web.Mvc\NinjectControllerFactory.cs"
## -53,10 +53,18 ## namespace
Ninject.Web.Mvc
if (controller == null)
return base.GetControllerInstance(requestContext,
controllerType);
var standardController = controller as
Controller;
var asyncController = controller as AsyncController;
if (asyncController != null)
{
asyncController.ActionInvoker =
CreateAsyncActionInvoker();
}
else
{
var standardController = controller as
Controller;
if (standardController != null)
standardController.ActionInvoker =
CreateActionInvoker();
}
if (standardController != null)
standardController.ActionInvoker =
CreateActionInvoker();
return controller;
} ## -69,5 +77,14 ## namespace Ninject.Web.Mvc
{
return new NinjectActionInvoker(Kernel);
}
}
///
/// Creates the action invoker.
///
/// The action invoker.
protected virtual NinjectAsyncActionInvoker
CreateAsyncActionInvoker()
{
return new NinjectAsyncActionInvoker(Kernel);
}
} } \ No newline at end of file
Remo

MvcContrib Test Helper problem

I am using MVC2 with MvcContrib HelpTester.
I have problem with testing Controllers which are in Areas.
Here is my Test class :
[TestFixture]
public class RouteTests
{
[TestFixtureSetUp]
public void Setup()
{
RouteTable.Routes.Clear();
MvcApplication.RegisterRoutes(RouteTable.Routes);
}
[Test]
public void RootMatchesHome()
{
"~/".ShouldMapTo<TradersSite.Controllers.HomeController>(x => x.Index());
}
[Test]
public void AdminProductShouldMapToIndex()
{
"~/Admin/Produit/".ShouldMapTo<TradersSite.Areas.Admin.Controllers.ProductController>(x => x.Index());
}
Here's the action Index from my ProductController in the Admin Area :
public ActionResult Index(int? page)
{
int pageSize = 10;
int startIndex = page.GetValueOrDefault() * pageSize;
var products = _productRepository.GetAllProducts()
.Skip(startIndex)
.Take(pageSize);
return View("Index", products);
}
Here is the route map in my AdminAreaRefistration :
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
Finally here is the message I get back from MbUnit :
[fixture-setup] success
[failure] RouteTests.AdminProductShouldMapToIndex
TestCase 'RouteTests.AdminProductShouldMapToIndex' failed: Expected Product but was Admin
MvcContrib.TestHelper.AssertionException
Message: Expected Product but was Admin
Source: MvcContrib.TestHelper
StackTrace:
RouteTests.cs(44,0): at CBL.Traders.ControllerTests.RouteTests.AdminProductShouldMapToIndex()
Your area routes aren't being registered in the setup. Since you're just calling RegisterRoutes, which (by default) doesn't register areas, it's getting missed.
You can either figure a way to call AreaRegistration.RegisterAllAreas() directly (which typically gets called on app start, or you need to manually register each area you want to test. In your case, the following would work:
public void Setup()
{
RouteTable.Routes.Clear();
var adminArea = new AdminAreaRegistration();
var context = new AreaRegistrationContext("Default", RouteTable.Routes);
adminArea.RegisterArea(context);
MvcApplication.RegisterRoutes(RouteTable.Routes);
}

Is Ninject MVC supposed to work with MVC 2 Preview?

I am running a MVC 2 Preview and this is my first time trying to use Ninject2 MVC
There error that I am continently getting is:
An error occurred when trying to create a controller of type 'MyMVC.Controllers.EventsController'. Make sure that the controller has a parameterless public constructor.
What I have in my Global.cs is this:
public class MvcApplication : NinjectHttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("elmah.axd");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
routes.MapRoute(
"Root",
"",
new { controller = "Home", action = "Index", id = "" }
);
}
protected override void OnApplicationStarted()
{
RegisterRoutes(RouteTable.Routes);
RegisterAllControllersIn(Assembly.GetExecutingAssembly());
}
protected override IKernel CreateKernel()
{
return new StandardKernel(new ServiceModule());
}
}
internal class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IEventService>().To<EventService>();
Bind<IEventRepository>().To<EventRepository>();
}
}
And this is what my Controller looks like.
public class EventsController : Controller
{
private IEventService _eventService;
//
// GET: /Events/
public EventsController(IEventService eventService)
{
_eventService = eventService;
}
public ActionResult Index(string name)
{
return View(_eventService.GetEvent(name));
}
public ActionResult UpcomingEvents()
{
return View(_eventService.GetUpcomingEvents().Take(3).ToList());
}
}
I've not used Ninject, but I would assume you need to implement your own IControllerFactory. Until they update it to MVC 2. Then utilize that instead of RegisterAllControllersIn(..):
ControllerBuilder.Current.SetControllerFactory(new MyNinjectControllerFactory());
EDIT: Again, i'm not all that familiar with Ninject but this might work as a simple factory:
public class MyNinjectControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(Type controllerType)
{
return [Container].GetInstance(controllerType) as Controller;
}
}
At the risk of stating the obvious, you should try adding a parameterless constructor to your Events Controller.
public class EventsController : Controller
{
private IEventService _eventService;
//
// Parameterless constructor, so NInject will work
public EventsController() {}
//
// Regular constructor
public EventsController(IEventService eventService)
{
_eventService = eventService;
}

Resources