TPL - Log data Async

Scenario:

Store log in parallel and async way. 

Solution:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    static void Main(string[] args)
            {
                var q = new BlockingCollection<ILog>();
                Task.Factory.StartNew(
                   () =>
                   {
                       foreach (var log in q.GetConsumingEnumerable())
                       {
                           List<Action<ILog>> handlers;
                           if (_handlers.TryGetValue(log.Type, out handlers))
                           {
                               Task.Factory.StartNew(
                                    () =>
                                    Parallel.ForEach(handlers,
                                                     handler =>
                                                     {
                                                         handler(log);
                                                     }));
                           }
                       }
                   });
    
                Console.ReadLine();
            }

TPL - Task Start

Scenario:

Run multiple Tasks

Solution: 

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
        public class ProgramTask
        {
            static void Main(string[] args)
            {
                Thread.CurrentThread.Name = "Main";
    
                Task taskHi = new Task(() => Console.WriteLine("Task Hi"));
    
                taskHi.Start();
    
                Console.WriteLine($"Task {Thread.CurrentThread.Name}");
    
                taskHi.Wait();
    
                Console.ReadLine();
            }
        }

TPL - Parallel with Partitioner Class

Scenario:

Process data in parallel

Solution:

MSDN: Slower performance is caused by the overhead involved in partitioning the data and the cost of invoking a delegate on each loop iteration. Partitioner.Create enables sequential loop for the delegate body, so that the delegate is invoked only once per partition, instead of once per iteration.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     public class PartitionerClassParallel
        {
            static void Main(string[] args)
            {
                var data = Enumerable.Range(0, 100).ToArray();
                var partitioner = Partitioner.Create(0, data.Length);
                var results = new double[data.Length];
    
                //range is to - from per partition and delegate called once per partition.
                Parallel.ForEach(partitioner, (range, loopState) =>
                {
                    for (int i = range.Item1; i < range.Item2; i++)
                    {
                        results[i] = data[i] * 2;
                    }
                });
    
                foreach (var d in results)
                {
                    Console.Write("{0} ", d);
                }
            }
        }

TPL - Handle exception

Scenario:

Process data in parallel and handle exception for each thread and then send them back to the caller as AggregateException.

Solution:

MSDN: Handle all exception generated by each thread by wrapping all exceptions from the loop in a System.AggregateException.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    public class ParallelAggregateExceptions
        {
            static void Main(string[] args)
            {
                int[] count = Enumerable.Range(0, 50).ToArray();
    
                try
                {
                    ProcessData(count);
                }
                catch (AggregateException ae)
                {
                    var ignoredExceptions = new List<Exception>();
    
                    foreach (var ex in ae.Flatten().InnerExceptions)
                    {
                        if (ex is ArgumentException)
                            Console.WriteLine(ex.Message);
                        else
                            ignoredExceptions.Add(ex);
                    }
    
                    if (ignoredExceptions.Count > 0)
                    {
                        throw new AggregateException(ignoredExceptions);
                    }
                }
    
                Console.ReadLine();
            }
    
            private static void ProcessData(int[] count)
            {
                //store exceptions in thread safe way
                var exceptions = new ConcurrentQueue<Exception>();
    
                Parallel.ForEach(count, c =>
                {
                    try
                    {
                        if (c < 5)
                            throw new ArgumentException($"Value {c}, is less than 5.");
                        else
                            Console.Write(c + " ");
                    }
                    // Store exception and continue
                    catch (Exception e)
                    {
                        exceptions.Enqueue(e);
                    }
                });
    
                //Console.WriteLine();
    
                // Throw the exceptions here after the loop completes.
                if (exceptions.Count > 0)
                {
                    throw new AggregateException(exceptions);
                }
            }
        }

TPL - Parallel with Cancellation token

Scenario:

Process data in parallel and on trigger cancel it in between

Solution:

MSDN: In a parallel loop, you supply the CancellationToken to the method in the ParallelOptions parameter and then enclose the parallel call in a try-catch block.

Create a CancelToken and and register it with a Parallel.ForEach. Create another thread and on trigger using this CancelToken it cancels the foreach processing.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    public class ParallelWithCancellation
        {
            static void Main(string[] args)
            {
                int[] count = Enumerable.Range(0, 1000).ToArray();
    
                CancellationTokenSource cts = new CancellationTokenSource();
    
                ParallelOptions options = new ParallelOptions
                {
                    CancellationToken = cts.Token,
                    MaxDegreeOfParallelism = Environment.ProcessorCount
                };
    
                Console.WriteLine("Press key to start or e to cancel");
                Console.ReadKey();
    
                //Cancel on Trigger the operations which has the Cancel Token
                Task.Factory.StartNew(() =>
                {
                    if (Console.ReadKey().KeyChar == 'e')
                        cts.Cancel();
                    Console.WriteLine("Canceled");
                });
    
                try
                {
                    //Register the Cancel token
                    Parallel.ForEach(count, options, (c) =>
                    {
                        Console.WriteLine("{0} on {1}", c, Thread.CurrentThread.ManagedThreadId);
                        options.CancellationToken.ThrowIfCancellationRequested();
                    });
                }
                catch (OperationCanceledException e)
                {
                    Console.WriteLine(e.Message);
                }
                finally
                {
                    cts.Dispose();
                }
    
                Console.ReadLine();
            }
        }

TPL - Parallel with Thread Local Variable

Scenario:

Process data in parallel and store data for each thread in a local variable and then keep adding it to class local variable in thread safe.

Solution:

Use thread-local variables to store and retrieve state in each separate task that is created by a for loop.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    public class ParallelWithThreadLocalVariable
        {
            static void Main(string[] args)
            {
                var rnd = new Random();
    
                int[] count = Enumerable.Range(0, 1000).ToArray();
                long totalCount = 0;
    
                //() => 0 initializes the thread-local variable to zero.
                //j: loop counter
                //loop: ParallelLoopState
                //subtotal: thread-local variable (returned by lambda expression)
                Parallel.For<long>(0, count.Length, () => 0, (j, loop, subtotal) =>
                {
                    int delay;
                    lock (rnd)
                        delay = rnd.Next(1, 1000);
                    Thread.Sleep(delay);
    
                    if (loop.ShouldExitCurrentIteration)
                    {
                        // if break has been called then any thread processing j > 500 will be called.
                        if (loop.LowestBreakIteration < j)
                            return subtotal;
                    }
    
                    if (j == 100)
                    {
                        Console.WriteLine($"Breaking at {j}");
                        loop.Break();
                    }
    
                    subtotal += count[j];
                    return subtotal;
                },
                //called  after all the iterations on a thread have completed.
                    (x) => Interlocked.Add(ref totalCount, x)
                );
    
                Console.WriteLine($"{totalCount}");
                Console.ReadLine();
            }
        }

TPL - ParallelUtility

Scenario:

Create utility to process data in parallel. Based on IDs, pull Users in parallel and then enqueue response and return back the list.

Solution:

ForEach takes list and Action to process the list and returns ParallelLoopResult. Add the result to ConcurrentQueue in thread safe visit. Then return/output list.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    public class ParallelUtility
        {
            static void Main(string[] args)
            {
                var data = "1,2,3,4";
                var dataArray = data.Split(',');
    
                var dataReponseQueue = new ConcurrentQueue<string>();
    
                ForEach(dataArray, g =>
                {
                    var responses =
                        GetUsers(g.ToString());
    
                    foreach (var response in responses)
                    {
                        dataReponseQueue.Enqueue(response);
                    }
                });
    
                foreach (var item in dataReponseQueue.ToList())
                {
                    Console.WriteLine($"{item}");
                }
                Console.ReadLine();
            }
    
            private static string[] GetUsers(string i)
            {
                if (int.Parse(i) == 1)
                {
                    return new string[] { "Ram", "Shyam" };
                }
                else if (int.Parse(i) == 2)
                {
                    return new string[] { "Seeta", "Geeta" };
                }
                else if (int.Parse(i) == 3)
                {
                    return new string[] { "N/A" };
                }
                else
                {
                    return new string[] { "InValid" };
                }
            }
    
            public static ParallelLoopResult ForEach<TSource>(IEnumerable<TSource> data, Action<TSource> body)
            {
                var result = Parallel.ForEach(data, o =>
                {
                    body(o);
                });
    
                return result;
            }
        }

TPL - Parallelism

Scenario:

Process data parallelly.

Solution:

MSDN: In data parallel operations, the source collection is partitioned so that multiple threads can operate on different segments concurrently.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
        public class DataParallelism
        {
            static void Main(string[] args)
            {
                var data = "1,2,3,4,5,6,7,8,9,10";
                var dataArray = data.Split(',');
    
                Parallel.ForEach(dataArray, item => ProcessData(item));
    
                Console.ReadLine();
            }
    
            private static void ProcessData(string i)
            {
                Console.WriteLine($"{i}");
            }
        }

GIT merge custom branch back to main branch (using Tortoise GIT)

Scenario:

GIT merge custom branch back to main branch

Solution:

  1. Commit or stash any uncommitted changes.
  2. Right click -> Merge -> select main branch you want to merge in your custom branch -> OK.
  3. If no conflict jump to #4 else open the conflict files(s) and merge changes manually (- (orange) are the ones getting deleted, + added and = same) -> Save -> Mark as resolved -> Reload -> should be empty if no more conflicts.
  4. Commit  (if not auto committed).
  5. Push changes.
  6. Right click -> Merge -> select next main branch you want to merge in your custom branch.
  7. Do #5.
  8. Switch checkout main branch, with checking below box:
    1. Override working tree changes
    2. Override branch if exists
  9. Merge custom branch to main branch with squash check box checked (to make all commits into one).
  10. If conflict go #3 else continue.
  11. Push changes.
  12. Show log (changes from parent 1 are main and parent 2 are custom branch)

Task operations

Scenario:

Setup users async way.

Solution:

Create multiple tasks to setup users and based on response add the details to collection and return. Also handle exceptions.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
        class ProgramTaskErrorHandling
        {
            static void Main(string[] args)
            {
                var users = new List<User>() { };
                var items = SetupUsers(users);
            }
    
            private static async Task<List<User>> SetupUsers(List<User> users)
            {
                var tasks = new List<Task<List<User>>>();
    
                foreach (var user in users)
                {
                    tasks.Add(Setup(user));
                }
    
                //ConcurrentBag allows generic data to be stored in unordered from and is a thread-safe allowing multiple threads to use it. 
                var result = new ConcurrentBag<User>();
    
                while (tasks.Count > 0)
                {
                    var task = await Task.WhenAny(tasks).ConfigureAwait(false);
    
                    if (task.IsFaulted)
                    {
                        throw task.Exception == null ? new System.Exception("Task without exception") : task.Exception.Flatten().InnerExceptions[0];
                    }
    
                    if (!task.IsFaulted)
                    {
                        foreach (var item in task.Result)
                        {
                            result.Add(item);
                        }
                    }
    
                    tasks.Remove(task);
                }
    
                return result.ToList();
            }
    
            private static Task<List<User>> Setup(User user)
            {
                throw new System.NotImplementedException();
            }
        }
    
        internal class User
        {
        }
    }

Design Pattern - Structural - Repository

Scenario:

Create repository for data store.

Solution:

Structural Pattern is used to mediate between the domain and data mapping layers like an in memory object collection.

Example: Create repository for data store [DataRepositoryPattern/MockRepositoryPattern].
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    public class DataRepositoryPattern<T> : IRepositoryPattern<T>
        {
            public bool TryRunStoredProcedure<T>(out T result, string name, params Param[] param)
            {
                try
                {
                    result = RunStoredProcedure<T>(name, param).FirstOrDefault();
                    return true;
                }
                catch (System.Exception)
                {
                    result = default(T);
                    return false;
                }
            }
    
            private IEnumerable<T> RunStoredProcedure<T>(string name, Param[] param)
            {
                throw new NotImplementedException();
            }
        }
    
        public class MockRepositoryPattern<T> : IRepositoryPattern<T>
        {
            public bool TryRunStoredProcedure<T>(out T result, string name, params Param[] param)
            {
                try
                {
                    result = RunStoredProcedure<T>(name, param).FirstOrDefault();
                    return true;
                }
                catch (System.Exception)
                {
                    result = default(T);
                    return false;
                }
            }
    
            private IEnumerable<T> RunStoredProcedure<T>(string name, Param[] param)
            {
                throw new NotImplementedException();
            }
        }
    
        interface IRepositoryPattern<T>
        {
            bool TryRunStoredProcedure<T>(out T result, string name, params Param[] param);
        }
    
        public class Param
        {
        }
    
        public class RepositoryPattern
        {
            static void Main(string[] args)
            {
                DataRepositoryPattern<string> pattern = new DataRepositoryPattern<string>();
                if (pattern.TryRunStoredProcedure(out string result, "GetUsersById", new Param[1] { new Param() }))
                {
    
                }
    
                MockRepositoryPattern<string> mockPattern = new MockRepositoryPattern<string>();
                if (mockPattern.TryRunStoredProcedure(out string mockResult, "GetUsersById", new Param[1] { new Param() }))
                {
    
                }
            }
        }

Design Pattern - Behavioral - Strategy

Scenario:

Create a Currency Helper to add the currency symbol based on country

Solution:

Behavioral Pattern is used to select an algorithm at runtime by dynamic parameter for example.

Example: Create a Currency Helper to add the currency symbol based on country
    public interface ICurrencyStrategy
    {
        string ToCurrency(long value);
    }
    
    public static class CurrencyCodes
    {
        public const string USD = "$";
        public const string INR = "₹";
    }
    
    public class USCurrencyStrategy : ICurrencyStrategy
    {
        public string ToCurrency(long value)
        {
            return $"{CurrencyCodes.USD} {value}";
        }
    }
    
    public class IndiaCurrencyStrategy : ICurrencyStrategy
    {
        public string ToCurrency(long value)
        {
            return $"{CurrencyCodes.INR} {value}";
        }
    }
    
    public class Currency
    {
        public long Value { get; set; }
    
        public Currency(long value)
        {
            Value = value;
        }
    
        public string ToCurrency()
        {
            ICurrencyStrategy currencyStrategy = ResolveStrategyByCountry();
            return currencyStrategy.ToCurrency(Value);
        }
    
        private ICurrencyStrategy ResolveStrategyByCountry()
        {
            if (CultureInfo.CurrentCulture.Name == "en-US")
            {
                return new USCurrencyStrategy();
            }
    
            if (CultureInfo.CurrentCulture.Name == "en-IN")
            {
                return new IndiaCurrencyStrategy();
            }
    
            return null;
    }

        public class StrategyPattern
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Enter key U for US or I for India");
    
                var key = Console.ReadKey();
    
                switch (key.Key)
                {
                    case ConsoleKey.U:
                        System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
                        break;
                    case ConsoleKey.I:
                        System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-IN");
                        break;
                }
    
                var price = new Currency(44);
    
                Console.WriteLine($"{price.ToCurrency()}");
            }
        }

Async ConfigureAwait and deadocks

Scenario:

Async ConfigureAwait and deadocks

Solution:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    using System.Net.Http;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
        class ProgramTaskRunDeadlock
        {
            static void Main(string[] args)
            {
                string url = "http://www.google.com";
    
                //Can lead to deadlock as this blocking the main context and so when the control goes back to method CurlUrl it does not get the context
                var result = CurlUrl(url).Result;
            }
    
            public async static Task<string> CurlUrl(string url)
            {
                using (var httpclient = new HttpClient())
                {
                    using (var response = await httpclient.GetAsync("http://www.google.com"))
                    {
                        return await response.Content.ReadAsStringAsync();
                    }
                }
            }
        }
    
        class ProgramTaskRunConfigureawait
        {
            static void Main(string[] args)
            {
                string url = "http://www.google.com";
    
                //as await are now .ConfigureAwait(false), method CurlUrl would not resume on the context, but on thread pool thread
                //So CurlUrl can complete the Task without need of reentering the context. 
                //note: Main method would always require the context
                var result = CurlUrl(url).Result;
            }
    
            public async static Task<string> CurlUrl(string url)
            {
                using (var httpclient = new HttpClient())
                {
                    using (var response = await httpclient.GetAsync("http://www.google.com").ConfigureAwait(false))
                    {
                        return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                    }
                }
            }
        }
    
        class ProgramTaskRunAsyncAllTheWay
        {
            static async Task Main(string[] args)
            {
                string url = "http://www.google.com";
    
                //Now the context is not blocked as all waits are asynchronous.
                var result = await CurlUrl(url);
            }
    
            public async static Task<string> CurlUrl(string url)
            {
                using (var httpclient = new HttpClient())
                {
                    using (var response = await httpclient.GetAsync("http://www.google.com"))
                    {
                        return await response.Content.ReadAsStringAsync();
                    }
                }
            }
        }
    }

Multiple Task.Run() & WaitAll()

Scenario:

From MSDN:

For I/O-bound code, you await an operation that returns a Task or Task<T> inside of an async method.
For CPU-bound code, you await an operation that is started on a background thread with the Task.Run method.

You can use Task.Run to move CPU-bound work to a background thread, but a background thread doesn't help with a process that's just waiting for results to become available.

Solution:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
        protected  void ProcessItems(Item[] item)
        {
            var tasks = item.Select(i =>
                Task.Run(() =>
                {
                    var stopwatch = Stopwatch.StartNew();
                    ProcessItemsAsync(d).Wait();
                    stopwatch.Stop();
                        }));
            Task.WaitAll(tasks.ToArray());
        }

Task.Run()

Scenario:

From MSDN:

For I/O-bound code, you await an operation that returns a Task or Task<T> inside of an async method.
For CPU-bound code, you await an operation that is started on a background thread with the Task.Run method.

You can use Task.Run to move CPU-bound work to a background thread, but a background thread doesn't help with a process that's just waiting for results to become available.

Solution:

     
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    using System;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
        class ProgramTaskRun
        {
            static async Task Main(string[] args)
            {
                while (true)
                {
                    ProcessData();
    
                    string data = Console.ReadLine();
                    Console.WriteLine($"You entered: {data}");
                }
            }
    
            private static async void ProcessData()
            {
                int result = await Task.Run(() => GenerateData());
                Console.WriteLine("Process: " + result);
            }
    
            private static int GenerateData()
            {
                int size = 0;
                for (int i = 0; i < 100; i++)
                {
                    for (int j = 0; j < 1000000; j++)
                    {
                        string value = j.ToString();
                        size += value.Length;
                    }
                }
                return size;
            }
        }
    }

Design Pattern - Behavioral - Chain of Responsibility

Scenario:

Create exclusions for cron scheduler 

Solution:

Behavioral Pattern is used to chain the objects and pass the request along it until an object handles it.

Example: Create exclusions for cron scheduler 
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    private ICalendar Scheduler(string exclusions)
    {
        ICalendar cal = null;
        var list = exclusions.Split(new[] { ListDelim }, StringSplitOptions.RemoveEmptyEntries);
    
        //chain exclusions
        foreach (var item in list)
        {
            cal = new CronCalendar(cal, item); 
        }
        return cal;
    }

LDAP authentiation

Scenario:

LDAP authentiation

Solution:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    using System.DirectoryServices.Protocols;
    using System.Net;
    
    public void AuthenticateUser(string name, string pass)
    {
        using (var ldapCon =
                        new LdapConnection(new LdapDirectoryIdentifier(server, 636)))
        {
            ldapCon.Credential = new NetworkCredential(servUser, servPass);
            ldapCon.AuthType = AuthType.Basic;
    
            var options = ldapCon.SessionOptions;
            options.SecureSocketLayer = true;
            options.ProtocolVersion = 3;
            options.VerifyServerCertificate = (con, cer) => true;
    
            ldapCon.Bind();
    
            var result = (SearchResponse)ldapCon.SendRequest(new SearchRequest(query,
                "samAccountName=" + name, SearchScope.Subtree));
    
            foreach (SearchResultEntry entry in result.Entries)
            {
                ldapCon.Bind(new NetworkCredential(entry.DistinguishedName, pass));
                var userID = entry.Attributes["samaccountname"][0].ToString();
                for (var i = 0; i < entry.Attributes["memberOf"].Count; i++)
                {
                    //permissions
                }
            }
        }
    }

Design Pattern - Behavioral - Command

Scenario:

Create a DB command to run stored procedures

Solution:

Behavioral Pattern is used to encapsulate a command as an object.

Example: Create a DB command to run stored procedures
  1. Create a DataCommand which takes name of SP and parameters for it

  2.  1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
        class DataCommand
        {
            //name = SP name
            public DataCommand(string name)
            {
                Name = name;
                Parameters = new List<DataCommandParameter>();
            }
    
            public class DataCommandParameter
            {
                public DataCommandParameter(string name, object value)
                {
                    Name = name;
                    Value = value;
                }
    
            }
        }

  3. Create a DataCommand with SP and params and execute it against the database

  4.  1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    class Users
        {
            static async Task Main(string[] args)
            {
                var param = new[]
                {
                    new DataCommandParameter {Name = "UserName", Value = "Test User"}
                };
    
                var command = new DataCommand
                {
                    Name = "GetUsersByName",
                    Parameters = param.ToList()
                };
    
                IEnumerable<ExpandoObject> result;
                if (ExecuteQuery(command, out result))
                {
                    ...
                }
            }
        }

Json operations using JSON.NET

Scenario:

Json operations using JSON.NET

Solution:

    using Newtonsoft.Json.Linq;
    using System;
    
    namespace ConsoleApplication1
    {
        class User
        {
            public string ModifiedBy { get; set; }
            public Role[] Roles { get; set; }
    
            public DateTime CreatedDate { get; set; }
        }
    
        class Role
        {
            public string Name { get; set; }
        }
    
        class DynamicJson
        {
            static async Task Main(string[] args)
    
            {
                //CreateDynamicJason();
    
                var data = @"{""CreatedDate"":""2020-07-14T16:03:47.0182203-07:00"",
                              ""ModifiedBy"":""Test User"",
                              ""Roles"": [
                                            {
                                                ""Name"":""Manager""
                                            },
                                            {
                                                ""Name"":""Coordinator""
                                            }
                                         ]
                             }";
                //ReadDynamicJason(data);
    
                ReadDynamicJasonToObject(data);
            }
    
            public static void CreateDynamicJason()
            {
                var jObj = new JObject();
    
                jObj.Add("CreatedDate", DateTime.Now);
    
                dynamic users = jObj;
    
                users.ModifiedBy = "Test User";
    
                users.Roles = new JArray() as dynamic;
    
                dynamic role = new JObject();
                role.Name = "Manager";
                users.Roles.Add(role);
    
                role = new JObject();
                role.Name = "Coordinator";
                users.Roles.Add(role);
    
                Console.WriteLine(users.ToString());
    
                Console.ReadLine();
            }
    
            public static void ReadDynamicJason(string data)
            {
                dynamic json = JValue.Parse(data);
    
                string user = json.ModifiedBy;
                DateTime createdDate = json.CreatedDate;
    
                //JArray jarray = JArray.Parse(json.Roles) as JArray;
                //dynamic roles = jarray;
                string role = string.Empty;
    
                foreach (dynamic r in json.Roles)
                {
                    role = role + r.Name.ToString() + ",";
                }
    
                Console.WriteLine($"{user} - {role} - {createdDate}");
    
                Console.ReadLine();
            }
    
            public static void ReadDynamicJasonToObject(string data)
            {
                dynamic users = JValue.Parse(data);
    
                //JArray users = JArray.Parse(data) as JArray;
    
                var userInfo = users.ToObject<User>();
    
                string user = userInfo.ModifiedBy;
                DateTime createdDate = userInfo.CreatedDate;
    
                //JArray jarray = JArray.Parse(json.Roles) as JArray;
                //dynamic roles = jarray;
                string role = string.Empty;
    
                foreach (dynamic r in userInfo.Roles)
                {
                    role = role + r.Name.ToString() + ",";
                }
    
                Console.WriteLine($"{user} - {role} - {createdDate}");
    
                Console.ReadLine();
            }
        }
    }

Design Pattern - Creational - Builder

Scenario:

Create a custom CheckBox.

Solution:

Creational Pattern to separate the construction from representation, so same process to construct can give us different representation. 

Example: Create a custom checkbox, with additional attributes and enable/disable based on permissions for the user
  1. Take the label of checkbox, attributes and claim (permission) as input and then build the checkbox using builder pattern based on conditions:

  2.  1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    public static MvcHtmlString CheckBox(this HtmlHelper helper, string label, string claim, string httpMethod,
                object htmlAttributes)
    {
                var builder = new TagBuilder("input");
    
                builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
                builder.MergeAttribute("type", HtmlHelper.GetInputTypeString(InputType.CheckBox));
                if (IsAuthorized(claim, httpMethod) &&
                    !htmlAttributes.ToString().Contains("disabled"))
                {
                    builder.Attributes.Add("disabled", "disabled");
                }
    
                builder.InnerHtml = label;
                return MvcHtmlString.Create(builder.ToString(TagRenderMode.Normal));
    }

  3. Below is cshtml caller to render the checkbox using the above helper class

  4. 1
    2
    3
    4
    5
    <tr>
        <td class="">
            @Html.CheckBox("Delete User", "DeleteUser", "POST", new { name = "selectedDeleteUser", value = "1" })
        </td>
    </tr>

Webhooks

Scenario:

Webhooks to post events

Solution:

Webhooks are user defined HTTP callbacks. The messages are triggered by an event and which are automatically sent by application to the client in a form for payload.

  1. Webhook registration
    1. Client would register for a predefined events with the callback url using the unique keys using an API.
    2. Client updates or deletes the webhook setup.
  1. Webhook events
    1. When a application performs an operation then it would generate an event with the predefined payload (json) or an API endpoint to pull the payload [encrypted on server].
    2. Typically you would use a messaging system which guarantees the sequence like Kafka, using it to queue (publish) and (consume) to read the messages.
    3. The message would then be sent to Webhook endpoint with payload for that client (key) and it would then post it to client per their subscriptions of events and setup per #1.
    4. The goal would be to not miss any messages, so on failure we would keep retrying.

 

Pagination

Give after every id, as traditional one is memory intensive:

  • Next -> / search after the above Id
  • Prev-> / search backward, with id going back

Move Github Sub Repository back to main repo

 -- delete .gitmodules git rm --cached MyProject/Core git commit -m 'Remove myproject_core submodule' rm -rf MyProject/Core git remo...