Is newing an XFormPageUnknownActionHandler in our BasePageController a bad idea?

Vote:
 

I've been troubleshooting an apparent memory leak issue that we're having on several of our EpiServer websites, and was encouraged to look for large objects or defective code.  See http://world.episerver.com/forum/developer-forum/-Episerver-75-CMS/Thread-Container/2016/8/how-can-we-fix-high-memory-usage-on-episerver-8-sites-in-windows-server-2012-r2/

Investigating the code, I ran across a BasePageController that news up an instance of the XFormPageUnknownActionHandler.  This BasePageController gets inherited by several of our other controllers.

We're using the XFormPageUnknownActionHandler for recaptcha.  But that appears to be it's only use on our sites.

Is the XFormPageUnknownActionHandler a resource-heavy object?  And if so, rather than instantiating it on a page load, can't we just new one of those up on a post ActionResult?  And if not, then what's a better way to instantiate that object to limit the surface of it's impact?  Thank you!

#152031
Aug 12, 2016 18:29
Vote:
 

Are you sure that XFormPageUnknownActionHandler is the guilty guy here? Did you commented it out and reran the tests?

Another question - why you are creating new instances of this type? Just to validate incoming captcha?

#155272
Sep 13, 2016 11:57
Vote:
 

Thanks Valdis.  Yes, I commented out that code and re-ran the tests, and that had appeared to have no direct impact on fixing high memory usage we are seeing.  Also, yes I believe the only reason we are creating new instances of that type is to validate the recaptcha.  This is my first exposure to that handler, and documentation that I found didn't really clarify it for me. Hence the original question.

For background, we identified other code that caused a memory leak, both in views and in the compiled C#, which was written by other developers.  Last week I fixed some views where the code was creating new instances of the EpiServer.DataFactory.Instance in the Razor for multiple views.  At this point I've been focused on cleaning up the code, by employing using statements when possible and disposing objects when necessary.

Back to the XFormPageUnknownActionHandler, is there a better place to instantiate it for recaptcha than in the BasePageController?  Or is putting it there actually a good idea?  Thanks.

#155309
Sep 13, 2016 19:43
Vote:
 

I do see here few issues though..

a) you are "not allowed" to do anything other than rendering stuff from viewmodel to markup in razor views :)

b) you should not touch DataFactory directly (even worse - creating new instances manually)

c) if you need any stuff from DataFactory, you should instead go via some interface (like IContentLoader)

d) those interfaces should be access from underlying controller

e) underlying controller needs to get these interfaces "from above" (preferrably via constrctor of the controller - Constructor Injection pattern).

f) if you are explictly using any of disposable dependencies - either rely on nested container disposal procedure or dispose those manually

#155311
Sep 13, 2016 20:33
Vote:
 

Thanks for your insights Valdis.  Unfortunately the code doesn't align with your recommendations.  I'm coming in after the fact (the sites were built by other developers).  One of the patterns they employed was to push a lot of business logic into the views.  So that's an anti-pattern that I'll be targeting.  And we have multiple instances of sites, based on a common template, but nevertheless multiple sites.

To give you an idea of one of the fixes I applied, we had multiple views on a couple of dozen sites where there was code similar to this:

IContentLoader contentLoader = EPiServer.DataFactory.Instance;
var home = contentLoader.Get<HomePage>(ContentReference.StartPage);

I converted that code to this instead:

var home = DataFactory.Instance.Get<HomePage>(ContentReference.StartPage);

That made a dramatic improvement on the memory usage.  DataFactory already exists in those contexts, so there is no need to create a new instance.  But we're still seeing problems.  Since the scope of this is so large, I'm trying to initially target some of the more obvious memory offenders, like undisposed StreamReaders and StringBuilders.  When it comes to the EpiServer objects, like the DataFactory and the XFormPageUnknownActionHandler, those are new territory for me.

#155320
Sep 13, 2016 22:14
Vote:
 

Your provided code fragment above shouldn't affect memory usage as you are just assigning DataFactory instance to a variable and calling Get() method from that assigned variable. It's not creating a new instance of DataFactory. "Best way" I would say - would be to ask IContentLoader interface from a ServiceLocator (ServiceLocator.Current.GetInstance<IContentLoader>()). This will make sure that IContentLoader dependency is respecting it's lifetime specifications (usually it's singleton anyway).

Was this the only change and then you saw dramatic improvements in memory consumption?

#155323
Sep 14, 2016 6:49
Vote:
 

We also set the primary memory limit for each application pool to 500,000 KB.  Originally those limits were set to zero. We applied the changes incrementally; first adjusting the memory limits, then testing, then adjusting the code.  And we saw an improvement in each case.

Additionally, there were a few files that created the DataFactory like so, which I adjusted in similar fashion to the fix above.

IContentLoader contentLoader = new DataFactory();
var home = contentLoader.Get<HomePage>(ContentReference.StartPage);
#155351
Sep 14, 2016 14:27
Vote:
 

This was definitely wrong :)

#155353
Sep 14, 2016 15:20
Vote:
 

Actually pretty strange its even possible :) definitely wrong yes. If you use content events it's always good to double check that you also remove the events in the initialization module. I've seen a few sites that trigger those events multiple times...tricky error to find

#155357
Sep 14, 2016 16:23
Vote:
 

Btw, what were tools you used to "test" memory consumption?

#155359
Sep 14, 2016 17:03
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.