MonoBehaviour Services
Use a MonoBehaviour Service when a service needs references to Unity objects, such as:
- Prefabs
- ScriptableObjects
- AudioSources
- Cameras
- Materials
- UI elements
- Scene objects
A MonoBehaviourService is a normal Unity MonoBehaviour that is also registered as a service.
Unlike pure C# services, MonoBehaviour services can be configured through the Unity Inspector and can directly reference objects managed by Unity.
The scope of a MonoBehaviour service is determined by where it is registered:
- Application scope — lives for the lifetime of the application.
- Scene scope — lives for the lifetime of a particular scene.
Creating a MonoBehaviour Service
Section titled “Creating a MonoBehaviour Service”Mark a MonoBehaviour with [MonoBehaviourService]:
using UnityEngine;using OneLastClick.Services.Attributes;
[MonoBehaviourService]public partial class PlayerManager : MonoBehaviour{ [SerializeField] public GameObject PlayerPrefab;}PlayerManager is now a service that can be resolved through the service system. Where the component is placed determines its scope.
The
partialmodifier is required because a source generator adds the automatic registration functionality to the class.
Application MonoBehaviour Services
Section titled “Application MonoBehaviour Services”Use an Application MonoBehaviour Service when the service should exist for the entire lifetime of the application.
Application MonoBehaviour services are created from a single prefab when the application starts.
Create an Application Services prefab
Section titled “Create an Application Services prefab”- Create an empty prefab in your project, for example
ApplicationServices.prefab. - Add your
MonoBehaviourServicecomponents to the root GameObject of the prefab. - Open Project Settings → OneLastClick → Services.
- Assign the prefab to Application Services Prefab.
When the application starts, OneLastClick.Services loads the prefab and registers every MonoBehaviourService on its root GameObject.
Only
MonoBehaviourServicecomponents on the root GameObject are automatically discovered.
For example:
ApplicationServices.prefab ├── PlayerManager ├── AudioService └── SettingsServiceThis prefab have an instance when entering play mode or in a build.
- During Editor, it will be instantiated before the first scene load
- In a Built Player, the prefab will have an instance in the first scene in the EditorBuildSettings.
Access an application service
Section titled “Access an application service”Application services can be resolved through ApplicationServices:
PlayerManager playerManager = ApplicationServices.Get<PlayerManager>();
GameObject playerPrefab = playerManager.PlayerPrefab;No serialized reference or singleton Instance property is required.
Example
Section titled “Example”public class PlayerSpawner : MonoBehaviour{ private void Start() { PlayerManager playerManager = ApplicationServices.Get<PlayerManager>();
Instantiate(playerManager.PlayerPrefab); }}Scene MonoBehaviour Services
Section titled “Scene MonoBehaviour Services”Use a Scene MonoBehaviour Service when the service belongs to a particular Unity scene.
Scene services are registered from MonoBehaviour components that exist in the scene.
For example:
using UnityEngine;using OneLastClick.Services.Attributes;
[MonoBehaviourService]public partial class LevelService : MonoBehaviour{ [SerializeField] private Transform _playerSpawnPoint;
[SerializeField] private Transform _enemyContainer;}Add the component to a root GameObject in the scene:
Level└── LevelServiceWhen the scene is loaded, OneLastClick.Services discovers the service and registers it in that scene’s service scope.
Scene MonoBehaviour services must be attached to a root GameObject for automatic discovery.
Unlike application services, scene services are removed when their scene is unloaded.
Referencing Scene Objects
Section titled “Referencing Scene Objects”One of the main benefits of a scene MonoBehaviour service is that it can reference objects that already exist in the scene.
For example:
[MonoBehaviourService]public partial class LevelService : MonoBehaviour{ [SerializeField] private Transform _playerSpawnPoint;
[SerializeField] private Transform _enemyContainer;
public Transform PlayerSpawnPoint { get { return _playerSpawnPoint; } }
public Transform EnemyContainer { get { return _enemyContainer; } }}The references can then be assigned directly through the Inspector.
Other components can resolve the service instead of having to receive references to each individual scene object:
LevelService levelService = gameObject.GetService<LevelService>();
Transform spawnPoint = levelService.PlayerSpawnPoint;This makes the service a convenient boundary around scene-specific references and systems.
Using Pure C# Services in a Scene
Section titled “Using Pure C# Services in a Scene”A scene service does not have to be a MonoBehaviour.
If you want to keep the service itself as a pure C# class, but still need to provide it with references to Unity objects, you can use an IServiceRegisterer.
The MonoBehaviour acts as the bridge between Unity and your pure C# service:
public class PlayerController : MonoBehaviour, IServiceRegisterer{ [SerializeField] private GameObject _prefab;
public void RegisterServices(ServicesCollectionBuilder builder) { builder.Register<IPlayerSpawnerService>(new PlayerSpawnerService(_prefab)); }}This keeps PlayerSpawnerService completely independent of Unity while allowing the scene to configure it through the Inspector.
The MonoBehaviour owns the Unity references, while the service receives only the dependencies it actually needs.
This can be useful when you want to keep your application logic testable and independent of Unity, while still configuring that logic from a scene.
Like components with the
MonoBehaviourServiceattribute, these components need to be on the root for automatic registartion to be invoked.
Application vs Scene Scope
Section titled “Application vs Scene Scope”The same MonoBehaviourService mechanism can be used for both application and scene services.
The difference is where the service is registered.
Application│├── Application Services│ ├── SaveService│ ├── AudioService│ └── PlayerManager│├── Scene A│ ├── LevelService│ └── EnemyService│└── Scene B ├── LevelService └── EnemyServiceApplication services are shared across the application.
Scene services belong to an individual scene.
This means multiple scenes can contain their own instance of the same service type:
Level_01└── LevelService
Level_02└── LevelServiceWhen resolving from an object in Level_01, the scene’s LevelService is used.
When resolving from an object in Level_02, the Level_02 instance is used.
Resolving MonoBehaviour Services
Section titled “Resolving MonoBehaviour Services”There are two convenient ways to resolve scene services.
From a GameObject
Section titled “From a GameObject”When working with a GameObject, use GetService<T>():
LevelService levelService = gameObject.GetService<LevelService>();The lookup uses the scene that the GameObject belongs to.
It first searches the scene service scope.
If the service is not found there, it falls back to the application service scope.
GameObject │ ▼Scene Services │ │ not found ▼Application ServicesThis makes GetService<T>() useful for components that operate inside a scene.
From a Scene
Section titled “From a Scene”You can also explicitly specify the scene:
Scene scene = gameObject.scene;
LevelService levelService = SceneServices.Get<LevelService>(scene);SceneServices.Get<T>() searches the specified scene and then falls back to application services.
Manual Registration
Section titled “Manual Registration”[MonoBehaviourService] is the simplest way to register a MonoBehaviour service.
If you need more control over registration, you can instead implement IServiceRegisterer on a root MonoBehaviour.
public class SceneServiceRegisterer : MonoBehaviour, IServiceRegisterer{ public void RegisterServices(ServicesCollectionBuilder builder) { builder.Register<LevelService>(); }}See Service Collection Builder for all registartion methods on the builder.
This allows you to explicitly control which services are registered and how they are constructed.
Manual registration is useful when:
- A service requires custom registration logic.
- You need to register a service that is not marked with
[MonoBehaviourService]. - Multiple services need to be configured together.
IServiceRegisterer can be used wherever services need to be registered, including scene-level registration.
MonoBehaviour Services vs Pure C# Services
Section titled “MonoBehaviour Services vs Pure C# Services”Not every service needs to be a MonoBehaviour.
Use a pure C# application service when the service does not need to reference Unity objects.
Pure C# Service │ └── No Unity object references required
MonoBehaviour Service │ ├── Prefab references ├── Scene objects ├── AudioSources ├── Cameras └── Other Unity componentsPrefer a pure C# service when possible.
Use a MonoBehaviour service when the Unity lifecycle, Inspector, or references to Unity objects are part of the service’s responsibilities.
Summary
Section titled “Summary”MonoBehaviour services allow Unity components to participate in the service system while still using the Inspector and referencing Unity objects.
They can be registered at two scopes:
- Application scope — registered from the Application Services prefab and available for the lifetime of the application.
- Scene scope — registered from a scene and available for the lifetime of that scene.
Both use the same [MonoBehaviourService] attribute and can participate in dependency injection.
Use:
ApplicationServices.Get<T>();when explicitly resolving an application service.
Use:
SceneServices.Get<T>(scene);when explicitly resolving a service for a particular scene.
Or, when working with a GameObject, use:
gameObject.GetService<T>();which searches the object’s scene first and then falls back to application services.
The key distinction is therefore not between different kinds of MonoBehaviour services, but where the service lives and how long it should exist.