Ticket Q305734
Visible to All Users
Duplicate

We have closed this ticket because another page addresses its subject:

How to customize the Object Space behavior in XPO-based XAF applications

How to use a custom ObjectSpace throughout the application by handling the CreateCustomObjectSpaceProvider event?

created 14 years ago

Hi Folks,
I've implemented an Object-oriented trigger infrastructure that can be plugged into Xpo to offer functionality analogous (and even superior to) database triggers. It is based on handling Session events and uses a singleton class, the TriggerService, to which all sessions should be registered so that trigger functionality is enabled for that session. I've then created a UnitoOfWork descendant, called TriggerAwareUnitOfWork which basically register itself within the TriggerService (and unregister itself when disposed).
Since I'm working in a Xaf application, I need to integrate this OO Trigger functionality into Xaf. The straightforward way of doing that is simply to "force" all Session (actually UnitOfWork) objects created by all ObjectSpace objects to be of the TriggerAwareUnitOfWork type. I know how to create an ObjectSpace descendant that will always create the session of the TriggerAwareUnitOfWork type. I also know that I need to create an ObjectSpaceProvider that will be responsible for creating my custom ObjectSpace (TriggerAwareObjectSpace sounds like a good name). What I don't know is how (where) to handle the XafApplication.CreateCustomObjectSpaceProvider event!!!
Could you provide sample code to show me where/when/how to write this event handler for the XafApplication… Should I put it in the Update.cs, in the Module.cs, will I need to create a controller and wire the event handler there?
This is a very, very urgent matter for us, that's why I'm checking the priority on this issue.
Thanks in advance.

Show previous comments (3)

    Hi Michael,
    It may really be impossible to introduce a custom ObjectSpace / ObjectSpaceProvider at the platform agnostic module, so I've moved my implementation attempts to the platform specific module. I was trying to make a proof of concept for the Windows target, following the example you've pointed out here: http://devexpress.com/Support/Center/p/E411.aspx
    I have one pending issue with the following implementation: (my comments will follow the code bellow)
    /*** CODE STARTS HERE ****/
    using System;
    using DevExpress.ExpressApp.Win;
    using DevExpress.ExpressApp;
    using DevExpress.Xpo;
    using DevExpress.ExpressApp.DC;
    namespace PTS.Admin.Win
    {
        public partial class AdminWindowsFormsApplication : WinApplication
        {
            public AdminWindowsFormsApplication()
            {
                InitializeComponent();
            }
            private void AdminWindowsFormsApplication_DatabaseVersionMismatch(object sender, DevExpress.ExpressApp.DatabaseVersionMismatchEventArgs e)
            {
    #if EASYTEST
                   e.Updater.Update();
                   e.Handled = true;
    #else
                if (System.Diagnostics.Debugger.IsAttached)
                {
                    e.Updater.Update();
                    e.Handled = true;
                }
                else
                {
                    throw new InvalidOperationException(
                        "The application cannot connect to the specified database, because the latter doesn't exist or its version is older than that of the application.\r\n" +
                        "This error occurred because the automatic database update was disabled when the application was started without debugging.\r\n" +
                        "To avoid this error, you should either start the application under Visual Studio in debug mode, or modify the " +
                        "source code of the 'DatabaseVersionMismatch' event handler to enable automatic database update, " +
                        "or manually create a database using the 'DBUpdater' tool.\r\n" +
                        "Anyway, refer to the 'Update Application and Database Versions' help topic at http://www.devexpress.com/Help/?document=ExpressApp/CustomDocument2795.htm " +
                        "for more detailed information. If this doesn't help, please contact our Support Team at http://www.devexpress.com/Support/Center/");
                }
    #endif
            }
            protected override IObjectSpaceProvider CreateDefaultObjectSpaceProvider(IXpoDataStoreProvider dataStoreProvider)
            {
                return new TriggerAwareObjectSpaceProvider(dataStoreProvider);
            }
        }
        public class TriggerAwareObjectSpaceProvider : ObjectSpaceProvider
        {
            public TriggerAwareObjectSpaceProvider(IXpoDataStoreProvider dataStoreProvider) : base(dataStoreProvider) { }
            protected override IObjectSpace CreateObjectSpaceCore(UnitOfWork unitOfWork, ITypesInfo typesInfo)
            {
                ObjectSpace objectSpace = new TriggerAwareObjectSpace(new TriggerAwareUnitOfWork(unitOfWork.ObjectLayer), typesInfo);
                /*
                 * objectSpace.AsyncServerModeSourceResolveSession = AsyncServerModeSourceResolveSession;
                 * objectSpace.AsyncServerModeSourceDismissSession = AsyncServerModeSourceDismissSession;
                 */
                return objectSpace;
            }
        }
        public class TriggerAwareUnitOfWork : UnitOfWork
        {
            public TriggerAwareUnitOfWork() { }
            public TriggerAwareUnitOfWork(DevExpress.Xpo.Metadata.XPDictionary dictionary) : base(dictionary) { }
            public TriggerAwareUnitOfWork(IDataLayer layer, params IDisposable[] disposeOnDisconnect) : base(layer, disposeOnDisconnect) { }
            public TriggerAwareUnitOfWork(IObjectLayer layer, params IDisposable[] disposeOnDisconnect) : base(layer, disposeOnDisconnect) { }
        }
        public class TriggerAwareObjectSpace : ObjectSpace
        {
            public TriggerAwareObjectSpace(DevExpress.Xpo.UnitOfWork unitOfWork, DevExpress.ExpressApp.DC.ITypesInfo typesInfo) : base(unitOfWork, typesInfo) { }
            public TriggerAwareObjectSpace(DevExpress.Xpo.UnitOfWork unitOfWork) : base(unitOfWork) { }
            protected override UnitOfWork CreateUnitOfWork(IDataLayer dataLayer)
            {
                return new TriggerAwareUnitOfWork(dataLayer);
            }
        }
    }
    /*** CODE ENDS HERE ****/
    The problem I'm facing is with the implementation of the TriggerAwareObjectSpaceProvider. It lies in the implementation of the following method:
        protected override IObjectSpace CreateObjectSpaceCore(UnitOfWork unitOfWork, ITypesInfo typesInfo)
        {
            ObjectSpace objectSpace = new TriggerAwareObjectSpace(new TriggerAwareUnitOfWork(unitOfWork.ObjectLayer), typesInfo);
            /*
             * objectSpace.AsyncServerModeSourceResolveSession = AsyncServerModeSourceResolveSession;
             * objectSpace.AsyncServerModeSourceDismissSession = AsyncServerModeSourceDismissSession;
             */
            return objectSpace;
        }
    As you can see, the AsyncServerModeSourceResolveSession and AsyncServerModeSourceDismissSession assignments are commented out. This is because they are marked as "protected internal"!!! So, while they were meant to be used for inheritors, DevExpress have chosen to mark them for internal, effectively making it possible for us to extend the class is we need them. I don't know exactly why I would need them, but since the original CreateObjectSpaceCore makes this same assignment, I thought it was sensible that my own implementation did the same. The problem is that I just can't do that due to the "internal" access level.
    How can I guarantee that my own TriggerAwareObjectSpaceProvider creates my own TriggerAwareObjectSpace that will behave in every single aspect exactly like the default ObjectSpaceProvider and ObjectSpace, except for the fact that they will create a Session of type TriggerAwareUnitOfWork instead of UnitOfWork?
    Is there a way around the above "internal" access level? Is this really a problem? Can I live without that? :-)

    DevExpress Support Team 14 years ago

      Hi Felipe,
      These fields are only used in asynchronous server mode, which is not yet officially supported in XAF. So, there is no problem to omit these field assignments, unless you are planning to use this undocumented mode. We will change access modifiers or, probably, rewrite our core when the asynchronous mode is supported.
      Thanks,
      Michael.

        Hi Michael,
        Then I guess this is it! Thanks for the amazing support, once again.

        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.