November 18, 2013

Future of Asp.Net Web Forms and MVC


On internet you can find plenty of articles and blog posts which are discuss briefly about the future of Asp.Net web forms and MVC, some of them are written by those persons who haven't like the Asp.net at all. 

Let me give you some thoughts: Few year back, Silverlight was the hot topic everywhere. Even the newbie developer tried to learn silverlight in such a way that Silverlight would be the best replacement of Adobe Flash based websites. Then what HAPPENED to SILVERLIGHT?? Totally collapse in front of Flash but still in use but not as that worth when it was first introduced. Now Microsoft introduced the new scripting library named as "Typescript". Would it be same as Silverlight or not it is a separate discussion. 

Here I want to discuss some good aspects and future of Asp.Net web forms and MVC architecture.

In Asp.net development, as compared with Web Forms the MVC is most popular choice by developers. The main reason of this popularity is to have an easy integration and accessibility of new and advance features of new client side libraries, Twitter Bootstrap for styling purpose etc and features which are present in HTML5. 

MVC is not just like Silverlight thing, it is different from it and Microsoft advancing it with many new features, easy to use advanced third party API's into as they are even much harder to integrate in Web Forms if you want to be.

In my thoughts, using MVC rather than web forms make developers life easier in order to maintain each and every entity, as the technology is advancing the features everyday, they are getting better and better in every release and expert's blog posts or articles would help you to adapt those new changes in fast pace. 

In term of testing the application, the MVC support easy testing compatibility because here we have the three separate layers (Model, View & Controller) as compared to Web forms in which testing is more complex because here too difficult to isolate the specific functionality.

This is a great time to learn new technologies, practising them and try to find out those points that help you to increase the scalability and performance of your application.

November 16, 2013

How to Negotiate a Higher Salary‏

Negotiating a higher salary is the last but trickiest part of securing a new job or keeping yourself happy in your current one. By negotiating a higher salary, you and your employer are letting each other know what the expectations are in terms of workload and compensation. With information and preparation, you will be able to negotiate for the higher salary you want and achieve positive results.
Step 1
Research what the market rate is for your position. Then you will know how much you should expect to negotiate.
Step 2
Look over your job description. Whether you are a new employee or a current one, it is important to consider what's expected of you and whether the salary your company is offering adequately covers those expectations.
Step 3
Round up your accomplishments. How much money have you saved the company or past companies? How much money have you made for them? Your hiring manager, recruiter or boss may ask you these questions when salary negotiations commence. Have the answers.
Step 4
Plan what you want to say before you meet with human resources or the boss. Do not try to negotiate a higher salary over email or telephone; salary negotiations should take place in a scheduled meeting.
Step 5
Listen carefully to the counteroffer. Carefully consider the comments or feedback he or she is providing. Ask questions if you need clarification or elaboration.
Step 6
Get the final offer in writing after salary negotiations end. If the company doesn't record the terms of your agreement, it is almost certainly subject to change.
 Source: E-How.com

November 5, 2013

Copy, Delete, and Move Files and Folders in C#

The following examples show how to copy, move, and delete files and folders in a synchronous manner by using the System.IO.File, System.IO.Directory, System.IO.FileInfo, and System.IO.DirectoryInfo classes from the System.IO namespace. These examples do not provide a progress bar or any other user interface. You can use System.IO.FileSystemWatcher to provide events that will enable you to calculate the progress when operating on multiple files.


// 1. The following example shows how to copy files and directories.

// Simple synchronous file copy operations with no user interface. 
// To run this sample, first create the following directories and files: 
// C:\Users\Public\TestFolder 
// C:\Users\Public\TestFolder\test.txt 
// C:\Users\Public\TestFolder\SubDir\test.txt 
public class SimpleFileCopy
{
    static void Main()
    {
        string fileName = "test.txt";
        string sourcePath = @"C:\Users\Public\TestFolder";
        string targetPath =  @"C:\Users\Public\TestFolder\SubDir";

        // Use Path class to manipulate file and directory paths. 
        string sourceFile = System.IO.Path.Combine(sourcePath, fileName);
        string destFile = System.IO.Path.Combine(targetPath, fileName);

        // To copy a folder's contents to a new location: 
        // Create a new target folder, if necessary. 
        if (!System.IO.Directory.Exists(targetPath))
        {
            System.IO.Directory.CreateDirectory(targetPath);
        }

        // To copy a file to another location and  
        // overwrite the destination file if it already exists.
        System.IO.File.Copy(sourceFile, destFile, true);

        // To copy all the files in one directory to another directory. 
        // Get the files in the source folder. (To recursively iterate through 
        // all subfolders under the current directory, see 
        // "How to: Iterate Through a Directory Tree.")
        // Note: Check for target path was performed previously 
        //       in this code example. 
        if (System.IO.Directory.Exists(sourcePath))
        {
            string[] files = System.IO.Directory.GetFiles(sourcePath);

            // Copy the files and overwrite destination files if they already exist. 
            foreach (string s in files)
            {
                // Use static Path methods to extract only the file name from the path.
                fileName = System.IO.Path.GetFileName(s);
                destFile = System.IO.Path.Combine(targetPath, fileName);
                System.IO.File.Copy(s, destFile, true);
            }
        }
        else
        {
            Console.WriteLine("Source path does not exist!");
        }

        // Keep console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}

// 2. The following example shows how to move files and directories.

// Simple synchronous file move operations with no user interface. 
public class SimpleFileMove
{
    static void Main()
    {
        string sourceFile = @"C:\Users\Public\public\test.txt";
        string destinationFile = @"C:\Users\Public\private\test.txt";

        // To move a file or folder to a new location:
        System.IO.File.Move(sourceFile, destinationFile);

        // To move an entire directory. To programmatically modify or combine 
        // path strings, use the System.IO.Path class.
        System.IO.Directory.Move(@"C:\Users\Public\public\test\", @"C:\Users\Public\private");
    }
}

// 3. The following example shows how to delete files and directories.

// Simple synchronous file deletion operations with no user interface. 
// To run this sample, create the following files on your drive: 
// C:\Users\Public\DeleteTest\test1.txt 
// C:\Users\Public\DeleteTest\test2.txt 
// C:\Users\Public\DeleteTest\SubDir\test2.txt 

public class SimpleFileDelete
{
    static void Main()
    {
        // Delete a file by using File class static method... 
        if(System.IO.File.Exists(@"C:\Users\Public\DeleteTest\test.txt"))
        {
            // Use a try block to catch IOExceptions, to 
            // handle the case of the file already being 
            // opened by another process. 
            try
            {
                System.IO.File.Delete(@"C:\Users\Public\DeleteTest\test.txt");
            }
            catch (System.IO.IOException e)
            {
                Console.WriteLine(e.Message);
                return;
            }
        }

        // ...or by using FileInfo instance method.
        System.IO.FileInfo fi = new System.IO.FileInfo(@"C:\Users\Public\DeleteTest\test2.txt");
        try
        {
            fi.Delete();
        }
        catch (System.IO.IOException e)
        {
            Console.WriteLine(e.Message);
        }

        // Delete a directory. Must be writable or empty. 
        try
        {
            System.IO.Directory.Delete(@"C:\Users\Public\DeleteTest");
        }
        catch (System.IO.IOException e)
        {
            Console.WriteLine(e.Message);
        }
        // Delete a directory and all subdirectories with Directory static method... 
        if(System.IO.Directory.Exists(@"C:\Users\Public\DeleteTest"))
        {
            try
            {
                System.IO.Directory.Delete(@"C:\Users\Public\DeleteTest", true);
            }

            catch (System.IO.IOException e)
            {
                Console.WriteLine(e.Message);
            }
        }

        // ...or with DirectoryInfo instance method.
        System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(@"C:\Users\Public\public");
        // Delete this dir and all subdirs. 
        try
        {
            di.Delete(true);
        }
        catch (System.IO.IOException e)
        {
            Console.WriteLine(e.Message);
        }

    }
}

Hope you understand the logics. Cheers

8 Most common mistakes C# developers make


In C# development, some mistakes are being repeated by almost every one of those who are young C# programmers. These are mostly the mistakes which once you note can easy to remember to avoid that mistake again in future. However, if a developer is not aware of them, they can cause many problems with the efficiency and quality of the developed software. Here I want to describe the the 8 most common mistakes made.

1. String concatenation instead of StringBuilder


String concatenation works in such a way that every time when you add something to a string, a new address in the memory is being allocated. The previous string is copied to a new location with the newly added part.   This is inefficient. On the other hand we have StringBuilder which keeps the same position in the memory without performing the copy operation. StringBuilder is much more efficient, especially in case of hundreds of append operations.

//INCORRECT
List values = new List(){"This ","is ","Sparta ","!"};
string outputValue = string.Empty;
foreach (var value in values)
{
   outputValue += value;
}

//CORRECT
StringBuilder outputValueBuilder = new StringBuilder();
foreach (var value in values)
{
   outputValueBuilder.Append(value);
}

2. LINQ – ‘Where’ with ‘First’ instead of FirstOrDefault

A lot of programmers find a certain set of elements by means of ‘Where’ and then return the first occurrence. This is inappropriate, because the ‘First’ method can be also applied with the ‘Where’ condition. What’s more, it shouldn’t be taken for granted that the value will always be found. If “First” is used when no value is found, an exception will be thrown. Thus, it’s better to use FirstOrDefault instead. When using FirstOrDefault, if no value has been found, the default value for this type will be returned and no exception will be thrown.

//INCORRECT
List numbers = new List(){1,4,5,9,11,15,20,21,25,34,55};
return numbers.Where(x => Fibonacci.IsInFibonacciSequence(x)).First();

//PARTLY CORRECT
return numbers.First(x => Fibonacci.IsInFibonacciSequence(x));

//CORRECT
return numbers.FirstOrDefault(x => Fibonacci.IsInFibonacciSequence(x));

3. Casting by means of ‘(T)’ instead of ‘as (T)’ when possibly not castable

It’s common that software developers use simple ‘(T)’ casting, instead of ‘as (T)’. And usually it doesn’t have any negative influence because casted objects are always castable. Yet, if there is even a very slight probability that an object can be under some circumstances not castable, „as (T)” casting should be used.

//INCORRECT
var woman = (Woman)person;

//CORRECT
var woman = person as Woman;

4. Not using mapping for rewriting properties

There are a lot of ready and very powerful C# mappers (e.g. AutoMapper). If a few lines of code are simply connected with rewriting properties, it’s definitely a place for a mapper. Even if some properties aren’t directly copied but some additional logic is performed, using a mapper is still a good choice (mappers enable defining the rules of rewriting properties to a big extend).

5. Incorrect exceptions re-throwing

C# programmers usually forget that when they throw an exception using „throw ex” they loose the stack trace. It is then considerably harder to debug an application and to achieve appropriate log messages. When simply using „throw” no data is lost and the whole exception together with the stack trace can be easily retrieved.

//INCORRECT
try
{
   //some code that can throw exception [...]
}
catch (Exception ex)
{
   //some exception logic [...]
   throw ex;
}

//CORRECT
try
{
   //some code that can throw exception [...]
}
catch (Exception ex)
{
   //some exception logic [...]
   throw;
}

6. Not using ‘using’ for objects disposal

Many C# software developers don’t even know that ‘using’ keyword  is not only used as a directive for adding namespaces, but also for disposing objects. If you know that a certain object should be disposed after performing some operations, always use the ‘using’ statement to make sure that the object will actually be disposed.

// INCORRECT:
SomeDisposableClass someDisposableObject = new SomeDisposableClass();
try
{
   someDisposableObject.DoTheJob();
}
finally
{
   someDisposableObject.Dispose();
}

// CORRECT:
using(SomeDisposableClass someDisposableObject = new SomeDisposableClass())
{
   someDisposableObject.DoTheJob();
}

7. Using ‘foreach’ instead of ‘for’ for anything else than collections

Remember that if you want to iterate through anything that is not a collection (so through e.g. an array), using the ‘for’ loop is much more efficient than using the ‘foreach’ loop. See Foreach vs For Performance for more details.

8. Retrieving or saving data to DB in more than 1 call

This is a very common mistake, especially among junior developers and especially when using ORMs like Entity Framework or NHibernate. Every DB call consumes some amount of time and therefore it’s crucial to decrease the amount of DB calls as much as possible. There are many ways to do so:

a. Using fetching (Eager Loading)
b. Enclosing DB operations in transactions
c. In case of a really complex logic, just moving it to the DB by building a stored procedure

Hope you understand the areas. To learn more about Best Recomemended Practices in developement read this. Cheers.

November 2, 2013

For vs Foreach in Performance Meter

There are two kinds of programmers. Those who write something to get the work done and those who want to write good code. But here is question about to show the best performance and it would come when you write a Good Code. So, What is good code? Good code comes from good programming practices. Here I'm showing you the comparision between two popular loops to show which one is best in performance. 

The demonstration will include the IL and assembly code, you must be familiar with them. Also have a good knowledge on how .Net framework works. Some knowledge of JIT is also needed to understand what is exactly happening.

I’m going to take a very small piece of code for two popular looping statements for and foreach. We will look some code and will see what it does, more in detail about the functionality.

FOR

int[] myInterger = new int[1];
int total = 0;
for(int i = 0; i < myInterger.Length; i++)
{
    total += myInterger[i];
}

Foreach

int[] myInterger = new int[1];
int total = 0;
foreach(int i in myInterger) 
{
    total += i;
}

Both codes will produce the same result. foreach is used on top of collections to traverse through while for can be used on anything for the same purpose. So, when we talk about the optimization, two things we must consider. First is C# compiler and the second is JIT.

In variable declaration, foreach has five variable declarations (three Int32 integers and two arrays of Int32) while for has only three (two Int32 integers and one Int32 array). When it goes to loop through, foreach copies the current array to a new one for the operation. While for doesn't care of that part.

Here, I’m going into the exact difference between the codes.

FOR

Instruction                           Effect

cmp     dword ptr [eax+4],0           i<myInterger.Length
jle     0000000F
mov     ecx,dword ptr [eax+edx*4+8]   total += myInterger[i]
inc     edx                           ++i
cmp     esi,dword ptr [eax+4]         i<myInterger.Length
jl      FFFFFFF8

Here, the esi register which holds the value of i and the length of myInteger array are compared at two stages. The first one is done only once to check the condition and if the loop can continue, the value is added. For the loop, it is done at the second stage. Inside the loop, it is well optimized and as explained, the work is done with perfect optimization.

Foreach

Instruction                            Effect

cmp     esi,dword ptr [ebx+4]          i<myInterger.Length
jl      FFFFFFE3
cmp     esi,dword ptr [ebx+4]          i<myInterger.Length 
jb      00000009
mov     eax,dword ptr [ebx+esi*4+8] 
mov     dword ptr [ebp-0Ch],eax  
mov     eax,dword ptr [ebp-0Ch]
add     dword ptr [ebp-8],eax          total += i
inc     esi                            ++i
cmp     esi,dword ptr [ebx+4]          i<myInterger.Length
jl      FFFFFFE3

Anyone will say that both are not the same. But we will look why it differs from the for loop. The main reason for the difference is that both of them are differently understood by the compiler. The algorithm they are using is different. Two compare statements one after the other is unnecessary. It is doing the same thing again and again for no reason!

cmp                    esi,dword ptr [ebx+4]   
jl                     FFFFFFE3
cmp                    esi,dword ptr [ebx+4]

It also uses some unnecessary move statements which also may reduce the performance of the code. Foreach is thinking everything as a collection and treating them as a collection. That will also reduce the performance of the work. 

Therefore, If you are planning to write high performance code that is not for collections, use for loop. Even for collections, foreach may look handy when using, but it's not that efficient. Cheers

November 1, 2013

Regular Expression's Technique and Methods

Regular expressions are a good way to validate text fields such as names, addresses, phone numbers, and other user information. You can use them to constrain input, apply formatting rules, and check lengths. To validate input captured with server controls, you can use the RegularExpressionValidator control. To validate other forms of input, such as query strings, cookies, and HTML control input, you can use the System.Text.RegularExpressions.Regex class.

RegularExpressionValidator


To validate a server control's input using a RegularExpressionValidator

  • Add a RegularExpressionValidator control to your page.
  • Set the ControlToValidate property to indicate which control to validate.
  • Set the ValidationExpression property to an appropriate regular expression.
  • Set the ErrorMessage property to define the message to display if the validation fails.
The following example shows a RegularExpressionValidator control used to validate a name field.


<%@ language="C#" %>
<form id="form1" runat="server">
    <asp:TextBox ID="txtName" runat="server"/>
    <asp:Button ID="btnSubmit" runat="server" Text="Submit" />
    <asp:RegularExpressionValidator ID="regexpName" runat="server"     
                                    ErrorMessage="This expression does not validate." 
                                    ControlToValidate="txtName"     
                                    ValidationExpression="^[a-zA-Z'.\s]{1,40}$" />
</form>

Regex Class


If you are not using server controls or if you need to validate input from sources other than form fields, such as query string parameters or cookies, you can use the Regex class within the System.Text.RegularExpressions namespace. To use the Regex class:

1. Add a using statement to reference the System.Text.RegularExpressions namespace.
2. Call the IsMatch method of the Regex class, as shown in the following example.


// Instance method:
Regex reg = new Regex(@"^[a-zA-Z'.]{1,40}$");
Response.Write(reg.IsMatch(txtName.Text));

// Static method:
if (!Regex.IsMatch(txtName.Text, 
                   @"^[a-zA-Z'.]{1,40}$"))
{
  // Name does not match schema
}

Regular Expression Comments


Regular expressions are much easier to understand if you use the following syntax and comment each component of the expression by using a number sign (#). To enable comments, you must also specify RegexOptions.IgnorePatternWhitespace, which means that non-escaped white space is ignored.


Regex regex = new Regex(@"
                        ^           # anchor at the start
                       (?=.*\d)     # must contain at least one numeric character
                       (?=.*[a-z])  # must contain one lowercase character
                       (?=.*[A-Z])  # must contain one uppercase character
                       .{8,10}      # From 8 to 10 characters in length
                       \s           # allows a space 
                       $            # anchor at the end", 
                       RegexOptions.IgnorePatternWhitespace);
  

Common Regular Expressions

FieldExpressionFormat SamplesDescription
Name^[a-zA-Z''-'\s]{1,40}$John Doe
O'Dell
Validates a name. Allows up to 40 uppercase and lowercase characters and a few special characters that are common to some names. You can modify this list.
Social Security Number^\d{3}-\d{2}-\d{4}$111-11-1111Validates the format, type, and length of the supplied input field. The input must consist of 3 numeric characters followed by a dash, then 2 numeric characters followed by a dash, and then 4 numeric characters.
Phone Number^[01]?[- .]?(\([2-9]\d{2}\)|[2-9]\d{2})[- .]?\d{3}[- .]?\d{4}$(425) 555-0123
425-555-0123
425 555 0123
1-425-555-0123
Validates a U.S. phone number. It must consist of 3 numeric characters, optionally enclosed in parentheses, followed by a set of 3 numeric characters and then a set of 4 numeric characters.
E-mail^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$someone@example.comValidates an e-mail address.
URL^(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&amp;%\$#_]*)?$http://www.microsoft.comValidates a URL
ZIP Code^(\d{5}-\d{4}|\d{5}|\d{9})$|^([a-zA-Z]\d[a-zA-Z] \d[a-zA-Z]\d)$12345Validates a U.S. ZIP Code. The code must consist of 5 or 9 numeric characters.
Password(?!^[0-9]*$)(?!^[a-zA-Z]*$)^([a-zA-Z0-9]{8,10})$Validates a strong password. It must be between 8 and 10 characters, contain at least one digit and one alphabetic character, and must not contain special characters.
Non- negative integer^\d+$0
986
Validates that the field contains an integer greater than zero.
Currency (non- negative)^\d+(\.\d\d)?$1.00Validates a positive currency amount. If there is a decimal point, it requires 2 numeric characters after the decimal point. For example, 3.00 is valid but 3.1 is not.
Currency (positive or negative)^(-)?\d+(\.\d\d)?$1.20Validates for a positive or negative currency amount. If there is a decimal point, it requires 2 numeric characters after the decimal point.

Choose Between ASP.NET MVC vs ASP.NET Web Form

You can probably imagine MVC is going to be an architectural pattern for the foreseeable future, especially on the web. So it is very important to internalize and understand the major difference between ASP.NET MVC and the older ASP.NET Web Forms.


ASP.NET Web Forms


ASP.NET Web Forms has proven to be a mature technology that runs small and large scale websites alike. Web Forms, was built around the Windows Form construction, where you had a declarative syntax with an event driven model. This allowed visual designers to take full advantage of the drag and drop, WYSIWYG, interface that they had become accustom to under Windows Forms development in Visual Studio 6.0. In that they only needed to drop controls onto the ASP.NET page and then wire up the events, as was common in Visual Basic 6.0 development at the time. This made Web Forms a natural choice for Windows Forms developers, because the learning curve was low and the need to understand HTML and many of the web centric technologies almost zero. 

Web Forms is not all roses and buttercups, when you are trying to optimize your code for scalability, the biggest problems are the ViewState and PostBack model.  ViewState is a way to store the state of the controls, such as data, selections etc, which is needed to preserve the Windows Form like development habits of the developers. ViewState was necessary, because the web is a stateless environment meaning that when a request comes in to the server it has no recollection of the previous request.  So in order to give state to a stateless environment you need to communicate the previous state back to the server, in Web Forms this was accomplished using hidden <input /> fields that can become ridiculously large. This increased size becomes apparent when server controls such as GridView are added to the page.  PostBack was another creation to facilitate the Windows Form development feel, it renders JavaScript for every subscribed event, which leaves web developer less control over how the browser communicates with the server.

Web Forms have many strengths and weaknesses:


Strengths


1. Mature technology
2. Provides very good RAD development capabilities
3. Great WYSIWYG designer support in Visual Studio
4. Easy state management
5. Rich control libraries from Microsoft and third party vendors
6. Abstracts the need to understand HTTP, HTML, CSS, and in some cases JavaScript
7. ViewState and PostBack model
8. A familiar feel to Windows Forms development

Weaknesses


1. Display logic coupled with code, through code-behind files
2. Harder to unit test application logic, because of the coupled code-behind files
3. ViewState and PostBack model
4. State management of controls leads to very large and often unnecessary page sizes

ASP.NET MVC


ASP.NET was often overlooked as a viable platform for modern highly interactive websites that required a very granular control over the output of the HTML, because of the lack of control over the rendered HTML. This granularity of control was sacrificed in Web Forms to make if more like Windows Forms development, in other words easier for the drag and drop developers. This lack of control over the HTML rendering forced developers to move the platforms such as PHP and Ruby on Rails, which offered the level of control they required and the MVC programming model that provided a necessary separation of concerns for their highly complex web applications.

In 2007, Microsoft implemented ASP.NET MVC to be a modern web development platform that gives a ‘closer to the metal’ experience to the developers that program with it, by providing full control and testability over the output that is returned to the browser. 

MVC has many strengths and weaknesses:

Strengths


1.  Provides fine control over rendered HTML
2.  Cleaner generation of HTML 
3.  Clear separation of concerns
4.  Provides application layer unit testing
5.  Can support multiple view engines, such as Brail, NHaml, NVelocity, XSLT, etc.
6.  Easy integration with JavaScript frameworks like jQuery or Yahoo UI frameworks
7.  Ability to map URLs logically and dynamically, depending on your use
8.  Restful interfaces are used by default 
9.  No ViewState and PostBack model
10. Supports all the core ASP.NET features, such as authentication, caching, membership, etc.
11. Size of the pages generated typically much smaller because of the lack of the ViewState

Weaknesses


1. Not event driven by the framework, so it maybe more difficult for ASP.NET Web Form developers to understand
2. Requires the need to understand, at least at the basic level, HTTP, HTML, CSS, and JavaScript
3. Third party library support is not as strong
4. No direct upgrade path from Web Forms
5. No ViewState and PostBack model which makes it more difficult to preserve state

The pros and cons of MVC have to be weighed just as much as Web Forms, and MVC is not always the logical choice. It’s up to you to decide and you choice needs to be weighted with a number of other factors, such as team and application requirements, when deciding which ASP.NET technology to implement. 

25 Different Ways to Say ‘Good Job’ in English


When learning English you don’t want to get stuck saying the same words over and over again. These are positive statements in English that you could say to anyone; at work, at school or.... ANYWHERE, Here is 25 alternatives to ‘Good Job’

1. Excellent 
2. Nice 
3. Exemplary 
4. Marvelous 
5. Outstanding 
6. Perfect 
7. Well done 
8. Impressive 
9. Good work 
10. Fantastic 
11. Great 
12. You did it! 
13. Way to go! 
14. I have never seen anyone get it done that quickly 
15. I knew you could do it! 
16. I love the way you work
17. It looks like a lot of work went into this 
18. I’m so proud of you 
19. Much better 
20. You make it look so easy 
21. Much improved 
22. How come I never knew you could know so well? 
23. You did better than I could have done it 
24. You really went to town 
25. Awesome 

Next time you find yourself about to tell someone they did a ‘good job;’ stop and use one of these words English phrases instead.