KB Article K18167
Visible to All Users

Troubleshooting - How to resolve the "Entering the 'GetObjectsNonReenterant' state..." error

Problem

I'm getting the following error:
Entering the 'GetObjectsNonReenterant' state from the 'GetObjectsNonReenterant' state is prohibited. The current state is 'GetObjectsNonReenterant'. Most probably, you are trying to initiate an object loading operation while the previous object loading operation isn't yet completed. Please postpone your operation until the Session.ObjectsLoaded or IXPObject.OnLoaded event is fired (while Session.IsObjectsLoading is true).
How can I diagnose this issue?

Solutions

As the exception message says, the problem is that a new loading operation is started while another operation is in progress. Here's the list of known possible mistakes that may lead to this situation.

1. You've injected additional business logic into the getter or setter of a persistent property (non-persistent is fine) without checking and this logic includes another persistent object access or modification to other properties. It is imperative to ensure that the object is not being saved or loaded before performing this logic by checking the IsLoading and IsSaving properties. For example:

C#
if (!IsSaving && !IsLoading){ DoSomeBusinessRule(); }
Visual Basic
If (Not IsSaving) AndAlso (Not IsLoading) Then DoSomeBusinessRule() End If

Note that there are corresponding properties in the Session object. You can check: IsObjectsLoading and IsObjectsSaving. Another reason for this state check is that property setters and getters are used not only when you modify the object, but also when an existing object is loaded from storage.

2. You should not manipulate data from different threads or do this as described at What's up with BeginInvoke?

3. If you calculate a property value based on detail collections or delayed reference properties within the OnSaving method or property getters when a persistent object is being saved or loaded, it may be required to pre-load the collection or reference properties on which this calculation depends. To do this, consider one of following solutions:

These solutions usually result in better performance in such scenarios since they avoid the N+1 Select Problem. This is, however, not 100% guaranteed and can even cause performance degradation in certain scenarios (e.g., when explicitly loaded collections or object graphs contain a lot of complex objects).

4. This exception can also be caused by a known .NET Framework specificity described in the Reentrancy, Avalon, Longhorn and the Client section of the Apartments and Pumping in the CLR blog. In short, an STA thread can process system messages ignoring the "lock" statement executed on it. This situation may happen when a data loading operation executed in the main thread takes too long and the .NET Framework decides to refresh the UI. You can detect this situation by locating the WMPaint method call in the exception call stack. To bypass this intermittent and quite rare issue, use the STASafeDataStore wrapper on top of the usual XPO connection provider:

C#
string connectionString = MSSqlConnectionProvider.GetConnectionString("localhost", "database"); IDataStore provider = new DevExpress.Xpo.Providers.STASafeDataStore(XpoDefault.GetConnectionProvider(connectionString, autoCreateOption));

This solution works in single-threaded apartment.

There is also a solution to this issue full of restrictions - use the multithreaded apartment (MTA) for the application (the default is STAThread), which you should normally avoid in your apps.

C#
static class Program { [MTAThread] static void Main() { ... } }

Beware that MTAThread lacks some important features like drag-and-drop, OLE, etc. and is generally NOT recommended in WinForms (MSDN). Similarly, we do not support it in our controls and are not responsible for any side effects in this mode, so use it at your own risk if no aforementioned solutions are possible.

To use the STASafeDataStore class in an XAF application, implement a custom IXpoDataStoreProvider and create it in the overridden XafApplication.CreateDefaultObjectSpaceProvider method. For more details, refer to the XPO-specific customizations > Implementing IXpoDataStoreProvider section in the How to customize the underlying database provider options and data access behavior in XAF article. This is an example of the CreateWorkingStore method for your reference. You can implement other methods similarly, but the STASafeDataStore wrapper is unnecessary there.

How to use the STASafeDataStore in an XAF app

To use the STASafeDataStore component in an XAF app, create the following ConnectionStringDataStoreProvider descendant:

C#
using System; using DevExpress.ExpressApp.Xpo; using DevExpress.Xpo.DB; using DevExpress.Xpo; using DevExpress.Xpo.Providers; namespace dxT1066749.Win { public class STASafeConnectionStringDataStoreProvider : ConnectionStringDataStoreProvider, IXpoDataStoreProvider { public STASafeConnectionStringDataStoreProvider(string connectionString) : base(connectionString) { } public new IDataStore CreateWorkingStore(out IDisposable[] disposableObjects) { IDataStore result = null; disposableObjects = null; result = XpoDefault.GetConnectionProvider(ConnectionString, AutoCreateOption.SchemaAlreadyExists, out disposableObjects); return new STASafeDataStore(result); } } }

Then, use this class's instance in the UseCustomDataStoreProvider (.NET 6) or CreateDefaultObjectSpaceProvider (.NET Framework) method:

C#
builder.ObjectSpaceProviders .AddSecuredXpo((application, options) => { options.ConnectionString = connectionString; options.UseCustomDataStoreProvider(new STASafeConnectionStringDataStoreProvider(connectionString)); })
C#
namespace dxT1066749.Win { public partial class dxT1066749WindowsFormsApplication : WinApplication { protected override void CreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgs args) { IObjectSpaceProvider provider = new XPObjectSpaceProvider(new STASafeConnectionStringDataStoreProvider(args.ConnectionString), false); args.ObjectSpaceProviders.Add(provider); args.ObjectSpaceProviders.Add(new NonPersistentObjectSpaceProvider(TypesInfo, null)); }

5. This error may also occur while debugging and setting break points in Visual Studio under some rare circumstances, as in the following ticket: Entering state 'GetObjectsNonReenterant' from state 'GetObjectsNonReenterant' is prohibited when using DataStoreService over WCF and debugging/inspecting variables in code editor. In this particular case, since both WCF server and client apps are being debugged at the same time, they are also stopped by Visual Studio when the execution hits a breakpoint. Since the WCF server is stopped, the query cannot be executed correctly. Visual Studio also kills the thread in which the SQL query is executed without waiting for the timeout. Due to the abnormal termination, the session stays in the 'loading' state unexpectedly. You can avoid the error in this case  by starting the WCF server without the debugger attached.

See Also:
XPO Best Practices
How to troubleshoot the "Reentrancy or cross thread operation detected" error

Show previous comments (8)
DM DM
David Maelfait 8 years ago

    Thanks Dennis,

    usefull solution.

    The problem is solved.

    I put my code here, maybe other people can use it.

    public XPServerCollectionSource GetRegistrationsContent(string errorString, int levelId, string TableName, DateTime From, DateTime Until, XPServerCollectionSource current)
            {
                XPServerCollectionSource result = current;
                try
                {
                    if (TableName == "Registrations" && (current == null || (current != null && !current.Session.IsObjectsLoading && !current.Session.IsObjectsSaving)))
                    {
                        CriteriaOperator criteria = CriteriaOperator.Parse("[Rac_LevelID] = ? AND [Rac_LogDateTime] >= ? AND [Rac_LogDateTime] <= ?", new object[] { levelId, From, Until });
                        if (current == null)
                        {
                            IDataStore dataStore = XpoDefault.GetConnectionProvider(ATRegistrationsConnectionString, AutoCreateOption.DatabaseAndSchema);
                            IDataStore provider = new STASafeDataStore(dataStore);
                            XpoDefault.DataLayer = new SimpleDataLayer(provider);
                            XPClassInfo classInfo = XpoDefault.Session.GetClassInfo(typeof(Registration));
                            result = new XPServerCollectionSource(XpoDefault.Session, classInfo, criteria);
                        }
                        else
                        {
                            current.FixedFilterCriteria = criteria;
                            current.Session.DropIdentityMap();
                            current.Reload();
                            result = current;
                        }
                    }
                }
                catch (Exception e)
                {
                    OnErrorEv(0, errorString, e);
                }
                return result;
            }

      All of your propositions is misunderstood.
      You should resolve in DevExpress and release the update in the new version.
      I got the same error and nothing helps.

      Anatol (DevExpress) 3 years ago

        Hello,

        Thank you for contacting us. This diagnostic message is intended to prevent further errors when XPO is used incorrectly - e.g., if an application starts loading objects when the previous loading operation is not finished. Such cases need to be resolved on an application level and cannot be fixed on our side. Please create a ticket in our Support Center and attach a sample project and exception details (Obtain an Exception's Call Stack). Our team will be happy to help.

        Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

        Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.