/// <summary> /// Select an applicable function without executing it /// </summary> /// <typeparam name="T">Generic type</typeparam> /// <param name="context">gate context</param> /// <param name="mode">mode to run the gated code in</param> /// <param name="conditionalPredicate">The conditional predicate.</param> /// <param name="functions">array of gated functions</param> /// <param name="keepContext">controls whether async operation should keep the synchronization context</param> /// <remarks> /// keep context should be set to true in code which is async end to end, /// and false in other cases to avoid deadlocking /// </remarks> /// <returns>a function to perform, never null</returns> public static Func <Task <T> > SelectFunction <T>(this IGateContext context, GatedCode.Modes mode, Func <bool> conditionalPredicate, GatedAsyncFunc <T>[] functions, bool keepContext) { Tuple <GatedAsyncFunc <T>, IGate[]> action = SelectCode(context, conditionalPredicate, functions); if (action?.Item1 == null) { return(() => Task.FromResult(default(T))); } return(async() => { context.EnterScopes(mode, action.Item2); try { if (action.Item1.Func != null) { return await action.Item1.Func().ConfigureAwait(keepContext); } } finally { context.ExitScopes(mode, action.Item2); } return default(T); }); }
/// <summary> /// Select an applicable function without executing it /// </summary> /// <param name="context">gate context</param> /// <param name="mode">mode to run the gated code in</param> /// <param name="functions">array of gated functions</param> /// <returns>a function to perform, never null</returns> public static Func <T, T> SelectFunction <T>(this IGateContext context, GatedCode.Modes mode, params GatedFunc <T, T>[] functions) { Tuple <GatedFunc <T, T>, IGate[]> action = SelectCode(context, null, functions); if (action != null && action.Item1 != null) { return(new Func <T, T>( (t) => { context.EnterScopes(mode, action.Item2); try { if (action.Item1.Func != null) { return action.Item1.Func(t); } } finally { context.ExitScopes(mode, action.Item2); } return t; })); } return(new Func <T, T>((t) => t)); }
/// <summary> /// Select an applicable action without executing it /// </summary> /// <param name="context">gate context</param> /// <param name="mode">mode to run the gated code in</param> /// <param name="conditionalPredicate">The conditional predicate.</param> /// <param name="actions">array of gated actions</param> /// <param name="keepContext">controls whether async operation should keep the synchronization context</param> /// <remarks> /// keep context should be set to true in code which is async end to end, /// and false in other cases to avoid deadlocking /// </remarks> /// <returns>an action to perform, never null</returns> public static Func <Task> SelectAction(this IGateContext context, GatedCode.Modes mode, Func <bool> conditionalPredicate, GatedAsyncAction[] actions, bool keepContext = false) { Tuple <GatedAsyncAction, IGate[]> action = SelectCode(context, conditionalPredicate, actions); if (action?.Item1 == null) { return(s_noOpAction); } return(async() => { context.EnterScopes(mode, action.Item2); try { if (action.Item1?.Action != null) { await action.Item1.Action().ConfigureAwait(keepContext); } } finally { context.ExitScopes(mode, action.Item2); } }); }
/// <summary> /// Select an applicable function without executing it /// </summary> /// <typeparam name="T">Generic type</typeparam> /// <param name="context">gate context</param> /// <param name="mode">mode to run the gated code in</param> /// <param name="conditionalPredicate">The conditional predicate.</param> /// <param name="functions">array of gated functions</param> /// <returns>a function to perform, never null</returns> public static Func <T> SelectFunction <T>(this IGateContext context, GatedCode.Modes mode, Func <bool> conditionalPredicate, params GatedFunc <T>[] functions) { Tuple <GatedFunc <T>, IGate[]> action = SelectCode(context, conditionalPredicate, functions); if (action != null && action.Item1 != null) { return(new Func <T>( () => { context.EnterScopes(mode, action.Item2); try { if (action.Item1.Func != null) { return action.Item1.Func(); } } finally { context.ExitScopes(mode, action.Item2); } return default(T); })); } return(new Func <T>(() => default(T))); }
/// <summary> /// Exit a scope for gated code /// </summary> /// <param name="context">the gate context</param> /// <param name="mode">mode that code should be performed (e.g. scoped or not)</param> /// <param name="gate">the gate to exit scope for</param> public static void ExitScope(this IGateContext context, GatedCode.Modes mode, IGate gate) { if (context.ShouldBeScoped((mode & GatedCode.Modes.ExitScope), gate)) { context.ExitScope(gate); } }
/// <summary> /// Should the context scope the code /// </summary> /// <param name="context">gate context</param> /// <param name="mode">preferred mode for code</param> /// <param name="gate">gate to run</param> /// <returns>true if the context should scope the code, false otherwise</returns> private static bool ShouldBeScoped(this IGateContext context, GatedCode.Modes mode, IGate gate) { if (gate == null) { return(false); } if (context == null) { return(false); } if ((mode & GatedCode.Modes.EnterScope) == GatedCode.Modes.EnterScope || (mode & GatedCode.Modes.ExitScope) == GatedCode.Modes.ExitScope) { return(true); } if (context.Request != null && context.Request.RequestedGateIds != null && context.Request.RequestedGateIds.Contains(gate.Name)) { return(true); } return(false); }
/// <summary> /// Perform each function that is applicable in the current gate context. The input parameter /// is passed to the first applicable function, and the result of that function is used as the input /// for the next applicable function, etc. This allows for chaining multiple functions, each having /// an opportunity to modify the input. /// </summary> /// <param name="context">gate context</param> /// <param name="input">the input object</param> /// <param name="mode">mode to run the gated code in</param> /// <param name="functions">array of gated functions</param> /// <typeparam name="T">the return type of the function</typeparam> /// <returns>instance of T (default if no applicable action found)</returns> public static T PerformEachFunction <T>(this IGateContext context, GatedCode.Modes mode, T input, params GatedFunc <T, T>[] functions) { Array.ForEach(functions, (function) => { input = SelectFunction(context, mode, function)(input); } ); return(input); }
/// <summary> /// Exits a collection of scopes in a reverse order. /// </summary> /// <param name="context">The gate context.</param> /// <param name="mode">The mode that code should be performed.</param> /// <param name="gates">The array of gates for exiting the scope.</param> public static void ExitScopes(this IGateContext context, GatedCode.Modes mode, IGate[] gates) { if (gates == null) { return; } for (int i = gates.Length - 1; i >= 0; i--) { ExitScope(context, mode, gates[i]); } }
/// <summary> /// Enters a collection of scopes in a nested way. /// </summary> /// <param name="context">The gate context.</param> /// <param name="mode">The mode that code should be performed.</param> /// <param name="gates">The array of gates for the scope.</param> public static void EnterScopes(this IGateContext context, GatedCode.Modes mode, IGate[] gates) { if (gates == null) { return; } foreach (IGate gate in gates) { EnterScope(context, mode, gate); } }
/// <summary> /// Select an applicable action without executing it /// </summary> /// <param name="context">gate context</param> /// <param name="mode">mode to run the gated code in</param> /// <param name="conditionalPredicate">The conditional predicate.</param> /// <param name="actions">array of gated actions</param> /// <returns>an action to perform, never null</returns> public static Action SelectAction(this IGateContext context, GatedCode.Modes mode, Func <bool> conditionalPredicate, params GatedAction[] actions) { Tuple <GatedAction, IGate[]> action = SelectCode(context, conditionalPredicate, actions); if (action != null && action.Item1 != null) { return(new Action( () => { context.EnterScopes(mode, action.Item2); try { action.Item1.Action?.Invoke(); } finally { context.ExitScopes(mode, action.Item2); } })); } return(new Action(() => { })); }
/// <summary> /// Perform an action that is applicable in the current gate context /// </summary> /// <param name="context">gate context</param> /// <param name="mode">mode to run the gated code in</param> /// <param name="actions">array of gated actions</param> public static Task PerformAction(this IGateContext context, GatedCode.Modes mode, params GatedAsyncAction[] actions) => SelectAction(context, mode, null, actions)();
/// <summary> /// Select an applicable function without executing it /// </summary> /// <param name="context">gate context</param> /// <param name="mode">mode to run the gated code in</param> /// <param name="functions">array of gated functions</param> /// <param name="keepContext">controls whether async operation should keep the synchronization context</param> /// <remarks> /// keep context should be set to true in code which is async end to end, /// and false in other cases to avoid deadlocking /// </remarks> /// <returns>a function to perform, never null</returns> public static Func <T, Task <T> > SelectFunction <T>(this IGateContext context, GatedCode.Modes mode, GatedAsyncFunc <T, T>[] functions, bool keepContext) { Tuple <GatedAsyncFunc <T, T>, IGate[]> action = SelectCode(context, null, functions); if (action != null && action.Item1 != null) { return(async t => { context.EnterScopes(mode, action.Item2); try { if (action.Item1.Func != null) { return await action.Item1.Func(t).ConfigureAwait(keepContext); } } finally { context.ExitScopes(mode, action.Item2); } return t; }); } return(Task.FromResult); }
/// <summary> /// Select an applicable function without executing it /// </summary> /// <param name="context">gate context</param> /// <param name="mode">mode to run the gated code in</param> /// <param name="functions">array of gated functions</param> /// <returns>a function to perform, never null</returns> public static Func <T, Task <T> > SelectFunction <T>(this IGateContext context, GatedCode.Modes mode, params GatedAsyncFunc <T, T>[] functions) { return(SelectFunction(context, mode, functions, false)); }
/// <summary> /// Perform each action that is applicable in the current gate context /// </summary> /// <param name="context">gate context</param> /// <param name="mode">mode to run the gated code in</param> /// <param name="actions">array of gated actions</param> public static void PerformEachAction(this IGateContext context, GatedCode.Modes mode, params GatedAction[] actions) { Array.ForEach(actions, (action) => PerformAction(context, mode, action)); }
/// <summary> /// Select an applicable action without executing it /// </summary> /// <param name="context">gate context</param> /// <param name="mode">mode to run the gated code in</param> /// <param name="conditionalPredicate">The conditional predicate.</param> /// <param name="actions">array of gated actions</param> /// <returns>an action to perform, never null</returns> public static Func <Task> SelectAction(this IGateContext context, GatedCode.Modes mode, Func <bool> conditionalPredicate, params GatedAsyncAction[] actions) { return(SelectAction(context, mode, conditionalPredicate, actions, false)); }
/// <summary> /// Select an applicable function without executing it /// </summary> /// <typeparam name="T">Generic type</typeparam> /// <param name="context">gate context</param> /// <param name="mode">mode to run the gated code in</param> /// <param name="conditionalPredicate">The conditional predicate.</param> /// <param name="functions">array of gated functions</param> /// <returns>a function to perform, never null</returns> public static Func <Task <T> > SelectFunction <T>(this IGateContext context, GatedCode.Modes mode, Func <bool> conditionalPredicate, params GatedAsyncFunc <T>[] functions) { return(SelectFunction(context, mode, conditionalPredicate, functions, false)); }
/// <summary> /// Perform a function that is applicable in the current gate context /// </summary> /// <param name="context">gate context</param> /// <param name="mode">mode to run the gated code in</param> /// <param name="functions">array of gated functions</param> /// <typeparam name="T">the return type of the function</typeparam> /// <returns>instance of T (default if no applicable action found)</returns> public static Task <T> PerformFunction <T>(this IGateContext context, GatedCode.Modes mode, params GatedAsyncFunc <T>[] functions) => SelectFunction(context, mode, null, functions)();