TransactionScope: A simple way to handle transactions in .NET

Have you ever tried implementing transactions using C# code? Normally, we implement transactions in SQL where multiple Insert/Update statements takes part in it. A Transaction follows the ACID (Atomicity, Consistency, Isolation, Durability) rule where either all the statements get committed or all get canceled and rolled back. TransactionScope allows us to implement it at application level. There could be some scenarios where you are required to do different operations in the same database or even multiple databases (distributed transaction) or due to some other constraints, it cannot be done at database level. It is also very helpful for application developers if they have less exposure to database.

What is TransactionScope

TransactionScope got introduced with .NET 2.0 as part of  System.Transaction. It is a class which provides a simple way to make a set of operations as part of a transaction without worrying about the complexity behind the scene. If any of the operation fails in between, entire transaction would fail and rolled back  which undo all the operation that got completed. All this would be taken care by the framework, ensuring the data consistency.

How to use the TransactionScope?

To use this, you need to add the reference of System.Transactions reference which is part of framework libraries (normally it wont be added by default). Once it get added, add the namespace System.Transactions wherever we want to use this. The syntax would look as

try
{
    using (TransactionScope scope = new TransactionScope())
    {
        // Do Operation 1
        // Do Operation 2
        //...

        // if all the coperations complete successfully, this would be called and commit the trabsaction. 
        // In case of an exception, it wont be called and transaction is rolled back
        scope.Complete();
    }
}
catch (ThreadAbortException ex)
{
    // Handle exception
}

Here we can see that we have used Disposable block while creating instance of TransactionScope, it makes sure the dispose gets called when it gets out of the block and ends the transaction scope.

In one Transaction scope, we can do multiple operation connecting to different databases as

using (TransactionScope scope = new TransactionScope())
{
    using (con = new SqlConnection(conString1))
    {
        con.Open();

        // Do Operation 1
        // Do Operation 2
        //...
    }

    using (con = new SqlConnection(conString2))
    {
        con.Open();

        // Do Operation 1
        // Do Operation 2
        //...

    }

    scope.Complete();
}

Here we are using two connection strings to connection different databases. We can use as many based on our requirement. We can have nested transactions as well. It could be as

public void DoMultipleTransaction()
{       
    try
    {
        using (TransactionScope scope = new TransactionScope())
        {
            using (con = new SqlConnection(conString1))
            {
                con.Open();
                // Do Operation 1
            }

            OtherTransaction();
            scope.Complete();
        }
    }
    catch (ThreadAbortException ex)
    {
        // Handle exception
    }
}

private void OtherTransaction()
{
    using (TransactionScope scope = new TransactionScope())
    {
        using (con = new SqlConnection(conString2))
        {
            con.Open();
            // Do Operations
        }
        scope.Complete();
    }
}

Here the outermost transaction is called as rootscope and here even if the inner transaction (OtherTransaction above) gets completed by calling scope.Complete(), if the rootscope complete could not be called due to various reasons, then the complete transaction would be rolled back including inner transactions.

Note: You might get one of the following exception while executing distributed trsanctions

  1. MSDTC on server is unavailable
  2. Network access for Distributed Transaction Manager (MSDTC) has been disabled.

 

Both the error are due to the same reason, first one occurs when you have the database and the application the same server while 2 if on the other server. For same server, go to run-> cmd-> services.msc. Run the service named Distributed Transaction Coordinator and make the startup type automatic so that it gets started again in case of system restart. For 2, follow the link to cofigure MSDTC.

TransactionScope provides various TransactionScopeOptions which defines transactions behavior for the scope. Lets see an example

using (TransactionScope scope = new TransactionScope())
{
    // Do Operation
    using (TransactionScope scope1 = new TransactionScope(TransactionScopeOption.Required))
    {
        // Do Operation
        scope1.Complete();
    }
    using (TransactionScope scope2 = new TransactionScope(TransactionScopeOption.RequiresNew))
    {
        // Do Operation
        scope2.Complete();
    }
    using (TransactionScope scope3 = new TransactionScope(TransactionScopeOption.Suppress))
    {
        // Do Operation
        scope3.Complete();
    }

    scope.Complete();
}

Here we created three transactions under the parent transaction with different TransactionScopeOptions. By default the scope is required, which applies to parent transaction here. It is a rootscope which creates a new transaction, and mark it as an ambient transaction. scope1 is also created with required and as we have already an ambient transaction (scope) so it joins the parent transaction. scope2 got created with option as RequiresNew which means it is a new transaction which is independently works with ambient transaction. scope3 got created with suppress option, which means it doesn’t take part in any ambient transactions. It gets executed regardless whether ambient transaction executes successfully or not. All the ambient transactions gets committed once the parent (global) scope completes.

Hope you enjoyed this post and will be using transaction in your future requirements.

Cheers,
Brij

What are Immutable types?

In C#, primarly we have two types of objects: reference type and value type. Value type objects always have default value and created on stack. When we assign value type variable to another variable, a new copy gets created. While reference type objects default to null and created on heap. Multiple variables can point to the same object, it means changing the value using one, will reflect accross variables. There is one more type called Nullable type which is similar to value type with additional capability to have no value if it is unassigned. You can learn more about from one of my previous posts here

A reference type can be categorized in two types : Mutable and Immutable. The plain english meaning is “Can Change” and “Cannot Change” respectively and which is same here as well.

It means an Immutable type object cannot be changed after it’s creation/initialization and if one tries to change, a new copy gets created (if allowed) and returned. In other words, it is a reference type but having value type semantics. String is one of the most used immutable types and it is provided by the .NET framework.

Normal class that we create, are mutable type. Let’s see an example

    class Program
    {
        static void Main(string[] args)
        {
            Person objPerson = new Person() { Name = "Brij", Age =32 };
            UpdatePerson(objPerson);
            Console.WriteLine(objPerson.Name);
            Console.ReadKey();
        }

        static void UpdatePerson(Person P)
        {
            P.Name += " Mishra";
        }
    }

    public class Person
    {
        public string Name { get; set; }

        public int Age { get; set; }
    }

So in this example the output will be Brij Mishra as the same object got changed. This class can also be modified as where we just provide the getter and the values then can be modified either at constructor or any other method inside the same class.

public class Person
{
    private string _name;
    public string Name { get { return _name; } }

    private int _age;
    public int Age { get { return _age; } }

    public Person(string name, int age)
    {
        this._name = name;
        this._age = age;
    }
}

Now to make it an immutable object, we have two options:

  1. Use Const
  2. Use Readonly

So I can make the class as

   public class Person
    {
        private readonly string _name;
        public string Name { get { return _name; } }

        private readonly int _age;
        public int Age { get { return _age; }  }

        public Person(string name, int age)
        {
            this._name = name;
            this._age = age;
        }
    }

Now once we create an instance of this class, it cannot be updated as all the properties are readonly. Even, we cannot update in another new method in the same class as in the previous example. We can use the Const instead of readonly but in that case, we will loose the ability to assign the value while object creation, instead we will have to provide the value at class definition. One more drawback, as const variable initialized at Class level itself, also called compile time constant so it would be same for all the instances of that type.

Now lets create another class address and have a List of Addresses in the class as

 public class Person
    {
        private List
<Address> _addresses;
        private readonly string _name;
        public string Name { get { return _name; } }

        private readonly int _age;
        public int Age { get { return _age; }  }

        public Person(string name, int age, List
<Address> addresses)
        {
            this._name = name;
            this._age = age;
            _addresses = addresses;
        }
        public List
<Address> Addresses { get { return _addresses; } }
    }

    public class Address
    {
        public string Address1 { get; set; }

        public string Address2 { get; set; }

        public string City { get; set; }

        public string State { get; set; }

        public string Zip { get; set; }
    }

As here the list of address has only get property exposed, it means we cannot replace the whole collection but certainly we can update the items from the list by adding and/or removing an item as

Person objPerson = new Person("Brij", 32, addresses);
objPerson.Addresses.Add(new Address());

Now, to make the Person class Immuatble, we need to change it as readonly collection as

public class Person
{
    private List
<Address> _addresses;
    private readonly string _name;
    public string Name { get { return _name; } }

    private readonly int _age;
    public int Age { get { return _age; }  }

    public Person(string name, int age, List
<Address> addresses)
    {
        this._name = name;
        this._age = age;
        _addresses = addresses;
    }

    public ReadOnlyCollection
<Address> Addresses { get { return _addresses.AsReadOnly(); } }
}

Now we wont be able to add or remove items from list. Still we have here one gap and using we can update any existing address object as Address is not a immutable type.

To make it immutable we will require to make all the properties readonly or const.

So to make an object immuatble, all the internal type used, should also be immutable and all the collection should be readonly.

C# 6 added a feature that says if we have a auto property with only a getter then it can be only initialized in constructor. Behaind the scene, it uses private readonly property as

public class Person
{
    public string Name { get; }

    public int Age { get; }
}

Here if we try to update the properties other than the constructor, it will throw an error stating that it is readonly.

Hope you all have enjoyed the post.

Cheers
Brij

.NET Datetime vs SQL Datetime : Comparison, Issues and Workarounds

Hello All,

Recently, in an application where we were saving the .NET DateTime value in SQL database, we had to compare this DateTime later in the .NET application. We realized that even the same DateTime stamp was not equating once it got fetched from database. I got Once we investigated further we found that the time stamp that we were sending to save in database, was not saving with the complete value and there were some more issues. It looks common requirement where you saving a value in database and later comparing it to add some business logic.  So I am sharing here my findings.

# 1

SQL DateTime type only stores time till milliseconds (3 digits) while in .NET it is stored till ticks. One millisecond is equivalent to 10,000 ticks. It means if you construct the .NET DateTime object from the DateTime of database, then it will never match because it will have all zero after the milliseconds. Lets see an example.
Here I am showing the same .NET DateTime value at application, in database table and again .NET DateTime read from the DB.

.NET DateTime

{6/19/2017 9:24:14 PM}
      Date: {6/19/2017 12:00:00 AM}
      Day: 19
      DayOfWeek: Monday
      DayOfYear: 170
      Hour: 21
      Kind: Local
      Millisecond: 777
      Minute: 24
      Month: 6
      Second: 14
      Ticks: 636335042547778146
      TimeOfDay: {21:24:14.7778146}
      Year: 2017

Let’s see how it is saved in database.

SQL DateTime

In database table it looks like as


When we fetch from database and convert it into it returns the following object
{6/19/2017 9:24:14 PM}
      Date: {6/19/2017 12:00:00 AM}
      Day: 19
      DayOfWeek: Monday
      DayOfYear: 170
      Hour: 21
      Kind: Unspecified
      Millisecond: 777
      Minute: 24
      Month: 6
      Second: 14
      Ticks: 636335042547770000
      TimeOfDay: {21:24:14.7770000}
      Year: 2017

Here we see the TimeOfDay component in both the object then we find that while in first object we have 7778146 while in second 7770000, it means last 4 digits are chopped off and reset to 0.
So is it safe if we compare till milliseconds only (say by using ToString(“MM/dd/yyyy hh:mm:ss.fff”))?
NO
There are some more mystery to it. Let’s see in second point

# 2

Here, I saved a new record in the database and the .net DateTime as
{6/19/2017 11:49:55 PM}
      Date: {6/19/2017 12:00:00 AM}
      Day: 19
      DayOfWeek: Monday
      DayOfYear: 170
      Hour: 23
      Kind: Local
      Millisecond: 731
      Minute: 49
      Month: 6
      Second: 55
      Ticks: 636335129957315136
      TimeOfDay: {23:49:55.7315136}
      Year: 2017

and when we see the record in the table, we see

Oh.. here we see the 730 millisecond while in .NET object it was 731. Let’s fetch the same and check the .net object as

{6/19/2017 11:49:55 PM}
      Date: {6/19/2017 12:00:00 AM}
      Day: 19
      DayOfWeek: Monday
      DayOfYear: 170
      Hour: 23
      Kind: Unspecified
      Millisecond: 730
      Minute: 49
      Month: 6
      Second: 55
      Ticks: 636335129957300000
      TimeOfDay: {23:49:55.7300000}
      Year: 2017

Here again we see 730 millisecond. It means we are losing one millisecond. It also suggests that comparing the two values till milliseconds would also not work. But why this is happening. Let’s dig it more.

Actually SQL DateTime stores till 1/3 millisecond approximately so the last digit of millisecond would always be

**0
**3
**7
**0

and SQL rounds of the milliseconds passed to it so if you pass
001 turns to 000
002 turns to 003
004 turns to 004
005 turns to 007

009 turns to 010

So can we just chop off milliseconds and compare the DateTime?
NO

It may work most of the time. But there are few chances to fail. Say we have a time as 09.00.00.999 then it will turn to 09.00.01.000 so here second got increased by 1. Even minute/hour can be changed if similar situation occur. So here we just have the option to round off the time based on the above logic and then compare.

Do we have any other option?
Yes

DateTime2

To overcome this, there is a new SQL data type datetime2 was introduced in SQL server 2008 which got the ability to save the millisecond till 7th precision. It is like an extension of DateTime which saves the time more accurately. Lets have a look on that

So we see here that the time is saved as 2017-06-19 23:49:55.7353342 while the same was saved in DateTime (type) as 2017-06-19 23:49:55.737 (rounded off). If we now fetch the same and assign the .NET DateTime object we get the exact date time and equality works as expected.

Note – There is one more significant update in datetime2. In DateTime if we want to same a default minimum DateTime then it was 1753 but in DateTime it could be 0001.

Conclusion

In this post, we discussed the behavior of SQL DateTime object, its issues and possible workarounds. Then we saw that the how the issues got resolved in datetime2 which was introduced in SQL server 2008. Obviously, it takes more space in database as it saves the time more granular level. I have rarely seen that DateTime values are stored in datetime2 format, mostly in DateTime at least in legacy application. And many of us don’t know the exact difference or may face the issues that we discussed. If we are working on some legacy application then we may not able to change the SQL data type, in that scenario, putting the round off logic could work.

Hope you have enjoyed the post. Do share your valuable feedback.

Happy Coding,
Brij

Singleton vs Static class : Key Differences and Usages

The debate about Singleton vs Static is quite old and it is still continuing and there are lots of confusion around this as well. In this post, I am trying to explain these two concepts, key differences and its usages.In this post I will not focus on the basics of Static and Singleton and how to write that. If you are new to these keywords, I will advise you to learn about these first to get more benefited.

So first we are going to understand the characteristics of each . Lets start with static class

Static Class :

  1. Static classes cannot be instantiated so it restricts us in many ways like it cannot implement Interfaces, inherit any class etc.
  2. Any other scenarios where this keyword is required, it cannot be used like indexer etc. Also it cannot be used as method parameter, local variable etc for the same reason.
  3. Static classes can have only static members – constructor, fields, methods, properties, events.
  4. One cannot control when static constructors are called. It’s always earlier than first access of the class. So no parameters can be passed as well.

Internally when compiler compiles static class, it marks it as a abstract and sealed. So that no instance can be created and cannot be extended as well. Now let’s talk about Singleton

Singleton Class :

  1. As name suggests it allows to have only one instance of a class.
  2. The constructor of this class are marked as private so that accidentally one cannot create multiple instances and provides a static function/property which first create one instance and returns the same each time.
  3. As singleton is a normal class, it allows us to leverage all that features of object oriented programming concepts.

Memory Management :

There is much confusion around memory management of static class and Singleton class. In simple words, any class whether it is itself static or any member if marked as static then it would not be collected by Garbage Collector.

Static variables/classes are not stored in normal Heap and there is a separate space in memory to store static resources which holds the static classes and variables.This space is beyond the scope of GC and memory get release only when corresponding process/AppDomain unloads.

Because singleton holds a static reference which cannot be collected by GC so the instance cannot be collected and both (Static and Singleton) gets destroyed with the AppDomain/Process.

Some Key common characteristics :

  • As both of the static and singleton instances are have just one copy in memory throughout the whole application, both used for holding global state in an application.
  • Both are initialized lazily, it means for static classes it is initialized only when accessed first time and for Singleton, it gets created only when it is accessed first time.

The Differences

  1. Very first difference is that Static is a language feature and Singleton is a architectural pattern so both belongs to difference arena altogether.
  2. Now a days everybody is behind using Dependency Injection and Static does not fit there because it is interface driven.
  3. Unit Testing is another topic where you can find some way to create a mock for singleton instances but testing static is a nightmare.
  4. Being singleton is a just another class, it enable you to use Object oriented concepts.

Singleton approach is much more flexible as we can see that from the differences itself. We can use interface with it and implement it in a class and use in our application. If some requirement changes and later we require to change the logic then we can just remove the older implementation and replace with new one without hiccups as long as the interface is same.. Also testing is another key benefit.

Static classes is mainly recommended for having grouping of a bunch of utility methods that can be called independently but again testing could be a problem and benefits of OOP is gone. So most of the time static should be avoided.

Having said that using global variable (like static class or singleton) makes a strong coupling between the global data and all the places where it is used.

Cheers,
Brij

 

Object vs ref Object : Passing a reference type using ref keyword

In this post, I am going to talk about ref keyword in C#. You all must be knowing the basic use of this keyword. But for them who are new to this keyword or C#, will explain the basics.

ref keyword is used to pass the parameter by reference. It means the parameter references the same memory location as the original variable.

As we know that there are two type of variable in C#. One is Value type and other is Reference type. Whenever a value type variable is passed to a method, a copy that variable is created and passed to the method. So let’s see it pictorially

Passed by valueSo when the variable is updated in the called method, then initial variable is not updated but the copy variable gets updated.

Now let’s pass the parameter using ref keyword. So when we pass a value type variable using ref keyword the reference of the variable is passed and both variable names points to same memory location. So when the variable is updated it is available in both method. It can be depicted pictorially as

Pass value using refTill now we passed the value type variable. But when we send other type (reference type) variable to the method the reference is passed so when we update the object in the called method, the updated object gets available to both the method. let’s see the example

For this example,I used an instance of Class type

Typeand the example is

refLet’s come to the real question. What if we pass the instance using ref keyword. When the instance is itself a reference type then what else we get from it. Or they exactly same? Let’s see by example

refref1But if we see the above example, then we get the difference that now variable name points the reference of the reference variable name. When we update the object it updates the same memory location as earlier. By seeing the above example, it seems that there is no difference between passing the reference type variable normally and by ref keyword. But Wait !! Let’s see the screenshot

refref12Now when the UpdateName method get’s executed then what will happen. Let’s see this

refref2

So here after execution of UpdateName both variable name and myName points to null and now the object is available in memory but not accessible from any variable.

But if we pass the object without ref keyword in same method then

ref2So here variable name points to null but myName still points to that object and object is accessible.

So it means as long as we update the object by updating it’s property method etc.,it is same in both case but when we play with the variable name then it makes a difference as we have seen in the above example.

So next time when someone asks that difference by passing the a reference using ref keyword or without ref keyword then you can explain it.

Happy learning!!

Regards,
Brij

Concurrency vs Multi-threading vs Asynchronous Programming : Explained

Recently, I was speaking in an event and I asked a question about Asynchronous programming to the audience, I found that many were confused between multi-threading and asynchronous programming and for few, it was same. So, I thought of explaining these terms including an additional term Concurrency. Here, there are two completely different concepts involved, First – Synchronous and Asynchronous programming model and second – Single threaded and multi-threaded environments. Each programming model (Synchronous and Asynchronous) can run in single threaded and multi-threaded environment. Let’s discuss each in detail.

Synchronous Programming model – In this programming model, A thread is assigned to one task and starts working on it. Once the task completes then it is available for the next task. In this model, it cannot leave the executing task in mid to take up another task. Let’s discuss how this model works in single and multi-threaded environments.

Single Threaded – If we have couple of tasks to be worked on and the current system provides just a single thread, then tasks are assigned to the thread one by one. It can be pictorially depicted as

singlethreadedHere we can see that we have a thread (Thread 1 ) and four tasks to be completed. Thread starts workingon the tasks one by one and completes all. (The order in which tasks will be taken up, does not affect the execution, we can have different algorithm which can define the priorities of tasks)

Continue reading

How to Override Finalize method in C#

Being a .NET Developer, you must have basic information about Garbage Collector. Garbage Collector is a boon for .Net developers which takes care of memory management for .NET programs in the background.

But as we know that there are some limitations as well. Garbage collector can collect only managed object. So what about unmanaged objects. Garbage collector cannot clean up unmanaged object properly because these object are not limited to .NET framework and CLR does not have complete control on it. So it is developer’s responsibility to clean up unmanaged resources. It is advised to override the Finalize method (that is a virtual method in Object class) to clean up the unmanaged resources. Garbage collector calls the finalize method of each object (which has overridden Finalize method) while collection process.

So have you ever tried to override the Finalize method in C#? Let’s do that

 public class MyClass
    {
        protected override void Finalize()
        {
            // Do unmanaged resource clean up
        }
    }

For simplicity, I just override the Finalize method. Now let’s build the code.
Ohh.. The above code does not build. It gives the following errorErrorSo if you see the error, it says that do not override Finalize. Instead use destructor.

It means We cannot override Finalize directly in C#.

So what is other way? As in error it suggests to provide destructor. So let us write the destructor (destructor in any class starts with tilde (~)). So now my class looks like

    public class MyClass
    {
        ~MyClass()
        {
            // Do unmanaged resource clean up

            Console.WriteLine("In destructor");
        }
    }

Now let’s build it.
It builds successfully. Now let’s see this class using assembly Reflector.
destuctorSo here our destructor turned into Finalize method. So it means that destructor and Finalize are same in C#. But obviously while writing code in C#, it does not allow to override the Finalize method so we have only option to write destructor for that.

So don’t get confused ever if you see somewhere that say to override Finalize and you are not able to override it. Instead use destructor for that purpose.

Cheers,
Brij

How to use two different languages in a .NET Project

Did you ever try to use two languages in some of your project? Or Say you created a Class in VB.NET and used in C# code. As .NET provides us the capability to use multiple languages in same project, even it allows to inherit a VB.NET class in C# Class.If you have not tried earlier then this post will help you in getting practical examples. So Let’s move to the example

In this example, I have created two projects : one is C# Class library project and other is VB console application. My C# class looks like

    public class Person
    {
        public void Print()
        {
            Console.WriteLine("C# - Person's Print method");
        }
    }

It’s perfectly legal to inherit C# class in vb class. So here my vb class looks like

Public Class Student
    Inherits CLSCompliantCsharp.Person

    Public Sub Display()
        Console.WriteLine("I am Student VB class")
    End Sub
End Class

So here I have just added one more method Display in my vb.net class. Let’s move to main method

Module Module1
    Sub Main()
        Dim o As New Student()
        o.Display()
        o.Print()
        Console.ReadLine()
    End Sub
End Module

Let’s run it and see the output.

NormalSo it is perfectly fine and run as expected. Now let’s add one more method in my person class as

    public class Person
    {
        public void Print()
        {
            Console.WriteLine("C# - Person's Print method");
        }

        public void print()
        {
            Console.WriteLine("C# - Person's print method");
        }
    }

Now I have added one new method with same name print but it’s first letter is small letter. As we know that C# is case sensitive language so having the method with same name with different case, is perfectly legal.So lets build the C# project after making the changes So it is perfectly builds.

Now again move to the VB project and run the code.

Oh.. it throws a error as

errorAs we can see that it is giving error message that Print is ambiguous because for VB.NET Print() and print() are same while for Csharp different.

So How to deal this?

.NET provides us a way to make a library language neutral i e it defines some basic set of rules that can be applied to any library to make neutral. So if you think that your code/dll might be used by different language then you must apply an attribute to the your assembly.

The attribute is CLSCompliant

So if you want to make it a Class library CLSCompliant then add this attribute in the AssemblyInfo.cs file as

[assembly: CLSCompliant(true)]

I have added the above attribute in my C# project and now lets build it (with having two print method as earlier)

CLSComplaintWarningNow if you see that then it is showing an warning that this code is not CLS-Compliant Now you can correct it. Once you remove all the CLS-Complaint warnings and you can take a deep breath. You wont get any complaint if your code is used on any other language in .NET platform.

CLSCompliant attribute also provides more granular approach. It means if you don’t want to make the entire Class library as CLS-Compliant then you apply this attribute at class level as well. Then compiler will apply this attribute on that class only and that can be used by other language applications accordingly.

Hope you all have enjoyed this post.

Cheers,
Brij

What is SecureString ?

In this post, we are going to discuss a class SecureString. Although this class is available since .NET 2.0, but I am sure, many of us would not be knowing or using it. Even I was not aware of this fantastic class few weeks ago. This class can be very useful for you if you are more concerned about your application security.

This class belongs to the namespace System.Security . This class should be used to store the data which is confidential. The text assigned to this string is by default encrypted. This data is also removed as soon as it is not required which in-turn reduces the chances of misuse.

Continue reading

Working with EventViewer using C#

There are several phases of a Application . It does not end with developing the application and deploying it on production servers. Other most important part, any problem surfaces after the deployment, how quickly the problem can be be resolved and according to severity of the issue (if required) a patch can be deployed on production. Apart from this, we also want to get notified on all the issues occurred on production and accordingly analyze and take care in future releases. We can also log other details that could be useful to check the status of Application.

Continue reading