Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions DeepTransaction/BaseContextualTransaction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using DeepTransaction.TransactionScope;

namespace DeepTransaction
{
public class BaseContextualTransaction<TContext> : BaseTransaction, IContextStep<TContext> where TContext : class, IDisposable
{
protected BaseContextualTransaction(string name, TContext context) : base(name)
{
_tran = new ContextualTransaction<TContext>(name, context);
}

public TContext Context { get; set; }
}
}
4 changes: 2 additions & 2 deletions DeepTransaction/BaseTransaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
{
public abstract class BaseTransaction : ITransactionStep
{
private readonly TransactionWorker _tran;
protected TransactionEngine _tran;

/// <summary>
/// Defines the transaction name
/// </summary>
/// <param name="name">Transaction Name</param>
protected BaseTransaction(string name)
{
this._tran = TransactionWorker.Define(name);
this._tran = new TransactionEngine(name);
}

/// <summary>
Expand Down
55 changes: 55 additions & 0 deletions DeepTransaction/ContextualTransaction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using DeepTransaction.DI;
using DeepTransaction.TransactionScope;

namespace DeepTransaction
{
public class ContextualTransaction<TContext> : TransactionEngine where TContext : class, IDisposable
{
private readonly TContext _context;
private readonly bool _isParent;
private readonly ITransactionScope<TContext> _transactionScope;

internal ContextualTransaction(string name, TContext context, bool isParent = false) : base(name)
{
_context = context;
_isParent = isParent;
_transactionScope = (ITransactionScope<TContext>)DeepBootstrapper.GetContext();
}

private void ExecuteIfParent(Action action)
{
if (_isParent) action();
}

public override TransactionContext Process(TransactionContext input)
{
foreach (var transactionStep in _steps)
{
if (transactionStep is IContextStep<TContext> step)
{
step.Context = _context;
}
}

ExecuteIfParent(() => _transactionScope.BeginTran(_context));

TransactionContext outputContext;

try
{
using (_context)
{
outputContext = base.Process(input);
ExecuteIfParent(() => _transactionScope.Commit(_context));
}
}
catch (Exception)
{
_transactionScope.Rollback(_context);
throw;
}
return outputContext;
}
}
}
13 changes: 12 additions & 1 deletion DeepTransaction/DI/DeepBootstrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ public static class DeepBootstrapper
{
private static IDependencyResolver _dependencyResolver;
private static IListener _listener;

private static object _context;

/// <summary>
/// This method will register your dependecy resolver in order to take advantage of IOC
/// </summary>
Expand All @@ -26,6 +27,11 @@ public static void MapListener(IListener listener)
_listener = listener;
}

public static void MapContext(object context)
{
_context = context;
}

internal static IDependencyResolver Get()
{
if (_dependencyResolver == null)
Expand All @@ -40,5 +46,10 @@ internal static IListener GetListener()
{
return _listener;
}

internal static object GetContext()
{
return _context;
}
}
}
7 changes: 5 additions & 2 deletions DeepTransaction/DeepTransaction.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,26 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Transactions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="BaseContextualTransaction.cs" />
<Compile Include="BaseTransaction.cs" />
<Compile Include="ContextualTransaction.cs" />
<Compile Include="DI\DeepBootstrapper.cs" />
<Compile Include="DI\IDependencyResolver.cs" />
<Compile Include="ITransaction.cs" />
<Compile Include="ITransactionStep.cs" />
<Compile Include="Listeners\IListener.cs" />
<Compile Include="Listeners\ListenerModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TransactionEngine.cs" />
<Compile Include="TransactionScope\IContextStep.cs" />
<Compile Include="TransactionScope\ITransactionScope.cs" />
<Compile Include="TransactionWorker.cs" />
<Compile Include="TransactionContext.cs" />
</ItemGroup>
Expand Down
79 changes: 79 additions & 0 deletions DeepTransaction/TransactionEngine.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System.Collections.Generic;
using DeepTransaction.DI;
using DeepTransaction.Listeners;

namespace DeepTransaction
{
public class TransactionEngine
{
private readonly string _name;
protected readonly Queue<ITransactionStep> _steps;
private readonly IDependencyResolver _dependencyResolver;
private IListener _listener;

internal TransactionEngine(string name)
{
_steps = new Queue<ITransactionStep>();
_dependencyResolver = DeepBootstrapper.Get();
_listener = DeepBootstrapper.GetListener();
this._name = name;
}

/// <summary>
/// This method is using for chaning steps for the current transaction
/// </summary>
/// <typeparam name="TStep">The type of the step</typeparam>
/// <returns>A base transaction used for chainging</returns>
public TransactionEngine AddStep<TStep>() where TStep : ITransactionStep
{
var step = _dependencyResolver.Resolve<TStep>();
this._steps.Enqueue(step);

return this;
}

/// <summary>
/// This method is for passing the context and execute the current transaction
/// </summary>
/// <param name="input">Input Context which has to have the type Transaction Context</param>
/// <returns></returns>
public virtual TransactionContext Process(TransactionContext input)
{
var stepName = string.Empty;
dynamic previousOutput = null;
while (_steps.Count > 0)
{
try
{
var step = _steps.Dequeue();
stepName = step.GetType().FullName;

_listener?.Before(new ListenerModel() { Context = input, StepName = stepName, TransactionName = _name });

step.Before(input);
previousOutput = step.Execute(input);

_listener?.After(new ListenerModel() { Context = input, StepName = stepName, TransactionName = _name });
}
catch (System.Exception e)
{
_listener?.OnError(new ListenerModel() { Context = input, StepName = stepName, TransactionName = _name }, e);
throw;
}
}

return previousOutput;
}

/// <summary>
/// Register listener to a specific transaction. If a global listener was already registered this method will overided it for this specific transaction
/// </summary>
/// <param name="listener">IListener instance implementation</param>
/// <returns></returns>
public TransactionEngine WithListener(IListener listener)
{
this._listener = listener;
return this;
}
}
}
9 changes: 9 additions & 0 deletions DeepTransaction/TransactionScope/IContextStep.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;

namespace DeepTransaction.TransactionScope
{
public interface IContextStep<T> where T : IDisposable
{
T Context { get; set; }
}
}
13 changes: 13 additions & 0 deletions DeepTransaction/TransactionScope/ITransactionScope.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace DeepTransaction.TransactionScope
{
public interface ITransactionScope<in TContext> where TContext : IDisposable
{
void BeginTran(TContext context);

void Commit(TContext context);

void Rollback(TContext context);
}
}
77 changes: 5 additions & 72 deletions DeepTransaction/TransactionWorker.cs
Original file line number Diff line number Diff line change
@@ -1,84 +1,17 @@
using System.Collections.Generic;
using DeepTransaction.DI;
using DeepTransaction.Listeners;
using System;

namespace DeepTransaction
{
public class TransactionWorker
{
private readonly string _name;
private readonly Queue<ITransactionStep> _steps;
private readonly IDependencyResolver _dependencyResolver;
private IListener _listener;

public static TransactionWorker Define(string name)
{
return new TransactionWorker(name);
}

private TransactionWorker(string name)
public static TransactionEngine Define(string name)
{
_steps = new Queue<ITransactionStep>();
_dependencyResolver = DeepBootstrapper.Get();
_listener = DeepBootstrapper.GetListener();
this._name = name;
}

/// <summary>
/// This method is using for chaning steps for the current transaction
/// </summary>
/// <typeparam name="TStep">The type of the step</typeparam>
/// <returns>A base transaction used for chainging</returns>
public TransactionWorker AddStep<TStep>() where TStep : ITransactionStep
{
var step = _dependencyResolver.Resolve<TStep>();
this._steps.Enqueue(step);

return this;
}

/// <summary>
/// This method is for passing the context and execute the current transaction
/// </summary>
/// <param name="input">Input Context which has to have the type Transaction Context</param>
/// <returns></returns>
public TransactionContext Process(TransactionContext input)
{
var stepName = string.Empty;
dynamic previousOutput = null;
while (_steps.Count > 0)
{
try
{
var step = _steps.Dequeue();
stepName = step.GetType().FullName;

_listener?.Before(new ListenerModel() { Context = input, StepName = stepName, TransactionName = _name });

step.Before(input);
previousOutput = step.Execute(input);

_listener?.After(new ListenerModel() { Context = input, StepName = stepName, TransactionName = _name });
}
catch (System.Exception e)
{
_listener?.OnError(new ListenerModel() { Context = input, StepName = stepName, TransactionName = _name }, e);
throw;
}
}

return previousOutput;
return new TransactionEngine(name);
}

/// <summary>
/// Register listener to a specific transaction. If a global listener was already registered this method will overided it for this specific transaction
/// </summary>
/// <param name="listener">IListener instance implementation</param>
/// <returns></returns>
public TransactionWorker WithListener(IListener listener)
public static ContextualTransaction<TContext> Define<TContext>(string name, TContext context) where TContext : class, IDisposable
{
this._listener = listener;
return this;
return new ContextualTransaction<TContext>(name, context, true);
}
}
}
Loading