0

I'm using Spring.NET to create my Command objects (with attached Advice) and run these in an MVC web application.

However I observed that the object I get back from

IApplicationContext ctx = ContextRegistry.GetContext();
MyObject obj = (MyObject) ctx.GetObject ("MyObject");

was not a new object, as I expected, as it had "remembered" the values from a previous request.

Worse still, I'm now suspecting that this shared instance is across the APPLICATION, and due to the multi-threaded nature of web requests, when my command executes and writes to the database this could result in a mish-mash of details being written from across multiple requests.

Are my fears founded, and is there a switch to always get me back a fresh and clean new object instead of a shared object? I feel I should still be able to use Spring IOC in my web apps.

tereško
  • 58,060
  • 25
  • 98
  • 150
Duncan
  • 10,218
  • 14
  • 64
  • 96
  • I should also add here that my fears are indeed real, please do not do this in your code! In a high-concurrency application this will result in problems, use the advice given below. – Duncan Aug 24 '12 at 14:29

2 Answers2

3

Spring.NET web applications support an additional attribute within object definition elements that allows you to control the scope of an object:

<object id="myObject" type="MyType, MyAssembly" scope="application | session | request"/>

The request, session and application scopes are only available if you use a web-aware Spring IApplicationContext implementation, such as WebApplicationContext.

http://www.springframework.net/doc-latest/reference/html/web.html#web-objectscope

Kirill Muratov
  • 368
  • 2
  • 8
  • One thing I didn't mention - can I use this in conjunction with AOP? I'm using the following at the moment: UpdateCustomerCommand beforeAdvice – Duncan Aug 24 '12 at 14:36
0

Answering my own question, hopefully others will find this useful.

Using Spring.NET in a new MVC site, I noticed some peculiar behaviour. I was mainly using Spring for its AOP abilities, and to do this I make use of its IOC to create command objects. The flow is:

Controller -> ‘create’ Command object:

var ctx = ContextRegistry.GetContext(); var updateContactCommand = (IUpdateCustomerCommand) ctx["UpdateCustomerCommand"]; Controller -> set up command object with new values

Controller -> execute command object, runs Audit advice which creates an Audit row in the database with the command details

Great stuff. Or so I thought.

I have code that only set a particular field on a certain condition. But when running this, I was seeing that the database was always storing the last value that was input, across transactions, even when the condition wasn’t met. The command was remembering the value set in a previous transaction!

Of course it wasn’t remembering the value, it was simply that when Spring ‘creates’ an updateContactCommand, it was only retrieving one that was created earlier – a singleton.

This has a major impact on multi-threaded web applications! There is a possibility that separate requests, using the same command object, could result in some quite undesirable behaviour.

The default behaviour of Spring.NET is to create a singleton, and so one must add ‘singleton=”false”‘ to the end of the object declaration as below. However, because I was using AOP, my object types were declared as ProxyFactoryObjects, and singleton is not valid at this point.

The answer is still in config, and it is to use the following:

  <object id="UpdateCustomerCommand" type="DataLib.Commands.UpdateCustomerCommand, DataLib" singleton="false"/>
  <object type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">
    <property name="ObjectNames">
      <list>
        <value>UpdateCustomerCommand</value>
      </list>
    </property>
    <property name="InterceptorNames">
      <list>
        <value>beforeAdvice</value>
      </list>
    </property>
  </object>

Note the use of AutoProxy.ObjectNameAutoProxyCreator.

This indeed gives me a new instance each time, which presumably will also address the multi-threading issue – still to be tested!

Source: http://forum.springframework.net/showthread.php?7027-Lifecycle-of-objects-how-to-get-a-new-instance-for-each-call-of-GetObject()

Duncan
  • 10,218
  • 14
  • 64
  • 96
  • 2
    i have to say that if your UpdateCustomerCommand object is storing transaction-specific state maybe you should fix that first. Your solution will create a new object for each "GetObject" call and i case you wanted to re-use the same object -in the same transaction- that would be impossible. A request-scoped singleton would be preferrable imo. – Jaguar Aug 23 '12 at 13:24
  • Thanks, my commands are simple 'fire-and-forget' so getting a new instance is all I need for this, but I 100% agree, I should be using web-aware Spring as intended, so will update this in future. – Duncan Aug 24 '12 at 14:28