File: Sessions\ApplicationSession.cs
Web Access
Project: src\src\Aspire.Hosting.Native.Core\Aspire.Hosting.Native.Core.csproj (Aspire.Hosting.Native.Core)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Aspire.Hosting.Native.Model;
using Aspire.Hosting.Native.Diagnostics;
 
namespace Aspire.Hosting.Native.Sessions;
 
/// <summary>Serializes ownership of successive declaration generations within an AppHost session.</summary>
internal sealed class ApplicationSession(TimeProvider timeProvider) : IDisposable
{
    public ApplicationSession() : this(TimeProvider.System)
    {
    }
    private readonly Lock _gate = new();
    private ApplicationModel? _model;
    private bool _disposed;
 
    /// <summary>Gets the identity used to correlate session ownership diagnostics.</summary>
    public Guid SessionId { get; } = Guid.NewGuid();
 
    /// <summary>Starts a generation only after the previous declaration graph has been retired.</summary>
    public ApplicationModel StartGeneration() =>
        NativeDiagnostics.Execute("session.generation.start", SessionId, null, operation => StartGenerationCore(operation), timeProvider);
 
    private ApplicationModel StartGenerationCore(NativeDiagnostics.Operation operation)
    {
        lock (_gate)
        {
            ObjectDisposedException.ThrowIf(_disposed, this);
            if (_model is not null)
            {
                throw new InvalidOperationException("An application generation is already active.");
            }
            _model = new ApplicationModel(timeProvider);
            operation.SetGeneration(_model.GenerationId);
 
            return _model;
        }
    }
 
    /// <summary>Retires the named generation without permitting a late owner to retire its replacement.</summary>
    public void RetireGeneration(Guid generationId) =>
        NativeDiagnostics.Execute("session.generation.retire", SessionId, generationId, _ => RetireGenerationCore(generationId), timeProvider);
 
    private void RetireGenerationCore(Guid generationId)
    {
        lock (_gate)
        {
            ObjectDisposedException.ThrowIf(_disposed, this);
            if (_model is null || _model.GenerationId != generationId)
            {
                throw new InvalidOperationException("The application generation is not active in this session.");
            }
            _model.Dispose();
            _model = null;
        }
    }
 
    /// <summary>Closes the session and invalidates its active declaration generation.</summary>
    public void Dispose() =>
        NativeDiagnostics.Execute("session.close", SessionId, null, _ => DisposeCore(), timeProvider);
 
    private void DisposeCore()
    {
        lock (_gate)
        {
            if (_disposed)
            {
                return;
            }
            _disposed = true;
            _model?.Dispose();
            _model = null;
        }
    }
}