# UseService
*Services in Ivy provide dependency injection and service management for clean application architecture.*
## Overview
The service system in Ivy supports:
- Dependency injection
- Service registration and [configuration](../../../01_Onboarding/02_Concepts/01_Program.md)
- Service [lifecycle management](../../../01_Onboarding/02_Concepts/02_Views.md)
- Scoped and singleton services
- Service interfaces and implementations
- Service [middleware](../../../01_Onboarding/02_Concepts/01_Program.md)
## Basic Usage
Use the `UseService<T>()` hook to access registered services in your views:
```csharp
public class ServiceExampleView : ViewBase
{
public override object? Build()
{
var client = UseService<IClientProvider>();
var message = UseState("Hello from service!");
return Layout.Vertical()
| Text.P(message.Value)
| new Button("Show Toast",
onClick: _ => client.Toast(message.Value, "Service Demo"));
}
}
```
### Service Registration
Register services in your [application startup](../../../01_Onboarding/02_Concepts/01_Program.md):
```csharp
public class Program
{
public static void Main()
{
var server = new Server()
.UseService<IMyService, MyService>()
.UseService<IDataService, DataService>(ServiceLifetime.Singleton)
.UseService<IAuthService, AuthService>();
}
}
```
### Service Descriptions
Services can provide custom descriptions by implementing the `IDescribableService` interface. Use `ServerDescriptionReader` to read environment-specific service descriptions from your [application](../../../01_Onboarding/02_Concepts/10_Apps.md).
```csharp
// Implement IDescribableService for custom service descriptions
public class MyService : IMyService, IDescribableService
{
public string ToYaml()
{
return "Custom service description in YAML format";
}
}
// Read service descriptions with environment context
var description = await ServerDescriptionReader.ReadAsync(
projectDirectory,
environment: "PRODUCTION"
);
```
The `ServiceDescription` class includes an optional `Description` property for better documentation of your services.
### Service Interfaces
Define service interfaces for better abstraction:
```csharp
public interface IDataService
{
Task<IEnumerable<Data>> GetDataAsync();
Task<Data> GetDataByIdAsync(string id);
Task SaveDataAsync(Data data);
}
public class DataService : IDataService
{
private readonly ILogger<DataService> _logger;
public DataService(ILogger<DataService> logger)
{
_logger = logger;
}
public async Task<IEnumerable<Data>> GetDataAsync()
{
_logger.LogInformation("Fetching data");
// Implementation
}
public async Task<Data> GetDataByIdAsync(string id)
{
_logger.LogInformation("Fetching data for id: {Id}", id);
// Implementation
}
public async Task SaveDataAsync(Data data)
{
_logger.LogInformation("Saving data");
// Implementation
}
}
```
### Service Lifetime
Ivy supports different service lifetimes:
```csharp
// Singleton - Created once for the entire application
.UseService<ICacheService, CacheService>(ServiceLifetime.Singleton)
// Scoped - Created once per request
.UseService<IDbContext, DbContext>(ServiceLifetime.Scoped)
// Transient - Created each time requested
.UseService<ILogger, Logger>(ServiceLifetime.Transient)
```
### Service Middleware
Add middleware to services for cross-cutting concerns:
```csharp
public class LoggingServiceMiddleware : IServiceMiddleware
{
private readonly ILogger _logger;
public LoggingServiceMiddleware(ILogger logger)
{
_logger = logger;
}
public async Task<T> ExecuteAsync<T>(Func<Task<T>> next)
{
_logger.LogInformation("Service method called");
try
{
return await next();
}
catch (Exception ex)
{
_logger.LogError(ex, "Service method failed");
throw;
}
}
}
// Register middleware
.UseServiceMiddleware<LoggingServiceMiddleware>()
```
## Best Practices
1. **Interface-based Design**: Always define interfaces for your services
2. **Single Responsibility**: Each service should have a single, well-defined purpose
3. **Dependency Injection**: Use constructor injection for dependencies
4. **Service Lifetime**: Choose appropriate lifetimes for your services
5. **Error Handling**: Implement proper error handling in services
6. **Logging**: Use logging for important operations and errors
7. **Testing**: Make services easily testable through interfaces
## Examples
### Simple Service Usage
Use a service to display notifications or interact with client features:
```csharp
public class SimpleServiceView : ViewBase
{
public override object? Build()
{
var client = UseService<IClientProvider>();
var count = UseState(0);
return Layout.Vertical()
| Text.P($"Button clicked {count.Value} times")
| new Button("Show Toast", onClick: _ =>
{
count.Set(count.Value + 1);
client.Toast($"Notification #{count.Value}", "Service Demo");
});
}
}
```
### Using Multiple Services
Access multiple services in a single view to combine their functionality:
```csharp
public class MultiServiceView : ViewBase
{
public override object? Build()
{
var client = UseService<IClientProvider>();
var message = UseState("Ready");
var count = UseState(0);
return Layout.Vertical()
| Text.P($"Last action: {message.Value}")
| Text.P($"Total actions: {count.Value}")
| (Layout.Horizontal()
| new Button("Action 1", onClick: _ =>
{
count.Set(count.Value + 1);
client.Toast("Action 1 executed", "Service Demo");
message.Set("Action 1 completed");
})
| new Button("Action 2", onClick: _ =>
{
count.Set(count.Value + 1);
client.Toast("Action 2 executed", "Service Demo");
message.Set("Action 2 completed");
}));
}
}
```