Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

EVERY request NEWs up a Controller? Really?

197 views
Skip to first unread message

Richard Maher

unread,
Jul 28, 2015, 4:06:05 AM7/28/15
to
http://i1.asp.net/media/4773381/lifecycle-of-an-aspnet-mvc-5-application.pdf?version_id=&cdn_id=2014-02-10-002

Why doesn't every thread just keep track of a it's single instance of
the controller?

So my naive "Let's initialize in the Controller Constructor and remove
repetitive work from the methods/actions" is completely counter productive?

Marcel Mueller

unread,
Jul 28, 2015, 5:25:35 PM7/28/15
to
On 28.07.15 10.05, Richard Maher wrote:
> Why doesn't every thread just keep track of a it's single instance of
> the controller?

Because not every request uses the same controller? Because subsequent
requests are not serviced by the same thread?


> So my naive "Let's initialize in the Controller Constructor and remove
> repetitive work from the methods/actions" is completely counter productive?

Exactly. You should not abuse a controller as Cache.
A data cache should be part of the model backend.
Really constant data can be cached in static members. But be sure that
they are immutable to avoid race conditions.


Marcel

Richard Maher

unread,
Jul 28, 2015, 6:19:30 PM7/28/15
to
On 7/29/2015 5:25 AM, Marcel Mueller wrote:
> On 28.07.15 10.05, Richard Maher wrote:
>> Why doesn't every thread just keep track of a it's single instance of
>> the controller?
>
> Because not every request uses the same controller?

So what? Those that do win, those that don't take the hit. Sooner or
later benefits start being reaped. So we've got idle_time set to 0 for
worker processes, min threads set to X, and that new prime-the-pump
start up initialization which should be able to say give every thread a
single controller instance of the, what 1/2 doz, controllers in the App.

Sounds desirable to me!

Because subsequent
> requests are not serviced by the same thread?

Again so what? Would it break your heart and memory budget if a thread's
controller instance was to go unused?

>
>
>> So my naive "Let's initialize in the Controller Constructor and remove
>> repetitive work from the methods/actions" is completely counter
>> productive?
>
> Exactly. You should not abuse a controller as Cache.
> A data cache should be part of the model backend.
> Really constant data can be cached in static members. But be sure that
> they are immutable to avoid race conditions.

Or override the the Constructor and implement IController (whatever it is)

Look it's becoming clear that my mvC variant of MVC is probably not best
:-( What are other people using where a server process can simply
initialize itself and take the overhead up front at process creation time?

Richard Maher

unread,
Jul 28, 2015, 7:05:29 PM7/28/15
to

Please provide a simple Controller factory that has a List of pre-primed
controllers front-ended by a thread-safe Singleton that will new-up
additional controller instances when the list is empty.

Cheers

Richard Maher

unread,
Jul 29, 2015, 5:40:45 PM7/29/15
to
C'mon. Someone please chirp up and suggest Application Cache so I can
once again explain to Arne that Web-GARDENS improve performance because
threads won't scale!

Marcel Mueller

unread,
Jul 29, 2015, 7:45:19 PM7/29/15
to
On 29.07.15 00.19, Richard Maher wrote:
>>> Why doesn't every thread just keep track of a it's single instance of
>>> the controller?
>>
>> Because not every request uses the same controller?
>
> So what? Those that do win, those that don't take the hit. Sooner or
> later benefits start being reaped.

At the expense of memory, of course. Furthermore one controller per
thread is insufficient, because the thread can service multiple requests
when the current one does asynchronous operations like web service
requests to another server. And even more complicated one these services
return another server thread may complete the request. Now TLS will no
longer fit the needs since the ownership of the controller is
transferred to another thread.

> So we've got idle_time set to 0 for
> worker processes, min threads set to X, and that new prime-the-pump
> start up initialization which should be able to say give every thread a
> single controller instance of the, what 1/2 doz, controllers in the App.
>
> Sounds desirable to me!

You never run a server with dozens or hundreds of applications, aren't you?

> Because subsequent
>> requests are not serviced by the same thread?
>
> Again so what? Would it break your heart and memory budget if a thread's
> controller instance was to go unused?

Nowadays doing CPU computations redundantly is often more desirable that
the required synchronization to avoid it.


>>> So my naive "Let's initialize in the Controller Constructor and remove
>>> repetitive work from the methods/actions" is completely counter
>>> productive?
>>
>> Exactly. You should not abuse a controller as Cache.
>> A data cache should be part of the model backend.
>> Really constant data can be cached in static members. But be sure that
>> they are immutable to avoid race conditions.
>
> Or override the the Constructor and implement IController (whatever it is)

You cannot override a constructor.

> Look it's becoming clear that my mvC variant of MVC is probably not best
> :-( What are other people using where a server process can simply
> initialize itself and take the overhead up front at process creation time?

We usually operate asynchronously in larger applications. At application
start several data objects that are likely to be used quite often are
prefetched by asynchronous tasks. These objects are accessed by a
context object similar to an entity framework context. The access
methods block at a conditional variable until the desired objects are in
a finalized (immutable) state. Since the state graph is forward only
this will not require any synchronization after finalization of the
objects due to the use of the double check idiom. Furthermore the
prefetched objects are compressed in memory by using deduplication,
preferably of strings. I.e. turning value equality into reference equality.

Other data that is less likely to be used is loaded on demand and cached
for a certain time. Besides that the algorithm is the same. Once
completed they become compressed and immutable. So they are shared by
all worker threads rather than only the current one. This allows to load
5 GB database content into less than 2GB of .NET memory.

Furthermore because of the deduplication the model keeps the entire data
history (all user changes) with only a moderate increase of memory,
since the history has likely a large overlap.

Of course, any objects for processing a single request are still
temporary. But they are lightweight.
Even the access context for the model is lightweight. It's only data
field is a time stamp that indicates the database revision. All changes
made with newer timestamps are not visible by this context (i.e this
request) to achieve a maximum data consistency at concurrent changes.


Marcel

mah...@googlemail.com

unread,
Jul 30, 2015, 4:01:36 AM7/30/15
to
Hi Marcel (and thanks for the responses)

> At the expense of memory, of course.

Again "So what?". You're newing up controller instances like there's no Tomorrow and now you're concerned about memory?

> Furthermore one controller per
> thread is insufficient, because the thread can service multiple requests
> when the current one does asynchronous operations like web service
> requests to another server. And even more complicated one these services
> return another server thread may complete the request. Now TLS will no
> longer fit the needs since the ownership of the controller is
> transferred to another thread.

Thanks for explaining!

I'm new to .NET C# IIS and didn't see this big jump from versions. (IIS 6 to 7?)

I now appreciate the dilemma. So I can cache my initialized data (STATIC data looks the best as thankfully it isn't shared across the Web Garden and a Singleton front-ending resource pools such as Oracle Commands seems doable) but why am I being forced to develop and manage my own Controller Pool?

We have Thread Pools, Application Pools, and Connection Pools, but some bright spark has decided we don't need a Controller Pool because some dogma says they shouldn't be stateful. Well they're bloody initialized! Could be why we now have IIS Auto Start Always Running and Pre-Loading; whaddaya wreakonn???

> You never run a server with dozens or hundreds of applications, aren't you?

Don't tell your Granny how to suck eggs mate. I've been coding since you were just a glint in your Father's eye. Ranging from phone-call processing in New Zealand and West Indies and Trade Matching for LCH in London. I grew up on Shared VMS servers when everyone was going for separate Linux VMs before MicroSoft decided Web Farms (almost Clusters) were back in vogue. I just wish we still has ASTs (in 4 modes) but that's another story.

> Nowadays doing CPU computations redundantly is often more desirable that
> the required synchronization to avoid it.

Sure that's why I like Web Gardens underneath Web Farms but don't forget there's I/O in initialization and not just CPU. But more importantly, when you have predictive text requests coming in potentially for every keystroke per user then you don't want to waste time initializing for what has already become a stale response.

> > Or override the the Constructor and implement IController (whatever it is)
>
> You cannot override a constructor.

Sorry, I was meaning override the Controller or more precisely the Controller Factory a la mode de: -
http://www.codeproject.com/Tips/732449/Understanding-and-Extending-Controller-Factory-i

No I can Auto Start a whole lot of Controllers MIN/MAX(503) and have a Static List to .ADD() them back on dispose() and .Remove() then on Create() but, again, why am I having to do this???

I am really only using the "C" from MVC and really ned a new paradigm/pattern as MVC is starting to give me the shits :-( Does .NET IIS offer something more appropriate for serving up JSON to Javascript?

What if I set Controller.DisableAsynchSupport = true? Can I now use Thread.ManagedThreadId as an index into my Controller HashTable?

What happened in the O'Reilly book on MVC4? If Asynchronous is SO GOOD why did you have to remove synchronous so people could no longer use it?

> We usually operate asynchronously in larger applications.

Who's we or should I start calling you Your Majesty?

Cheers

Marcel Mueller

unread,
Jul 30, 2015, 3:57:58 PM7/30/15
to
On 30.07.15 10.01, mah...@googlemail.com wrote:
> I'm new to .NET C# IIS and didn't see this big jump from versions. (IIS 6 to 7?)

The pipeline mode of IIS 7.5 (default) is different in many ways.


> I now appreciate the dilemma. So I can cache my initialized data (STATIC data looks the best as thankfully it isn't shared across the Web Garden and a Singleton front-ending resource pools such as Oracle Commands seems doable) but why am I being forced to develop and manage my own Controller Pool?

> We have Thread Pools, Application Pools, and Connection Pools, but some bright spark has decided we don't need a Controller Pool because some dogma says they shouldn't be stateful. Well they're bloody initialized! Could be why we now have IIS Auto Start Always Running and Pre-Loading; whaddaya wreakonn???

Controllers should be cheap to instantiate. Otherwise they are likely
not only controllers.


>> You never run a server with dozens or hundreds of applications, aren't you?
>
> Don't tell your Granny how to suck eggs mate. I've been coding since you were just a glint in your Father's eye. Ranging from phone-call processing in New Zealand and West Indies and Trade Matching for LCH in London. I grew up on Shared VMS servers when everyone was going for separate Linux VMs before MicroSoft decided Web Farms (almost Clusters) were back in vogue. I just wish we still has ASTs (in 4 modes) but that's another story.

This explains why you look that fussy at performance issues. Al the old
stagers do so because they learned it the hard way. ;-) The young guys
on the other hand don't even care to invoke a complex LINQ query inside
a nested loop.


>> Nowadays doing CPU computations redundantly is often more desirable that
>> the required synchronization to avoid it.
>
> Sure that's why I like Web Gardens underneath Web Farms but don't forget there's I/O in initialization and not just CPU.

In case of I/O you have to care. But then it is pretty sure not part of
the controller but part of the model.

> But more importantly, when you have predictive text requests coming in potentially for every keystroke per user then you don't want to waste time initializing for what has already become a stale response.

Again, your model should not be part of the controller.


> No I can Auto Start a whole lot of Controllers MIN/MAX(503) and have a Static List to .ADD() them back on dispose() and .Remove() then on Create() but, again, why am I having to do this???

I think this is not best practice to do so. Adjust your model classes to
provide the information the controller needs. Do any caching or pooling
in the model.

> I am really only using the "C" from MVC and really ned a new paradigm/pattern as MVC is starting to give me the shits :-( Does .NET IIS offer something more appropriate for serving up JSON to Javascript?

Controllers for JSON services should be very lightweight in general. In
contrast to user pages there is no complex navigation graph. But I am
not really familiar with services like that in conjunction with MVC.

> What if I set Controller.DisableAsynchSupport = true? Can I now use Thread.ManagedThreadId as an index into my Controller HashTable?

Sorry, no idea.
But be careful not to introduce cacheline hopping. Using a thread ID as
index to mutable storage might scale tremendously bad with many cores.

> What happened in the O'Reilly book on MVC4? If Asynchronous is SO GOOD why did you have to remove synchronous so people could no longer use it?

AFAIK unless you invoke a Method that explicitly allows reuse of the
current worker thread nothing strange happens. But the call tree can be
quite subtle. I.e. if some method you call invokes a WebClient then this
class might use the asynchronous features and the thread ID might
change. I don't know exactly how this happens. I only observed that the
tread ID is sometimes no longer constant during processing of a single
request. We used TLS to keep some data for the time of the request
(instead of Request.Items) and this broke at IIS 7.5.


>> We usually operate asynchronously in larger applications.
>
> Who's we or should I start calling you Your Majesty?

Our programming team.


Marcel

Richard Maher

unread,
Jul 30, 2015, 6:52:38 PM7/30/15
to
On 7/31/2015 3:57 AM, Marcel Mueller wrote:
>
> Lots of good stuff.

Really appreciate your time and information Marcel!

I guess I should look more at what the Model can do for me.

Cheers

Richard Maher

unread,
Jul 30, 2015, 7:01:06 PM7/30/15
to
On that note, can you (or anyone else here) please point to an example
where the Model can assist in initializing something like Log4Net?

I'm guessing Log4Net, while instantiating, uses the configuration info
to open its log-files, Sockets or whatever before it is ready for
appenders and formatters etc.

This is the sort of o/head I'd like to take away from every method on
the Controller so that it is done at Worker Process initialization time.

If not Log4Net then something that generates 100 random numbers and
stores them in a Static array. You get the idea?

If there is and example somewhere on the Web I'd really appreciate it!

Arne Vajhøj

unread,
Jul 30, 2015, 7:25:01 PM7/30/15
to
On 7/30/2015 7:00 PM, Richard Maher wrote:
> On 7/31/2015 6:52 AM, Richard Maher wrote:
>> On 7/31/2015 3:57 AM, Marcel Mueller wrote:
>>>
>>> Lots of good stuff.
>>
>> Really appreciate your time and information Marcel!
>>
>> I guess I should look more at what the Model can do for me.
>
> On that note, can you (or anyone else here) please point to an example
> where the Model can assist in initializing something like Log4Net?
>
> I'm guessing Log4Net, while instantiating, uses the configuration info
> to open its log-files, Sockets or whatever before it is ready for
> appenders and formatters etc.
>
> This is the sort of o/head I'd like to take away from every method on
> the Controller so that it is done at Worker Process initialization time.

????

log4net will have overhead initializing. But that should only happen
once. And that should either be at first usage or at explicit
configuration which for ASP.NET should probably be done
in application start event.

Most/all seems to be using the latter:

http://weblogs.asp.net/dotnetstories/using-log4net-in-an-asp-net-application

http://www.codeproject.com/Articles/823247/How-to-use-Apache-log-net-library-with-ASP-NET-MVC

> If not Log4Net then something that generates 100 random numbers and
> stores them in a Static array. You get the idea?

For normal PRNG generating 100 numbers should take extremely
little time (nano seconds!).

Cryptographic secure PRNG may be different though.

Back to model.

Your wizard should already generate model classes that you
can use as examples.

But model in itself does not provide the one/few time
expensive initialization and later re-usage problem that
you solve by using a pool.

But the usage of r the object pool do most likely belong in the model,
so your controller uses your model and your model uses the object
pool.

Arne



Arne Vajhøj

unread,
Jul 30, 2015, 7:54:58 PM7/30/15
to
That is easy.

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;

namespace E
{
public class PoolingControllerFactory : DefaultControllerFactory
{
private static Queue<IController> pool = new Queue<IController>();
public override IController CreateController(RequestContext
requestContext, string controllerName)
{
lock(pool)
{
if(pool.Count > 0) {
return pool.Dequeue();
}
}
Type controllerType = Type.GetType("E.Controllers." +
controllerName + "Controller");
IController controller =
(IController)Activator.CreateInstance(controllerType);
return controller;
}
public override void ReleaseController(IController controller)
{
lock(pool)
{
pool.Enqueue(controller);
}
}
}
public class TestApplication : HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.Ignore("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new {
controller = "Test",
action = "Index",
id = UrlParameter.Optional
});
}

protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);

ControllerBuilder.Current.SetControllerFactory(typeof(PoolingControllerFactory));

}
}
}

But it does not solve your problem.

The framework test for it so it gives:

[InvalidOperationException: A single instance of controller
'E.Controllers.TestController' cannot be used to handle multiple
requests. If a custom controller factory is in use, make sure that it
creates a new instance of the controller for each request.]

:-(

And a simple attempt to just wrap the same instance in a different
delegating object does not work either.

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;

using Castle.Core;
using Castle.DynamicProxy;

namespace E
{
public class PoolingControllerFactory : DefaultControllerFactory
{
private static Queue<IController> pool = new Queue<IController>();
private IController Wrap(IController controller)
{
ProxyGenerator gen = new ProxyGenerator();
return
(IController)gen.CreateInterfaceProxyWithTarget(typeof(IController),
controller, new IInterceptor[0]);
}
private IController UnWrap(IController controller)
{
return (IController)ProxyUtil.GetUnproxiedInstance(controller);
}
public override IController CreateController(RequestContext
requestContext, string controllerName)
{
lock(pool)
{
if(pool.Count > 0) {
return Wrap(pool.Dequeue());
}
}
Type controllerType = Type.GetType("E.Controllers." +
controllerName + "Controller");
IController controller =
(IController)Activator.CreateInstance(controllerType);
return Wrap(controller);
}
public override void ReleaseController(IController controller)
{
lock(pool)
{
pool.Enqueue(UnWrap(controller));
}
}
}
public class TestApplication : HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.Ignore("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new {
controller = "Test",
action = "Index",
id = UrlParameter.Optional
});
}

protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);

ControllerBuilder.Current.SetControllerFactory(typeof(PoolingControllerFactory));

}
}
}

Still gives:

[InvalidOperationException: A single instance of controller
'E.Controllers.TestController' cannot be used to handle multiple
requests. If a custom controller factory is in use, make sure that it
creates a new instance of the controller for each request.]

:-(

But then we have to startup a decompiler and we see that our
controller extend Controller that extend ControllerBase that has:

public abstract class ControllerBase : IController
{
private readonly SingleEntryGate _executeWasCalledGate = new
SingleEntryGate();
...
protected virtual void Execute(RequestContext requestContext)
{
if (requestContext == null)
throw new ArgumentNullException("requestContext");
this.VerifyExecuteCalledOnce();
this.Initialize(requestContext);
this.ExecuteCore();
}
...
internal void VerifyExecuteCalledOnce()
{
if (!this._executeWasCalledGate.TryEnter())
throw new
InvalidOperationException(string.Format((IFormatProvider)
CultureInfo.CurrentUICulture,
MvcResources.ControllerBase_CannotHandleMultipleRequests, new object[1]
{
(object) this.GetType()
}));
}
...
}

And now we know what to do:

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;

namespace E
{
public class PoolingControllerFactory : DefaultControllerFactory
{
private static Queue<IController> pool = new Queue<IController>();
public override IController CreateController(RequestContext
requestContext, string controllerName)
{
lock(pool)
{
if(pool.Count > 0) {
return pool.Dequeue();
}
}
Type controllerType = Type.GetType("E.Controllers." +
controllerName + "Controller");
IController controller =
(IController)Activator.CreateInstance(controllerType);
return controller;
}
public override void ReleaseController(IController controller)
{
lock(pool)
{
// very dirty hack
Type seg =
Type.GetType("System.Web.Mvc.Async.SingleEntryGate, System.Web.Mvc");
ConstructorInfo segctor =
seg.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic |
BindingFlags.Public, null, new Type[0], null);

typeof(ControllerBase).GetField("_executeWasCalledGate",
BindingFlags.Instance | BindingFlags.NonPublic |
BindingFlags.Public).SetValue(controller, segctor.Invoke(null));
//
pool.Enqueue(controller);
}
}
}
public class TestApplication : HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.Ignore("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new {
controller = "Test",
action = "Index",
id = UrlParameter.Optional
});
}

protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);

ControllerBuilder.Current.SetControllerFactory(typeof(PoolingControllerFactory));

}
}
}

Standard disclaimer:
* I have not tested the code beyond the most basic
* the pool can only grow not shrink
* all sorts of error handling is missing
* certain things are hardcoded

Specific disclaimer:
* the usage of reflection may cost more than the object
initialization that you try to avoid
* there are probably a good reason MS spend so much effort
preventing this so you may encounter serious problems
if you go this route

I will not recommend this.

Arne






Arne Vajhøj

unread,
Jul 30, 2015, 8:03:35 PM7/30/15
to
On 7/30/2015 4:01 AM, mah...@googlemail.com wrote:
> Sorry, I was meaning override the Controller or more precisely the
> Controller Factory a la mode de: -
> http://www.codeproject.com/Tips/732449/Understanding-and-Extending-Controller-Factory-i
>
> No I can Auto Start a whole lot of Controllers MIN/MAX(503) and have
> a Static List to .ADD() them back on dispose() and .Remove() then on
> Create()

Not quite as easy.

See my long email.

> I am really only using the "C" from MVC and really ned a new
> paradigm/pattern as MVC is starting to give me the shits :-( Does
> .NET IIS offer something more appropriate for serving up JSON to
> Javascript?

ASP.NET Web API exists for this purpose.

Alternatively a plain .ashx !

Arne

mah...@googlemail.com

unread,
Jul 30, 2015, 9:00:02 PM7/30/15
to
Wow Arne! I've said it before and I'll say it again "You're a bloody legend!". I don't care what everyone else says :-)

> [InvalidOperationException: A single instance of controller
> 'E.Controllers.TestController' cannot be used to handle multiple
> requests. If a custom controller factory is in use, make sure that it
> creates a new instance of the controller for each request.]
>
> :-(

Very VERY interesting! And ":-(" is right.

Do any of the following mean more to you than me and help at all?

http://stackoverflow.com/questions/13557973/single-instance-of-controller-cannot-be-used-to-handle-multiple-requests-autof

builder.RegisterType<AccountController>().InstancePerDependency();

http://stackoverflow.com/questions/24743215/structuremap-mvc-5-html-action-issue

x.For<{Your controller name}>().AlwaysUnique();


PS Thankyou for your time and patience over the years especially with JAVA.

mah...@googlemail.com

unread,
Jul 30, 2015, 9:10:32 PM7/30/15
to
On Friday, July 31, 2015 at 7:25:01 AM UTC+8, Arne Vajhøj wrote:
>
> ????
>
> log4net will have overhead initializing. But that should only happen
> once. And that should either be at first usage or at explicit
> configuration which for ASP.NET should probably be done
> in application start event.
>
> Most/all seems to be using the latter:
>
> http://weblogs.asp.net/dotnetstories/using-log4net-in-an-asp-net-application
>
> http://www.codeproject.com/Articles/823247/How-to-use-Apache-log-net-library-with-ASP-NET-MVC
>
> > If not Log4Net then something that generates 100 random numbers and
> > stores them in a Static array. You get the idea?
>
> For normal PRNG generating 100 numbers should take extremely
> little time (nano seconds!).
>
> Cryptographic secure PRNG may be different though.

Just examples off the top of my head Arne. Feel free to substitute your own worthy example. My reall World example involves a few trips to the database to initialize some Statics and instantiating stuff that is request re-usable.
>
> Back to model.
>
> Your wizard should already generate model classes that you
> can use as examples.
>
> But model in itself does not provide the one/few time
> expensive initialization and later re-usage problem that
> you solve by using a pool.

Ok cancel Model then.
>
> But the usage of r the object pool do most likely belong in the model,
> so your controller uses your model and your model uses the object
> pool.

I am a simple man who believes that, like every good book, a Worker Process has a Beginning, a Middle, and an End. Or, if you like, A Constructor, A group of Actions, and a Destructor. Why does Microsoft want to isolate the Actions from sensible prologue and epilogue processing???

My Actions need Controller-specific ambiance God damn it!

>
> Arne

mah...@googlemail.com

unread,
Jul 30, 2015, 9:12:02 PM7/30/15
to
On Friday, July 31, 2015 at 8:03:35 AM UTC+8, Arne Vajhøj wrote:
> On 7/30/2015 4:01 AM, mah...@googlemail.com wrote:
> > Sorry, I was meaning override the Controller or more precisely the
> > Controller Factory a la mode de: -
> > http://www.codeproject.com/Tips/732449/Understanding-and-Extending-Controller-Factory-i
> >
> > No I can Auto Start a whole lot of Controllers MIN/MAX(503) and have
> > a Static List to .ADD() them back on dispose() and .Remove() then on
> > Create()
>
> Not quite as easy.
>
> See my long email.

Thanks again.

>
> > I am really only using the "C" from MVC and really ned a new
> > paradigm/pattern as MVC is starting to give me the shits :-( Does
> > .NET IIS offer something more appropriate for serving up JSON to
> > Javascript?
>
> ASP.NET Web API exists for this purpose.

Yeah but aren't its Controllers subject to the same stupidity?

Arne Vajhøj

unread,
Jul 30, 2015, 10:07:47 PM7/30/15
to
I did find the first when researching.

As far as I can see then they do use some third party software so
they do not apply to out of the box ASP.NET MVC.

Arne


Arne Vajhøj

unread,
Jul 30, 2015, 10:14:10 PM7/30/15
to
MS is doing it like MVC is traditionally done.

The first widely used web MVC framework was Struts 1.

In Struts 1 you do not even write a controller class - everything
uses the standard Struts controller. Instead you write a class
per action.

Look at the MVC split:

M = Model = all data and business logic = 100% custom classes
V = View = presentation = .aspx files
C = Control = handling of user input = controller and action class/classes

I am rather sure that your stuff logical belongs in M.

Arne


mah...@googlemail.com

unread,
Jul 30, 2015, 10:16:38 PM7/30/15
to
Yeah there's also a lot of Unity and something called Castle Windsor and AutoFac. Sorry for the Red Herring.

Arne Vajhøj

unread,
Jul 30, 2015, 10:37:12 PM7/30/15
to
> Yeah there's also a lot of Unity and something called Castle Windsor and AutoFac. Sorry for the Red Herring.

I actually did use Castle as well when I tried to create a unique
wrapper object around the real controller before I found out
how ASP.NET MVC did the check.

Very powerful tool!

Arne


Arne Vajhøj

unread,
Jul 30, 2015, 10:37:12 PM7/30/15
to
By default yes.

But maybe it is easier to setup a controller factory to use a
pool - I have not tested.

Anyway also for Web API then you should use M for the pool
stuff.

But if you are not interested in returning HTML then Web API
is the better fit in general.

Arne

mah...@googlemail.com

unread,
Jul 31, 2015, 1:09:49 AM7/31/15
to
How 'bout (clutching at straws): -

https://msdn.microsoft.com/en-us/library/system.web.mvc.controllerbase.initialize(v=vs.118).aspx#M:System.Web.Mvc.ControllerBase.Initialize(System.Web.Routing.RequestContext)

override "intialize(requestContext)" method with a super.initialize(reuestContext) followed by a controllerWorkingStorage = myWorkingStorageFactory();

But when to put controllerWorkingStorage back into the "pool"?

mah...@googlemail.com

unread,
Jul 31, 2015, 1:41:15 AM7/31/15
to
Aargh! Does MVC 6 get rid of Initialize()?

http://stackoverflow.com/questions/27716923/how-do-you-initialize-application-state-at-startup-and-access-it-from-controller

*BUT* the good news looks to be dependency injection with Controller constructor injection. Have to read up on "Services"

Marcel Mueller

unread,
Jul 31, 2015, 12:24:56 PM7/31/15
to
On 31.07.15 01.00, Richard Maher wrote:
> On that note, can you (or anyone else here) please point to an example
> where the Model can assist in initializing something like Log4Net?

This is not up to the controller but up the the application start. Use
global.asax.cs, methode Application_Start for this purpose.

> I'm guessing Log4Net, while instantiating, uses the configuration info
> to open its log-files, Sockets or whatever before it is ready for
> appenders and formatters etc.

Usually only the config file. Everything else depends on the content of
that file.

> This is the sort of o/head I'd like to take away from every method on
> the Controller so that it is done at Worker Process initialization time.

Tho Log4Net initialization should not be repeated at all. This is
subject to be a race condition. What happens if another thread is just
logging while you change the Log4Net configuration concurrently? I am
not sure whether Log4Net is thread-safe in this way. Usually only the
logging functions are thread-safe.
I don't use Log4Net, but I just checked the docs. The use of the
Configurator classes like XmlConfigurator is /not/ thread safe and the
logging framework must not be used during configuration.

> If not Log4Net then something that generates 100 random numbers and
> stores them in a Static array. You get the idea?

Not really.


Marcel

Arne Vajhøj

unread,
Jul 31, 2015, 7:55:37 PM7/31/15
to
If you want to:
- have a pool of expensive objects
- add one of these objects to your controller when starting
- removing it and return it to the pool when done
then the controller factory should work fine.

Arne


Arne Vajhøj

unread,
Jul 31, 2015, 7:58:54 PM7/31/15
to
DI is perfect for the case described where a reference to the same
single object is injected into all controller instances. Because
in that case there is no need to release back to pool.

Arne



Richard Maher

unread,
Jul 31, 2015, 9:10:48 PM7/31/15
to
On 8/1/2015 7:58 AM, Arne Vajhøj wrote:
> On 7/31/2015 1:41 AM, mah...@googlemail.com wrote:
>> Aargh! Does MVC 6 get rid of Initialize()?
>>
>> http://stackoverflow.com/questions/27716923/how-do-you-initialize-application-state-at-startup-and-access-it-from-controller
>>
>>
>> *BUT* the good news looks to be dependency injection with Controller
>> constructor injection. Have to read up on "Services"
>
> DI is perfect for the case described where a reference to the same
> single object is injected into all controller instances.

I'll work with a screw-driver, hammer, or chisel.

> Because
> in that case there is no need to release back to pool.

I still have to put it back in the pool because i don't want to take the
overhead of re-initializing. If .NET won't let me re-use Controllers
(and given, thanks very much to you, we now know it's way down in the
ControllerBase class) I was opting for DI as a way to pass and preserve
pre-initialize and re-usable ActionVariables/Working-Storage.
>

Arne Vajhøj

unread,
Jul 31, 2015, 9:16:57 PM7/31/15
to
DI is fine for:
- injecting a resource when all containers need the same resource
- injecting a resource when all containers needs a newly created resource
- injecting a resource pool to acquire resources from and release back

Just not for acquiring resources and releasing back.

Arne


Richard Maher

unread,
Jul 31, 2015, 9:29:31 PM7/31/15
to
Your factory with the dodgy (defeat the one-check) hack that you
disowned as soon as giving birth?

Look, this guy seems to be trying to solve similar problems: -
http://www.codeproject.com/Articles/560798/ASP-NET-MVC-Controller-Dependency-Injection-for-Be


I'm more of a pragmatist than a purist so this looks good to me: -

public class HomeController : Controller
{
private readonly ILogger _logger;
public HomeController():this(new DefaultLogger())
{
}
public HomeController(ILogger logger)
{
_logger = logger;
}
}

and this is also very interesting: -

public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController
GetControllerInstance(System.Web.Routing.RequestContext requestContext,
Type controllerType)
{
ILogger logger = new DefaultLogger();
IController controller =
Activator.CreateInstance(controllerType, new[] { logger }) as Controller;
return controller;
}
}


(They seem to have a license at http://www.codeproject.com/info/cpol10.aspx)

But them he starts to talk about Entity Framework and elsewhere I see a
whole lot of additional CargoCult crap and MVC 6 replacings Global.asax
with Startup.cs and VS2015 combining with ASP.NET 5 ti really fuck
people's lives up more than Windows 8 and 10.

Anyway, for me in the short (now) term, I hope static constructors work
with Controllers so I can static my i/o there. (Only needs to be done
once for all instances) and I'll just new-up the Action-Specific storage
every time. I am using Oracle Statement Cache so at least the SQL will
only have to be compiled once.

Arne Vajhøj

unread,
Jul 31, 2015, 10:13:51 PM7/31/15
to
On 7/31/2015 9:29 PM, Richard Maher wrote:
> On 8/1/2015 7:55 AM, Arne Vajhøj wrote:
>> On 7/31/2015 1:09 AM, mah...@googlemail.com wrote:
>>> How 'bout (clutching at straws): -
>>>
>>> https://msdn.microsoft.com/en-us/library/
>
>>> system.web.mvc.controllerbase.initialize(v=vs.118).aspx
>
>>> #M:System.Web.Mvc.ControllerBase.
>
>>> Initialize(System.Web.Routing.RequestContext)
>>>
>>>
>>> override "intialize(requestContext)" method with a
>>> super.initialize(reuestContext) followed by a
>
>>> controllerWorkingStorage
>>> = myWorkingStorageFactory();
>>>
>>> But when to put controllerWorkingStorage back into the "pool"?
>>
>> If you want to:
>> - have a pool of expensive objects
>> - add one of these objects to your controller when starting
>> - removing it and return it to the pool when done
>> then the controller factory should work fine.

I am babbling.

I meant:

then DI should work fine.

> Your factory with the dodgy (defeat the one-check) hack that you
> disowned as soon as giving birth?

Controller factory is fine.

Using reflection to change a private readonly field is not fine.

> Anyway, for me in the short (now) term, I hope static constructors work
> with Controllers so I can static my i/o there. (Only needs to be done
> once for all instances) and I'll just new-up the Action-Specific storage
> every time. I am using Oracle Statement Cache so at least the SQL will
> only have to be compiled once.

It should work. That is core C# and CLR functionality. ASP.NET can not
really change that.

Arne

0 new messages