diff --git a/Control/AthToolSupport/AsgServices/AsgServices/AsgService.h b/Control/AthToolSupport/AsgServices/AsgServices/AsgService.h
new file mode 100644
index 0000000000000000000000000000000000000000..dd038551ad86898dfc00468a745b9432f0a29f2e
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/AsgServices/AsgService.h
@@ -0,0 +1,60 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+/// @author Nils Krumnack
+/// @author David Adams <dladams@bnl.gov> (for original implementation for tools)
+
+#ifndef ASGSERVICES_ASGSERVICE_H
+#define ASGSERVICES_ASGSERVICE_H
+
+#include "AsgServices/IAsgService.h"
+
+#ifdef XAOD_STANDALONE
+#include "AsgMessaging/AsgMessaging.h"
+#include "AsgTools/AsgComponent.h"
+#else
+#include "AthenaBaseComps/AthService.h"
+#endif
+
+
+class ISvcLocator;
+
+namespace asg
+{
+  // Declare the type name of AsgService's base class
+#ifndef XAOD_STANDALONE
+  typedef ::AthService AsgServiceBase;
+#else
+  typedef AsgComponent AsgServiceBase;
+#endif
+
+  /// Base class for the dual-use service implementation classes
+  ///
+  /// This class can be used like AthService can be used for
+  /// Athena-only services.
+  ///
+  /// Loosely based on the \ref AsgTool implementation.
+
+  class AsgService : public virtual IAsgService,
+                     public AsgServiceBase
+  {
+  public:
+    AsgService (const std::string& name,
+                ISvcLocator* pSvcLocator);
+
+
+    /// set up/tear down functions
+    /// \{
+    virtual StatusCode initialize ();
+    virtual StatusCode finalize ();
+    /// \}
+
+    /// Print the state of the service
+    virtual void print() const;
+
+  }; // class AsgService
+
+} // namespace asg
+
+#endif // ASGSERVICES_ASGSERVICE_H
diff --git a/Control/AthToolSupport/AsgServices/AsgServices/AsgServiceConfig.h b/Control/AthToolSupport/AsgServices/AsgServices/AsgServiceConfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..1a1ac37804604a5048d97d178dc70757be7e0ada
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/AsgServices/AsgServiceConfig.h
@@ -0,0 +1,166 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+/// @author Nils Krumnack
+
+
+
+#ifndef ASG_SERVICES_ASG_SERVICE_CONFIG_H
+#define ASG_SERVICES_ASG_SERVICE_CONFIG_H
+
+#include <AsgTools/AsgComponentConfig.h>
+#include <AsgServices/AsgService.h>
+#include <AsgServices/ServiceHandle.h>
+
+#ifndef XAOD_STANDALONE
+#include <GaudiKernel/Service.h>
+#endif
+
+namespace asg
+{
+  /// \brief an object that can create a \ref AsgService
+
+  class AsgServiceConfig : public asg::AsgComponentConfig
+  {
+    //
+    // public interface
+    //
+
+    /// \brief standard constructor
+    /// \par Guarantee
+    ///   strong
+    /// \par Failures
+    ///   out of memory I
+  public:
+    AsgServiceConfig () = default;
+
+
+    /// \brief initializing constructor
+    /// \par Guarantee
+    ///   strong
+    /// \par Failures
+    ///   out of memory II
+  public:
+    explicit AsgServiceConfig (const std::string& val_typeAndName);
+
+
+    /// \brief make a service with the given configuration
+    ///
+    /// \warn This is mostly meant as a low level interface to be used
+    /// in unit tests and internally by framework functions that
+    /// manage services.  As a user you should mostly rely on the
+    /// python configuration or on passing the AsgServiceConfig object
+    /// to your framework, which will then create and manage the
+    /// service for you.
+    ///
+    /// \warn Regardless of which function you use, the memory
+    /// management and cleanup of services differs between stand-alone
+    /// use and Athena.  In EventLoop you receive an owning
+    /// pointer/handle that can be shared with other users and will
+    /// release the service when the last reference is deleted.  In
+    /// Athena the framework itself will hold on to the service (or at
+    /// least its configuration) and release it at the end of the job,
+    /// even if no user code references it.  As a user you should not
+    /// rely on the service still being around after you destroy the
+    /// last reference, or on the service being around after framework
+    /// teardown has started.
+    ///
+    /// \par Guarantee
+    ///   strong
+    /// \par Failures
+    ///   configuration errors\n
+    ///   service creation/initialization errors
+    /// \{
+  public:
+    template<typename T> ::StatusCode
+    makeService (std::shared_ptr<T>& service) const;
+    template<typename T> ::StatusCode
+    makeService (ServiceHandle<T>& service) const;
+    /// \}
+
+
+
+    //
+    // private interface
+    //
+  };
+
+
+
+  //
+  // template methods
+  //
+
+#ifdef XAOD_STANDALONE
+
+  template<typename T> ::StatusCode AsgServiceConfig ::
+  makeService (std::shared_ptr<T>& service) const
+  {
+    using namespace msgComponentConfig;
+
+    std::unique_ptr<T> myservice;
+    ANA_CHECK (makeComponentExpert (myservice, "new %1% (\"%2%\", nullptr)", false, ""));
+    AsgService *asgService = dynamic_cast<AsgService*>(myservice.get());
+    ANA_CHECK (asgService->initialize());
+
+    service = std::move (myservice);
+    ANA_CHECK (ServiceStore::put (service));
+
+    ANA_MSG_DEBUG ("Created component of type " << type());
+    return StatusCode::SUCCESS;
+  }
+
+  template<typename T> ::StatusCode AsgServiceConfig ::
+  makeService (ServiceHandle<T>& service) const
+  {
+    using namespace msgComponentConfig;
+
+    std::shared_ptr<T> myservice;
+    ANA_CHECK (makeService (myservice));
+    service = ServiceHandle (myservice, service.parentName());
+    return StatusCode::SUCCESS;
+  }
+
+#else
+
+  template<typename T> ::StatusCode AsgServiceConfig ::
+  makeService (std::shared_ptr<T>& service) const
+  {
+    using namespace msgComponentConfig;
+
+    ServiceHandle<T> serviceHandle (typeAndName(), "AsgServiceConfig");
+    ANA_CHECK (makeService (serviceHandle));
+
+    // This creates an unmanaged shared pointer, i.e. a pointer that
+    // doesn't actually own the pointed to object, it will neither
+    // guarantee to keep the object around until its own destruction,
+    // nor will it ever trigger a destruction of the object on its own
+    // destruction.  Since the athena framework will keep the services
+    // around until the end of the job, that ought to be safe if used
+    // as advertised.
+    service = std::shared_ptr<T> (std::shared_ptr<void>(), &*serviceHandle);
+
+    ANA_MSG_DEBUG ("Created component of type " << type());
+    return StatusCode::SUCCESS;
+  }
+
+  template<typename T> ::StatusCode AsgServiceConfig ::
+  makeService (ServiceHandle<T>& service) const
+  {
+    using namespace msgComponentConfig;
+
+    ANA_CHECK (configureComponentExpert ("", false));
+    service.setTypeAndName (typeAndName());
+    ANA_CHECK (service.retrieve());
+    ANA_CHECK (dynamic_cast<::AthService*>(&*service)->sysInitialize());
+
+    ANA_MSG_DEBUG ("Created component of type " << type());
+    return StatusCode::SUCCESS;
+  }
+
+#endif
+
+}
+
+#endif
diff --git a/Control/AthToolSupport/AsgServices/AsgServices/AsgServiceMacros.h b/Control/AthToolSupport/AsgServices/AsgServices/AsgServiceMacros.h
new file mode 100644
index 0000000000000000000000000000000000000000..035691534c34310b4cc703a3cb4ec1f180211e33
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/AsgServices/AsgServiceMacros.h
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+/// @author Nils Krumnack
+/// @author David Adams <dladams@bnl.gov> (for original implementation for tools)
+
+#ifndef AsgServiceMacros_H
+#define AsgServiceMacros_H
+
+/// \file CPP macros that turn ASG services into Athena services.
+
+#ifndef XAOD_STANDALONE
+
+// This is used in the body of the service interface class definition, e.g.
+//   class IMyServiceInterface:
+//   virtual public IAsgService {
+//   ASG_SERVICE_INTERFACE(MyServiceInterface)
+//   .
+//   .
+//   .
+//   };
+  
+#define ASG_SERVICE_INTERFACE(CLASSNAME) \
+public: \
+  static const InterfaceID& interfaceID() { \
+    static const InterfaceID myid(#CLASSNAME, 1, 0 ); \
+    return myid; \
+  } 
+
+// This is used in the body of the service implementation definition, e.g.
+//   class MyServiceInterface:
+//   virtual public IMyServiceInterface, public AsgService {
+//   ASG_SERVICE_INTERFACE(MyServiceInterface,IMyServiceInterface)
+//   .
+//   .
+//   .
+//   };
+  
+#define ASG_SERVICE_CLASS1(CLASSNAME,INT1)      \
+  public:                                       \
+  StatusCode queryInterface( const InterfaceID& riid, void** ppvi ) override { \
+  if ( ppvi == nullptr ) { return StatusCode::FAILURE ; }               \
+    if ( INT1::interfaceID() == riid ) {                                \
+    *ppvi = static_cast<INT1*>(this);                                   \
+    addRef();                                                           \
+    return StatusCode::SUCCESS;}                                        \
+  return AthService::queryInterface( riid, ppvi );}
+
+#else
+
+#define ASG_SERVICE_INTERFACE(CLASSNAME)
+#define ASG_SERVICE_CLASS1(CLASSNAME,INT1)
+
+#endif
+
+#endif
diff --git a/Control/AthToolSupport/AsgServices/AsgServices/AsgServicesDict.h b/Control/AthToolSupport/AsgServices/AsgServices/AsgServicesDict.h
new file mode 100644
index 0000000000000000000000000000000000000000..adf156bcc469d6a3e32767aa728d55851b4ab0ae
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/AsgServices/AsgServicesDict.h
@@ -0,0 +1,17 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef ASGSERVICES_ASGSERVICESDICT_H
+#define ASGSERVICES_ASGSERVICESDICT_H
+
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+// Local include(s):
+#include "AsgServices/IAsgService.h"
+#include "AsgServices/AsgService.h"
+#include "AsgServices/AsgServiceConfig.h"
+
+#endif // not ASGSERVICES_ASGSERVICESDICT_H
diff --git a/Control/AthToolSupport/AsgServices/AsgServices/AsgServicesStandaloneDict.h b/Control/AthToolSupport/AsgServices/AsgServices/AsgServicesStandaloneDict.h
new file mode 100644
index 0000000000000000000000000000000000000000..ac71e7e6d5f6f91a7ac4702dad228b54809f9a94
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/AsgServices/AsgServicesStandaloneDict.h
@@ -0,0 +1,15 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef ASGSERVICES_ASGSERVICESSTANDALONEDICT_H
+#define ASGSERVICES_ASGSERVICESSTANDALONEDICT_H
+
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+// Local include(s):
+#include "AsgServices/ServiceStore.h"
+
+#endif // not ASGSERVICES_ASGSERVICESDICT_H
diff --git a/Control/AthToolSupport/AsgServices/AsgServices/IAsgService.h b/Control/AthToolSupport/AsgServices/AsgServices/IAsgService.h
new file mode 100644
index 0000000000000000000000000000000000000000..4e1450dd20bddb637212b18ddb747612f46f4cae
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/AsgServices/IAsgService.h
@@ -0,0 +1,36 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+/// @author Nils Krumnack
+/// @author David Adams <dladams@bnl.gov> (for original implementation for tools)
+
+#ifndef ASGSERVICES_IASGSERVICE_H
+#define ASGSERVICES_IASGSERVICE_H
+
+// System include(s):
+#include <string>
+
+// Local include(s):
+#include "AsgServices/AsgServiceMacros.h"
+#include "AsgMessaging/INamedInterface.h"
+
+namespace asg
+{
+  /// Base class for the dual-use service interface classes
+  ///
+  /// Loosely based on IAsgTool class
+
+  class IAsgService
+    : virtual public INamedInterface
+  {
+  public:
+
+    /// Print the state of the service
+    virtual void print() const = 0;
+
+  }; // class IAsgService
+
+} // namespace asg
+
+#endif // ASGSERVICES_IASGSERVICE_H
diff --git a/Control/AthToolSupport/AsgServices/AsgServices/ServiceHandle.h b/Control/AthToolSupport/AsgServices/AsgServices/ServiceHandle.h
new file mode 100644
index 0000000000000000000000000000000000000000..8f9e87bf09621d768fc38999c1daeb21dbcb0152
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/AsgServices/ServiceHandle.h
@@ -0,0 +1,131 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+/// @author Nils Krumnack
+/// @author David Adams <dladams@bnl.gov> (for original implementation for tools)
+/// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> (for original implementation for tools)
+
+
+#ifndef ASGSERVICES_SERVICEHANDLE_H
+#define ASGSERVICES_SERVICEHANDLE_H
+
+// Local include(s):
+#ifndef XAOD_STANDALONE
+#   include "GaudiKernel/ServiceHandle.h"
+#else // not XAOD_STANDALONE
+
+// System include(s):
+#include <string>
+#include <iosfwd>
+
+// Local include(s):
+#include "AsgMessaging/StatusCode.h"
+#include "AsgServices/ServiceStore.h"
+
+/// Non-templated base class for the ServiceHandle types
+///
+/// This base class takes care of implementing all the functionality of
+/// ServiceHandle that doesn't depend on the template parameter of the class.
+/// Making the built binaries a bit smaller, and faster.
+///
+/// Based on \ref ToolHandleBase
+
+class ServiceHandleBase
+{
+public:
+   /// Constructor with a type/name string
+  ServiceHandleBase( const std::string& typeAndName, const std::string& parentName );
+
+   /// Return the type/name string specified by the user
+   const std::string& typeAndName() const;
+   /// Return the service's type name
+   const std::string& type() const;
+   /// Return the service's instance name
+   const std::string& name() const;
+   /// Return the service's parent service name
+   const std::string& parentName() const;
+
+   /// Change the handle's type and name
+   void setTypeAndName(const std::string& typeAndName);
+   /// Change the handle's name
+   void setName(const std::string& name);
+
+protected:
+   /// The type/name string specified in the constructor
+   std::string m_typeAndName;
+   /// The type name of the target service
+   std::string m_type;
+   /// The instance name of the target service
+   std::string m_name;
+   /// The parent service
+   std::string m_parentName;
+
+}; // class ServiceHandleBase
+
+/// Partial re-implementation of Gaudi's ServiceHandle class
+///
+/// This class can be used in a dual-use service to find other
+/// dual-use services that have been instantiated by the user.
+///
+/// Based on \ref ToolHandle implementation
+
+template< class T >
+class ServiceHandle : public ServiceHandleBase
+{
+public:
+   /// A convenience type declaration
+   typedef T value_type;
+
+   /// Constructor from a service pointer
+   ServiceHandle( const std::shared_ptr<T>& pservice,
+                  const std::string& parentName );
+
+   /// Constructor from a service name.
+   ServiceHandle( const std::string& servicename, const std::string& parentName);
+
+   /// Constructor declaring a property
+   template<typename T2>
+   ServiceHandle (T2 *parent, const std::string& propertyName,
+               const std::string& serviceName,
+               const std::string& propertyTitle = "");
+
+   /// Dereferencing operator
+   T& operator*();
+   /// Dereferencing operator
+   const T& operator*() const;
+   /// Dereferencing operator
+   T* operator->();
+   /// Dereferencing operator
+   const T* operator->() const;
+
+   /// Retrieve service.
+   /// For compatibility with Gaudi.
+   /// Returns success if pointer is non-null and of the correct type.
+   StatusCode retrieve() const;
+
+   /// Clear out the service
+   void disable () noexcept;
+
+   /// Return true if service has no pointer or name
+   bool empty() const;
+
+   /// Return if the pointer is set
+   bool isSet() const;
+
+private:
+   /// Pointer to the service
+   mutable std::shared_ptr<T> m_pservice;
+
+}; // class ServiceHandle
+
+/// A convenience operator for printing the values of such objects
+template< class T >
+std::ostream& operator<< ( std::ostream& out,
+                           const ServiceHandle< T >& handle );
+
+// Include the implementation of the code:
+#include "AsgServices/ServiceHandle.icc"
+
+#endif // not XAOD_STANDALONE
+#endif // ASGSERVICES_SERVICEHANDLE_H
diff --git a/Control/AthToolSupport/AsgServices/AsgServices/ServiceHandle.icc b/Control/AthToolSupport/AsgServices/AsgServices/ServiceHandle.icc
new file mode 100644
index 0000000000000000000000000000000000000000..bca4b52f304296140f916f4558c4fdf802da8549
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/AsgServices/ServiceHandle.icc
@@ -0,0 +1,182 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+/// @author Nils Krumnack
+/// @author David Adams <dladams@bnl.gov> (for original implementation for tools)
+
+
+
+#ifndef ASGSERVICES_SERVICEHANDLE_ICC
+#define ASGSERVICES_SERVICEHANDLE_ICC
+
+// System include(s):
+#include <stdexcept>
+#include <iostream>
+
+// Local include(s):
+#include "AsgServices/ServiceStore.h"
+
+template< class T >
+ServiceHandle< T >::ServiceHandle( const std::shared_ptr<T>& pservice,
+                                   const std::string& parentName)
+  : ServiceHandleBase("",parentName), m_pservice( pservice )
+{
+  // Set the name in the base class in case we received a valid pointer:
+  if( m_pservice ) {
+    m_name = m_pservice->name();
+  }
+}
+
+template< class T >
+ServiceHandle< T >::ServiceHandle( const std::string& typeAndName,
+                                   const std::string& parentName )
+: ServiceHandleBase( typeAndName , parentName )
+{}
+
+template<typename T> template<typename T2>
+ServiceHandle<T> ::
+ServiceHandle (T2 *parent, const std::string& propertyName,
+               const std::string& serviceName,
+               const std::string& propertyTitle)
+  : ServiceHandle (serviceName, parent)
+{
+  parent->declareProperty (propertyName, *this, propertyTitle);
+}
+
+template< class T >
+T& ServiceHandle< T >::operator*()
+{
+   // Retrieve the service pointer if necessary:
+   if( ! m_pservice )
+     m_pservice = asg::ServiceStore::get< T >( name() );
+
+   // Check if we succeeded:
+   if( ! m_pservice )
+      throw std::runtime_error( "Couldn't find service with name \"" +
+                                name() + "\"" );
+
+   // Return a reference to the service:
+   return *m_pservice;
+}
+
+template< class T >
+const T& ServiceHandle< T >::operator*() const
+{
+   // Retrieve the service pointer if necessary:
+   if( ! m_pservice )
+      m_pservice = asg::ServiceStore::get< T >( name() );
+
+   // Check if we succeeded:
+   if( ! m_pservice )
+      throw std::runtime_error( "Couldn't find service with name \"" +
+                                name() + "\"" );
+
+   // Return a reference to the service:
+   return *m_pservice;
+}
+
+template< class T >
+T* ServiceHandle<T>::operator->()
+{
+   // Retrieve the service pointer if necessary:
+   if( ! m_pservice ) {
+      m_pservice = asg::ServiceStore::get< T >( name() );
+   }
+   // Check if we succeeded:
+   if( ! m_pservice ) {
+      throw std::runtime_error( "Couldn't find service with name \"" +
+                                name() + "\"" );
+   }
+
+   // Return the (possibly null-)pointer to the service:
+   return m_pservice.get();
+}
+
+template< class T >
+const T* ServiceHandle<T>::operator->() const
+{
+
+   // Retrieve the service pointer if necessary:
+   if( ! m_pservice )
+      m_pservice = asg::ServiceStore::get< T >( name() );
+
+   // Check if we succeeded:
+   if( ! m_pservice )
+      throw std::runtime_error( "Couldn't find service with name \"" +
+                                name() + "\"" );
+
+   // Return the (possibly null-)pointer to the service:
+   return m_pservice.get();
+}
+
+template< class T >
+StatusCode ServiceHandle< T >::retrieve() const
+{
+  // If we have the service already, there's nothing to do:
+  if( m_pservice )
+    return StatusCode::SUCCESS;
+
+  // Try to retrieve the service:
+  m_pservice = asg::ServiceStore::get< T >( name() );
+
+  // Check if it succeeded:
+  if( m_pservice ) {
+    return StatusCode::SUCCESS;
+  } else {
+    return StatusCode::FAILURE;
+  }
+}
+
+template< class T >
+void ServiceHandle< T >::disable () noexcept
+{
+  m_pservice.reset ();
+}
+
+template< class T >
+bool ServiceHandle< T >::empty() const
+{
+  return ( ( m_pservice == nullptr ) && ( name().size() == 0 ) );
+}
+
+template< class T >
+bool ServiceHandle< T >::isSet() const
+{
+  return ( !( m_pservice == nullptr ) );
+}
+
+template< class T >
+std::ostream& operator<<( std::ostream& out,
+                          const ServiceHandle< T >& handle )
+{
+  out << "ASG ServiceHandle with name = \"" << handle.name() << "\", pointer = ";
+  const T* pservice = nullptr;
+  if (handle.retrieve())
+    pservice = &*handle;
+  out << pservice;
+
+  // Return the same stream object:
+  return out;
+}
+
+namespace asg
+{
+  namespace detail
+  {
+    StatusCode packStringSingle (const std::string& value,
+				 std::string& result);
+
+    template<typename T> struct GetStringHelper;
+
+    template<typename T> struct GetStringHelper<ServiceHandle<T> >
+    {
+      static StatusCode get (const ServiceHandle<T>& value,
+			     std::string& result) {
+        return packStringSingle (value.typeAndName(), result);
+      }
+    };
+  }
+}
+
+#endif // ASGSERVICES_SERVICEHANDLE_ICC
diff --git a/Control/AthToolSupport/AsgServices/AsgServices/ServiceStore.h b/Control/AthToolSupport/AsgServices/AsgServices/ServiceStore.h
new file mode 100644
index 0000000000000000000000000000000000000000..24941b50d515e999e0e5a9b1163ef0ee210cea9f
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/AsgServices/ServiceStore.h
@@ -0,0 +1,76 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+/// @author Nils Krumnack
+/// @author David Adams <dladams@bnl.gov> (for original implementation for tools)
+/// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> (for original implementation for tools)
+
+
+
+#ifndef ASGSERVICES_SERVICESTORE_H
+#define ASGSERVICES_SERVICESTORE_H
+
+#ifndef XAOD_STANDALONE
+#error "This header should only be used in XAOD_STANDALONE"
+#else
+
+// System include(s):
+#include <memory>
+#include <string>
+
+// Local include(s):
+#include "AsgServices/IAsgService.h"
+#include "AsgMessaging/StatusCode.h"
+
+namespace asg
+{
+
+  /// A light-weight store for services in stand-alone analysis
+  ///
+  /// In order to allow users to find services through
+  /// ServiceHandles, just like in Athena, we need a global registry
+  /// of all of the services that the user instantiates in his/her
+  /// job.
+  ///
+  /// This class does exactly this. Services created via \ref
+  /// AsgServiceConfig get registered here so that other components
+  /// can find them.
+  ///
+  /// Based on \ref ToolStore
+
+  class ServiceStore final
+  {
+  public:
+    /// Store a named service by its name.
+    /// The name must be non-blank and not already exist in the store.
+    static StatusCode put( const std::shared_ptr<IAsgService>& pservice );
+
+    /// Retrieve a service by name.
+    static std::shared_ptr<IAsgService> get( const std::string& name, bool silent = false );
+
+    /// Retrieve a service by name and interface.
+    template< typename T >
+    // cppcheck-suppress constStatement; false positive
+    static std::shared_ptr<T> get( const std::string& name )
+    {
+      return std::dynamic_pointer_cast< T >( get( name ) );
+    }
+
+    /// Check whether a service with a given type and name is known in the store
+    template< typename T >
+    static bool contains( const std::string& name )
+    {
+      return ( dynamic_cast< T* >( get( name, true ).get() ) != 0 );
+    }
+
+    /// dump the service configuration for all services to std::cout
+    static void dumpServiceConfig ();
+
+  }; // class ServiceStore
+
+} // namespace asg
+
+#endif
+
+#endif // ASGSERVICES_SERVICESTORE_H
diff --git a/Control/AthToolSupport/AsgServices/AsgServices/selection.xml b/Control/AthToolSupport/AsgServices/AsgServices/selection.xml
new file mode 100644
index 0000000000000000000000000000000000000000..89a5d061f071fe4be373c65379407ec6e7cd7de8
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/AsgServices/selection.xml
@@ -0,0 +1,14 @@
+<!--
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+ -->
+
+<lcgdict>
+
+   <!-- The basic service types: -->
+   <class name="asg::IAsgService" />
+   <class name="asg::AsgService" />
+   <class name="asg::AsgServiceConfig" />
+
+   <!-- Helper types: -->
+
+</lcgdict>
diff --git a/Control/AthToolSupport/AsgServices/AsgServices/selection_standalone.xml b/Control/AthToolSupport/AsgServices/AsgServices/selection_standalone.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4133fe59de8339a73037fd96582976b84571f180
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/AsgServices/selection_standalone.xml
@@ -0,0 +1,9 @@
+<!--
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+ -->
+
+<lcgdict>
+
+   <class name="asg::ServiceStore" />
+
+</lcgdict>
diff --git a/Control/AthToolSupport/AsgServices/CMakeLists.txt b/Control/AthToolSupport/AsgServices/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..009e5a2f08e8f4bcfedd3f7b52337609719e831b
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/CMakeLists.txt
@@ -0,0 +1,41 @@
+# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+
+# Declare the package name:
+atlas_subdir( AsgServices )
+
+# Dependencies are taken based on what environment we are in:
+if( XAOD_STANDALONE )
+   set( libs )
+else()
+   set( libs )
+endif()
+
+# Decide which sources to use:
+if( XAOD_STANDALONE )
+   set( sources Root/*.cxx )
+else()
+   set( sources Root/AsgService.cxx Root/AsgServiceConfig.cxx )
+endif()
+
+# Component(s) in the package:
+atlas_add_library( AsgServicesLib
+   AsgServices/*.h AsgServices/*.icc ${sources}
+   PUBLIC_HEADERS AsgServices
+   PRIVATE_INCLUDE_DIRS
+   LINK_LIBRARIES AsgTools ${libs}
+   PRIVATE_LINK_LIBRARIES )
+
+# Select which xml files to use for dictionary generation
+
+atlas_add_dictionary( AsgServicesDict
+   AsgServices/AsgServicesDict.h AsgServices/selection.xml
+   LINK_LIBRARIES AsgServicesLib )
+
+if (XAOD_STANDALONE)
+  atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )
+   atlas_add_test( AsgServiceConfigUnitTests
+      SCRIPT python -m unittest AsgServices.AsgServiceConfig )
+  atlas_add_dictionary( AsgServicesStandaloneDict
+     AsgServices/AsgServicesStandaloneDict.h AsgServices/selection_standalone.xml
+     LINK_LIBRARIES AsgServicesLib )
+endif ()
diff --git a/Control/AthToolSupport/AsgServices/Root/AsgService.cxx b/Control/AthToolSupport/AsgServices/Root/AsgService.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..77683417451129811abf6254d9b5e4326ea2cc20
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/Root/AsgService.cxx
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+/// @author Nils Krumnack
+/// @author David Adams <dladams@bnl.gov> (for original implementation for tools)
+
+
+
+// Local include(s):
+#include "AsgServices/AsgService.h"
+
+// System include(s):
+#include <iostream>
+
+namespace asg
+{
+  AsgService ::
+  AsgService( const std::string& name,
+              ISvcLocator* pSvcLocator )
+      : AsgServiceBase(
+#ifndef XAOD_STANDALONE
+                       name, pSvcLocator
+#else // not XAOD_STANDALONE
+                       name
+#endif // not XAOD_STANDALONE
+                    )
+   {
+     (void) pSvcLocator;
+   }
+
+  StatusCode AsgService ::
+  initialize ()
+  {
+    return StatusCode::SUCCESS;
+  }
+
+
+
+  StatusCode AsgService ::
+  finalize ()
+  {
+    return StatusCode::SUCCESS;
+  }
+
+
+
+  void AsgService::print() const
+  {
+    ATH_MSG_INFO( "AsgService " << name() << " @ " << this );
+    return;
+  }
+
+} // namespace asg
diff --git a/Control/AthToolSupport/AsgServices/Root/AsgServiceConfig.cxx b/Control/AthToolSupport/AsgServices/Root/AsgServiceConfig.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..9c1be6bb4c1b8e5ac111a49d06d077b03d9ddd1e
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/Root/AsgServiceConfig.cxx
@@ -0,0 +1,28 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+/// @author Nils Krumnack
+
+
+
+//
+// includes
+//
+
+#include <AsgServices/AsgServiceConfig.h>
+
+#include <AsgServices/AsgService.h>
+#include <AsgTools/MessageCheckAsgTools.h>
+
+//
+// method implementations
+//
+
+namespace asg
+{
+  AsgServiceConfig ::
+  AsgServiceConfig (const std::string& val_typeAndName)
+    : AsgComponentConfig (val_typeAndName)
+  {}
+}
diff --git a/Control/AthToolSupport/AsgServices/Root/ServiceHandle.cxx b/Control/AthToolSupport/AsgServices/Root/ServiceHandle.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..bfa1fa3b560a62267244dc924de5893fa81dc5d8
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/Root/ServiceHandle.cxx
@@ -0,0 +1,77 @@
+/*
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+*/
+
+/// @author Nils Krumnack
+/// @author David Adams <dladams@bnl.gov> (for original implementation for tools)
+/// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> (for original implementation for tools)
+
+
+
+// Local include(s):
+#include "AsgServices/ServiceHandle.h"
+#include "AsgServices/IAsgService.h"
+
+ServiceHandleBase ::
+ServiceHandleBase( const std::string& typeAndName,
+                   const std::string& parentName )
+  : m_typeAndName( typeAndName ), m_type(), m_name(), m_parentName(parentName)
+{
+   setTypeAndName(typeAndName);
+}
+
+
+
+void ServiceHandleBase::setTypeAndName(const std::string& typeAndName)
+{
+  m_typeAndName = typeAndName;
+  // Decode the received string:
+  size_t pos = 0;
+  if( ( pos = m_typeAndName.find( '/' ) ) == std::string::npos )
+  {
+    // The user specified a single string, which is used as both the type
+    // and instance name.
+    m_type = m_typeAndName;
+    m_name = m_typeAndName;
+  } else
+  {
+    // The user specified both a type and an instance name.
+    m_type = m_typeAndName.substr( 0, pos );
+    m_name = m_typeAndName.substr( pos + 1 );
+  }
+}
+
+
+
+void ServiceHandleBase::setName(const std::string& name)
+{
+  m_name = name;
+}
+
+
+
+const std::string& ServiceHandleBase::typeAndName() const
+{
+  return m_typeAndName;
+}
+
+
+
+const std::string& ServiceHandleBase::type() const
+{
+  return m_type;
+}
+
+
+
+const std::string& ServiceHandleBase::name() const
+{
+  return m_name;
+}
+
+
+
+const std::string& ServiceHandleBase::parentName() const
+{
+  return m_parentName;
+}
diff --git a/Control/AthToolSupport/AsgServices/Root/ServiceStore.cxx b/Control/AthToolSupport/AsgServices/Root/ServiceStore.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..fbecdd3d1f8376ad780d939ea5dc531530211afb
--- /dev/null
+++ b/Control/AthToolSupport/AsgServices/Root/ServiceStore.cxx
@@ -0,0 +1,136 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+/// @author Nils Krumnack
+/// @author David Adams <dladams@bnl.gov> (for original implementation for tools)
+/// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> (for original implementation for tools)
+
+
+
+// Local include(s):
+#include "AsgServices/ServiceStore.h"
+#include "AsgServices/AsgService.h"
+#include "AsgTools/MessageCheckAsgTools.h"
+#include "AsgMessaging/MsgStreamMacros.h"
+
+// System include(s):
+#include <map>
+#include <iostream>
+#include <mutex>
+
+/// Convenience type definition
+typedef std::map< std::string, std::weak_ptr<asg::IAsgService> > ServiceMap_t;
+
+namespace
+{
+  /// The application-wide service registry
+  static ServiceMap_t s_services ATLAS_THREAD_SAFE;
+  std::mutex s_serviceMutex;
+}
+
+namespace asg
+{
+  StatusCode ServiceStore::
+  put( const std::shared_ptr<IAsgService>& pservice )
+  {
+    using namespace msgComponentConfig;
+
+    // Start with a little sanity check:
+    if( ! pservice )
+    {
+      ANA_MSG_ERROR( "asg::ServiceStore::put      " <<
+                     "Received a null pointer" );
+      return StatusCode::FAILURE;
+    }
+
+    // Get and check the name of the service:
+    const std::string& name = pservice->name();
+    if( ! name.size() )
+    {
+      ANA_MSG_ERROR( "asg::ServiceStore::put      " <<
+                     "The received service doesn't have a name" );
+      return StatusCode::FAILURE;
+    }
+
+    std::lock_guard<std::mutex> lock (s_serviceMutex);
+
+    auto& currentService = s_services[name];
+    if (currentService.lock())
+    {
+      ANA_MSG_ERROR ("Service with name \""
+                     << name << "\" already registered");
+      return StatusCode::FAILURE;
+    }
+
+    currentService = pservice;
+    return StatusCode::SUCCESS;
+  }
+
+
+
+  std::shared_ptr<IAsgService> ServiceStore::
+  get( const std::string& name, bool silent )
+  {
+    using namespace msgToolHandle;
+
+    std::lock_guard<std::mutex> lock (s_serviceMutex);
+    auto iservice = s_services.find( name );
+
+    std::shared_ptr<IAsgService> result;
+    if( iservice != s_services.end() )
+      result = iservice->second.lock();
+
+    if( ! silent && !result )
+      ANA_MSG_ERROR ("Service with name \"" << name << "\" not found");
+    return result;
+  }
+
+
+
+  void ServiceStore::dumpServiceConfig ()
+  {
+    using namespace asg::msgProperty;
+
+    // I am first putting everything into a map, so that the error
+    // messages don't interleave the property values
+    std::map<std::string,std::map<std::string,std::string> > properties;
+
+    std::lock_guard<std::mutex> lock (s_serviceMutex);
+    for (auto& service : s_services)
+    {
+      auto myservice = service.second.lock();
+      if (myservice)
+      {
+        auto& myproperties = properties[service.first];
+        myproperties[""] = std::string (typeid(*myservice).name()) + "/" + service.first;
+        for (auto& property : dynamic_cast<const AsgService*>(myservice.get())->getPropertyMgr()->getProperties())
+        {
+          std::string asString;
+          if (property.second->getString (asString).isFailure())
+          {
+            ANA_MSG_ERROR ("on property " << property.first << " for service " << service.first);
+            myproperties[property.first] = "<<invalid>>";
+          } else
+            myproperties[property.first] = asString;
+        }
+      }
+    }
+    // Using std::cout here intentionally to bypass the messaging
+    // system to avoid accidental changes to the formatting.  This
+    // could be updated in the future to allow the user to pass in the
+    // stream to output to, if desired.
+    for (const auto& myproperties : properties)
+    {
+      for (auto& property : myproperties.second)
+      {
+	std::cout << myproperties.first;
+	if (!property.first.empty())
+	  std::cout << "." << property.first;
+	std::cout << " = " << property.second << "\n";
+      }
+    }
+    std::cout << std::flush;
+  }
+
+} // namespace asg