Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mongo session provider support #89

Merged
merged 12 commits into from
Jan 19, 2024
6 changes: 6 additions & 0 deletions src/MongoDB.Extensions.sln
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".SolutionFiles", ".Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Context.AllowedTypes.Tests", "Context.AllowedTypes.Tests\Context.AllowedTypes.Tests.csproj", "{C59B2068-C3F4-4900-A1CB-7BFD63F94095}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Session.Abstractions", "Session.Abstractions\Session.Abstractions.csproj", "{01DB2766-1419-4518-9C6F-77BF9C670F72}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -86,6 +88,10 @@ Global
{C59B2068-C3F4-4900-A1CB-7BFD63F94095}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C59B2068-C3F4-4900-A1CB-7BFD63F94095}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C59B2068-C3F4-4900-A1CB-7BFD63F94095}.Release|Any CPU.Build.0 = Release|Any CPU
{01DB2766-1419-4518-9C6F-77BF9C670F72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{01DB2766-1419-4518-9C6F-77BF9C670F72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01DB2766-1419-4518-9C6F-77BF9C670F72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01DB2766-1419-4518-9C6F-77BF9C670F72}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
12 changes: 12 additions & 0 deletions src/Session.Abstractions/ISession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using System.Threading;
using System.Threading.Tasks;

namespace MongoDB.Extensions.Session;

public interface ISession : IDisposable
{
Task<T> WithTransactionAsync<T>(
Func<ISession, CancellationToken, Task<T>> action,
CancellationToken cancellationToken);
}
15 changes: 15 additions & 0 deletions src/Session.Abstractions/ISessionProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Extensions.Context;

namespace MongoDB.Extensions.Session;

public interface ISessionProvider<TContext>
where TContext : IMongoDbContext
{
Task<ITransactionSession> BeginTransactionAsync(
CancellationToken cancellationToken);

Task<ISession> StartSessionAsync(
CancellationToken cancellationToken);
}
9 changes: 9 additions & 0 deletions src/Session.Abstractions/ITransactionSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;
using System.Threading.Tasks;

namespace MongoDB.Extensions.Session;

public interface ITransactionSession : IDisposable
{
Task CommitAsync();
}
14 changes: 14 additions & 0 deletions src/Session.Abstractions/Session.Abstractions.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(CCResourceProjectProps)" Condition="Exists('$(CCResourceProjectProps)')" />

<PropertyGroup>
<AssemblyName>MongoDB.Extensions.Session.Abstractions</AssemblyName>
<RootNamespace>MongoDB.Extensions.Session.Abstractions</RootNamespace>
<PackageId>MongoDB.Extensions.Session.Abstractions</PackageId>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Context\Context.csproj" />
</ItemGroup>

</Project>
52 changes: 52 additions & 0 deletions src/Session/Internal/MongoSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;

namespace MongoDB.Extensions.Session;

internal sealed class MongoSession : ISession
{
private readonly IClientSessionHandle _session;
private bool _disposed;

private static TransactionOptions TransactionOptions { get; } = new(
ReadConcern.Majority,
ReadPreference.Primary,
WriteConcern.WMajority.With(journal: true),
TimeSpan.FromSeconds(180));

public MongoSession(IClientSessionHandle clientSession)
{
_session = clientSession;
}

public Task<T> WithTransactionAsync<T>(
Func<ISession, CancellationToken, Task<T>> action,
CancellationToken cancellationToken)
{
return _session.WithTransactionAsync<T>(
(_, ct) => action(this, ct),
TransactionOptions,
cancellationToken);
}

private void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_session.Dispose();
}

_disposed = true;
}
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
51 changes: 51 additions & 0 deletions src/Session/Internal/MongoSessionProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
using MongoDB.Extensions.Context;

namespace MongoDB.Extensions.Session;

internal class MongoSessionProvider<TContext> : ISessionProvider<TContext>
where TContext : IMongoDbContext
{
private readonly IMongoClient _mongoClient;

public MongoSessionProvider(TContext context)
{
_mongoClient = context.Client;
}

public Task<ITransactionSession> BeginTransactionAsync(
CancellationToken cancellationToken)
{
return BeginTransactionAsync(true, cancellationToken);
}

private async Task<ITransactionSession> BeginTransactionAsync(
bool safeModeEnabled,
CancellationToken cancellationToken)
{
IClientSessionHandle clientSession = await _mongoClient
.StartSessionAsync(cancellationToken: cancellationToken);

var transactionOptions = new TransactionOptions(
ReadConcern.Majority,
ReadPreference.Primary,
WriteConcern.WMajority.With(journal: safeModeEnabled),
TimeSpan.FromSeconds(180));

clientSession.StartTransaction(transactionOptions);

return new MongoTransactionSession(clientSession, cancellationToken);
}

public async Task<ISession> StartSessionAsync(
CancellationToken cancellationToken)
{
IClientSessionHandle clientSession = await _mongoClient
.StartSessionAsync(cancellationToken: cancellationToken);

return new MongoSession(clientSession);
}
}
45 changes: 45 additions & 0 deletions src/Session/Internal/MongoTransactionSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;

namespace MongoDB.Extensions.Session;

internal class MongoTransactionSession : ITransactionSession
{
private readonly IClientSessionHandle _session;
private readonly CancellationToken _cancellationToken;
private bool _disposed;

public MongoTransactionSession(
IClientSessionHandle clientSession,
CancellationToken cancellationToken)
{
_session = clientSession;
_cancellationToken = cancellationToken;
}

public async Task CommitAsync()
{
await _session.CommitTransactionAsync(_cancellationToken);
}

protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_session.Dispose();
}

_disposed = true;
}
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
18 changes: 18 additions & 0 deletions src/Session/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using MongoDB.Extensions.Context;

namespace MongoDB.Extensions.Session;

public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMongoSessionProvider<TContext>(
this IServiceCollection services)
where TContext : class, IMongoDbContext
{
services.TryAddSingleton<TContext>();
services.TryAddSingleton<ISessionProvider<TContext>, MongoSessionProvider<TContext>>();

return services;
}
}
5 changes: 5 additions & 0 deletions src/Session/Session.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@

<ItemGroup>
<PackageReference Include="MongoDB.Driver" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Session.Abstractions\Session.Abstractions.csproj" />
</ItemGroup>

</Project>
Loading