Tuesday, 9 September 2025

Create Email Body In Jenkins Using Editable Email Notification Plugin

 Problem Statement - 

After publishing test result in Jenkin's post build action any xunit plugin such as publish Junit/TestNG restult. One may want to create simple mail to stake holders quantifying test execution status. 

Email body may be typically in html format with rows and columns with columns for total tests/pass/fail/skip...

Solution #1 - Use of Default Content (Simple Information Without Test Count Status - Total/Pass/Fail/Skip) -

Challenge with default content approach - 

While default content can write Job/build/Jenkins URL seamlessly, it struggles to get details regarding test success count (Total/Pass/Fail/Skip).

content of default content can be like below - 

"""

$JOB_NAME ($BUILD_NUMBER) - $BUILD_URL

<!DOCTYPE html>

<html>

<head>

<style>

table {

  font-family: arial, sans-serif;

  border-collapse: collapse;

  width: 100%;

}

td, th {

  border: 1px solid #dddddd;

  text-align: left;

  padding: 8px;

}

tr:nth-child(even) {

  background-color: #dddddd;

}

</style>

</head>

<body>

<h3>$JOB_NAME - $BUILD_NUMBER - $BUILD_STATUS!</h3>

<table>

  <tr>

    <th>Job Name</th>

    <th>Build Number</th>

    <th>Jenkins URL</th>

  </tr>

  <tr>

    <td>$JOB_NAME</td>

    <td>$BUILD_NUMBER</td>

    <td>$BUILD_URL</td>

  </tr>

</table>

</body>

</html>

"""

Solution #2 - Use Of Pre-Send Script (Under Advanced Section Of Editable Email Notificaction) to read job/build/test status programmatically using Jenkins hudson library)

Following groovy script has to be added - 

/***
Challenge - Since, script interacts with hudson library Jenkins restricts accessing hudson layer directly. 
Script and various hudson methods have to be explicitly approved in Jenkins in-process Script Approval plugin

***/

def testResult = build.getAction(hudson.tasks.junit.TestResultAction.class)
def totalCount = "NA", failCount = "NA", skipCount = "NA", passCount = "NA", fail_per = "NA", skip_per = "NA", pass_per = "NA"
def job = build.getProject().getName()
def build_number = build.getNumber()
def build_status = build.getResult()
def build_url = build.getUrl()

if (testResult != null) {
   logger.println("test result found")
    totalCount = testResult.getTotalCount()
    failCount = testResult.getFailCount()
    skipCount = testResult.getSkipCount()
    passCount = totalCount - failCount - skipCount
    
    fail_per = (totalCount > 0) ? ((failCount / totalCount) * 100).intValue() : 0
    skip_per = (totalCount > 0) ? ((skipCount / totalCount) * 100).intValue() : 0
    pass_per = 100 - (fail_per + skip_per)

   
    
    def failed_tests_refs_rows = ""
    def text_to_strip = "Ubicquia_Tests.Test_Components.Framework_Update."
    def counter = 0
    if(failCount>0) {
     logger.println("---------------------------------------------------------------Failed Tests Details For ${failCount} Tests Are Printed Below---------------------------------------------------------------------------------------------------------------:")
    def failedTests = testResult.getFailedTests()
        failedTests.each { test ->
        counter = counter + 1        
        def name = test.getName() // Test method name
        def className = test.getClassName() // Fully qualified class name
        className = className - text_to_strip
        def errorDetails = test.getErrorDetails() // Error message
        logger.println("${counter } -> Test Fails -> ${className}  \nError Details -> ${errorDetails}")
        def row_background = (counter %2 ==0)? "style='background-color: #e6f3ff;'": "" //set light blue for alternate row starting from
        failed_tests_refs_rows = failed_tests_refs_rows + "<tr ${row_background}><td>${counter}</td><td>${name}</td><td style='text-align: left;'>${className}</td><td style='text-align: left;'>${errorDetails}</td></tr>"
    }
 logger.println("---------------------------------------------------------------Failed Tests Details For ${failCount} Tests Ends---------------------------------------------------------------------------------------------------------------:")
}

    def summary = """

<!DOCTYPE html>
<html>
<head>
<style>
table {
  font-family: arial, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

td, th {
  border: 2px solid #dddddd;
  text-align: center;
  vertical-align: middle;
  padding: 8px;
}


</style>
</head>
<body>

<table>
<table>
<tr><td><h3>${job} - ${build_number} - ${build_status}</h3></td></tr>
</table>

<table>
  <tr><th>Jenkins URL</th><th>Total Tests</th><th>Total Pass</th><th>Total Fail</th><th>Total Skip</th></tr>
  <tr><td style='text-align: left;'><a href='${build_url}'>${build_url}</td><td>${totalCount}</td><td>${passCount} ( ${pass_per}% )</td><td>${failCount} ( ${fail_per}% )</td><td>${skipCount} ( ${skip_per}% )</td></tr>
</table>

<table class='details-table'>
<tr><th>Serial Number</th><th>Failed Tests</th><th>Class Name</th><th>Error Details</th></tr>${failed_tests_refs_rows}

</table>
</table>
</body>
</html>
   """.toString()
    
msg.setContent(summary, "text/html")
   
}
else{
logger.println("test result not found")
}
 logger.println("Test results: Total Test =${totalCount}, Total Passed=${passCount} (${pass_per}%), Total Failed=${failCount} (${fail_per}%), Total Skipped = ${skipCount} (${skip_per}%)")

Solution #3 - Using Macro/Environment Variable Set By test is published. (Yet To Be Verified For Test Counts...)


Job Name: $JOB_NAME
Build Number: $BUILD_NUMBER
Build URL: $BUILD_URL
Total Tests: ${TEST_COUNTS,var="total"}
Passed: ${TEST_COUNTS,var="pass"}
Failed: ${TEST_COUNTS,var="fail"}
Skipped: ${TEST_COUNTS,var="skip"}

Tuesday, 8 August 2023

Jenkins - Build Steps - Execute Windows batch command - pytest

::echo off

echo test_product=%test_product%

echo test_env=%test_env%

echo list_devices=[%list_devices%]

echo total iteration=%ota_iterations%

echo total max attempts=%ota_max_attempt%

set test1=KPI_Scripts\UbiCell\%KPM_Tests%

echo test1=%test1%

echo is_test_result_to_be_uploaded_on_cloud=%is_test_result_to_be_uploaded_on_cloud%

pytest %test1% -n=%NumberOfThreadsForOTAIterations% --junitxml="./Reports/reports.xml" --html="./Reports/reports.html" 

Jenkins Groovy Function To Be Used by Active Choice Parameter - To Have Auto Selected Based On Certain Logic

 

Jenkins Groovy Function To Be Used by Active Choice Parameter - To Have Auto Selected Based On Certain Logic

def get_list(x,delimiter,item_to_be_selected,bool_is_selected=false) {

    list_selected = null

    if(x!=null && x.length() > 0) {

        list = x.split(delimiter)

        list_selected = []

        for(int i=0;i<list.size();i++){

            if(bool_is_selected){

                if(list[i].trim().equals(item_to_be_selected)){

                     list_selected[i] = list[i].trim() + ':selected'

                    

                    }

                else {

                    list_selected[i] = list[i].trim()

                }

            }

            else {

                list_selected[i] = list[i].trim()

            }

            

        }

       

    }

     return list_selected

}


Calling the function - return get_list(list_ota_servers,'-','t:98,d:http://updqa4.ubicquia.com',true)

Tuesday, 25 July 2023

Regular Expression For Exclusion

 Regular expression for exclusion

Regular expression can be applied for excluding certain words - 

1. Use (?!<word to be excluded>)

2. (?i) to make cases insensitive

Example - discarded and template to be excluded where (?i) indicates being case insensitive

(?i)(?!.*discarded.*)(?!.*template.*)(.*ubicell.*) 

Saturday, 22 July 2023

Regular Expression - How To Create Regular Expression For Case Insensitive

 How To Create Regular Expression For Case Insensitive


  1. Use Simple Regular Expression Syntax - (?i)<Normal Regular Expression>
    • (?i) -> Indicates Case Insensitive Regular Expression
  2. Use Language And Technology To Use Library/Methods/Interface To Pass Additional Parameter As             Flag To Determine If Case Sensitive Or Case InSensitive Comparison Is Required. 
  • FindPattern(<regular expression>, caseSensitiveFlag(True/False))

Tuesday, 30 May 2023

MQTT Protocol - IOT Design Approach

Original Source - https://www.javatpoint.com/mqtt-protocol

 MQTT stands for Message Queuing Telemetry Transport. MQTT is a machine to machine internet of things connectivity protocol. It is an extremely lightweight and publish-subscribe messaging transport protocol. This protocol is useful for the connection with the remote location where the bandwidth is a premium. These characteristics make it useful in various situations, including constant environment such as for communication machine to machine and internet of things contexts. It is a publish and subscribe system where we can publish and receive the messages as a client. It makes it easy for communication between multiple devices. It is a simple messaging protocol designed for the constrained devices and with low bandwidth, so it's a perfect solution for the internet of things applications.

Current MQTT Version - MQTT 5.0, developed and managed by OASIS.

Journey - MQTT 3.1 -> MQTT 3.1.1 (Backward Compatible) -> MQTT 5.0 (Not Backward Compatible)

The major functional objectives in version 5.0 are:

  • Enhancement in the scalability and the large-scale system in order to set up with the thousands or the millions of devices.
  • Improvement in the error reporting

Characteristics of MQTT

The MQTT has some unique features which are hardly found in other protocols. Some of the features of an MQTT are given below:

  • It is a machine to machine protocol, i.e., it provides communication between the devices.
  • It is designed as a simple and lightweight messaging protocol that uses a publish/subscribe system to exchange the information between the client and the server.
  • It does not require that both the client and the server establish a connection at the same time.
  • It provides faster data transmission, like how WhatsApp/messenger provides a faster delivery. It's a real-time messaging protocol.
  • It allows the clients to subscribe to the narrow selection of topics so that they can receive the information they are looking for.

MQTT Architecture


To understand the MQTT architecture, we first look at the components of the MQTT.

  • Message
  • Client
  • Server or Broker
  • TOPIC

Message

The message is the data that is carried out by the protocol across the network for the application. When the message is transmitted over the network, then the message contains the following parameters:

  1. Payload data
  2. Quality of Service (QoS)
  3. Collection of Properties
  4. Topic Name

Client

In MQTT, the subscriber and publisher are the two roles of a client. The clients subscribe to the topics to publish and receive messages. In simple words, we can say that if any program or device uses an MQTT, then that device is referred to as a client. A device is a client if it opens the network connection to the server, publishes messages that other clients want to see, subscribes to the messages that it is interested in receiving, unsubscribes to the messages that it is not interested in receiving, and closes the network connection to the server.

In MQTT, the client performs two operations:

In MQTT, the client performs two operations:

Publish: When the client sends the data to the server, then we call this operation as a publish.

Subscribe: When the client receives the data from the server, then we call this operation a subscription.

Server

The device or a program that allows the client to publish the messages and subscribe to the messages. A server accepts the network connection from the client, accepts the messages from the client, processes the subscribe and unsubscribe requests, forwards the application messages to the client, and closes the network connection from the client.

TOPIC

MQTT protocol

The label provided to the message is checked against the subscription known by the server is known as TOPIC.

Now we will look at the architecture of MQTT. To understand it more clearly, we will look at the example. Suppose a device has a temperature sensor and wants to send the rating to the server or the broker. If the phone or desktop application wishes to receive this temperature value on the other side, then there will be two things that happened. The publisher first defines the topic; for example, the temperature then publishes the message, i.e., the temperature's value. After publishing the message, the phone or the desktop application on the other side will subscribe to the topic, i.e., temperature and then receive the published message, i.e., the value of the temperature. The server or the broker's role is to deliver the published message to the phone or the desktop application.

MQTT Message Format

MQTT protocol

The MQTT uses the command and the command acknowledgment format, which means that each command has an associated acknowledgment. As shown in the above figure that the connect command has connect acknowledgment, subscribe command has subscribe acknowledgment, and publish command has publish acknowledgment. This mechanism is similar to the handshaking mechanism as in TCP protocol.

Now we will look at the packet structure or message format of the MQTT.

Sunday, 14 May 2023

Problem Statement - Jenkins HTML Pubisher Does Not Display HTML Reports Properly With CSS

By default, Jenkins latest version displays Extent Report or any html report with CSS in normal text, as Extent Report or any html report with CSS contains scripts which pose threat to web security. 

To overcome the problem, we have to override property - hudson.model.DirectoryBrowserSupport.CSP

There are 2 options available - 

1. Pass Parameter While Invoking Jenkins With War File - 

    java -Dhudson.model.DirectoryBrowserSupport.CSP="" -jar jenkins.war

2. Configure Jenkins 

    1.     Go to http://localhost:8080/ using admin credentials

2.     Click on Manage Jenkins link.

3.     Click on Script Console.

4.     Type below Syntax in Script Console and click on Run link.

            System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "")


Thursday, 9 March 2023

 Confiuring VSCode For Protractor Execution- 

Create launch.json file, this file should be under .vscode folder.

launch.json file should have reference to runner tool in program attribute and args attribute should contain the parameters for program attribute. 

Run command would refer lanunch.json for parameters used for execution

Typically, it should like as below - 

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version""0.2.0",
    "configurations": [
        

        {
            "type""pwa-node",          
            "request""launch",
            "name""Protractor Runner",
            "skipFiles": [
                "<node_internals>/**"
            ],
            "program""${env:APPDATA}/npm/node_modules/protractor/bin/protractor",
            "args": ["${workspaceFolder}/conf/conf_Jenkins.js"]
            /*
            "args": [
                "-c", "/Users/xyz/config",
                "-p", "2012"
            */
        }
    ]
}

Saturday, 28 December 2019

Adding Environment Variables In Jenkins Using Groovy Script

https://medium.com/@mukeshsingal/access-jenkins-global-environment-variables-using-groovy-or-java-b5c1e6b53685
import hudson.EnvVars;
import hudson.slaves.EnvironmentVariablesNodeProperty;
import hudson.slaves.NodeProperty;
import hudson.slaves.NodePropertyDescriptor;
import hudson.util.DescribableList;
import jenkins.model.Jenkins;public createGlobalEnvironmentVariables(String key, String value){

        Jenkins instance = Jenkins.getInstance();

        DescribableList<NodeProperty<?>, NodePropertyDescriptor> globalNodeProperties = instance.getGlobalNodeProperties();
        List<EnvironmentVariablesNodeProperty> envVarsNodePropertyList = globalNodeProperties.getAll(EnvironmentVariablesNodeProperty.class);

        EnvironmentVariablesNodeProperty newEnvVarsNodeProperty = null;
        EnvVars envVars = null;

        if ( envVarsNodePropertyList == null || envVarsNodePropertyList.size() == 0 ) {
            newEnvVarsNodeProperty = new hudson.slaves.EnvironmentVariablesNodeProperty();
            globalNodeProperties.add(newEnvVarsNodeProperty);
            envVars = newEnvVarsNodeProperty.getEnvVars();
        } else {
            envVars = envVarsNodePropertyList.get(0).getEnvVars();
        }
        envVars.put(key, value)
        instance.save()
}createGlobalEnvironmentVariables('Var1','DummyValue')

Thursday, 22 February 2018

Monday, 29 January 2018

Maven POM Configuration For TestNG Execution

http://maven.apache.org/surefire/maven-surefire-plugin/examples/testng.html

Inclusions and Exclusions of Tests

Inclusions

By default, the Surefire Plugin will automatically include all test classes with the following wildcard patterns:
  • "**/Test*.java" - includes all of its subdirectories and all Java filenames that start with "Test".
  • "**/*Test.java" - includes all of its subdirectories and all Java filenames that end with "Test".
  • "**/*Tests.java" - includes all of its subdirectories and all Java filenames that end with "Tests".
  • "**/*TestCase.java" - includes all of its subdirectories and all Java filenames that end with "TestCase".
If the test classes do not follow any of these naming conventions, then configure Surefire Plugin and specify the tests you want to include.
<project>
  [...]
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.20.1</version>
        <configuration>
          <includes>
            <include>Sample.java</include>
          </includes>
        </configuration>
      </plugin>
    </plugins>
  </build>
  [...]
</project>

Exclusions

There are certain times when some tests are causing the build to fail. Excluding them is one of the best workarounds to continue the build. Exclusions can be done by configuring the excludes property of the plugin.
<project>
  [...]
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.20.1</version>
        <configuration>
          <excludes>
            <exclude>**/TestCircle.java</exclude>
            <exclude>**/TestSquare.java</exclude>
          </excludes>
        </configuration>
      </plugin>
    </plugins>
  </build>
  [...]
</project>

Using Suite XML Files

Another alternative is to use TestNG suite XML files. This allows flexible configuration of the tests to be run. These files are created in the normal way, and then added to the Surefire Plugin configuration:
<plugins>
    [...]
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.20.1</version>
        <configuration>
          <suiteXmlFiles>
            <suiteXmlFile>testng.xml</suiteXmlFile>
          </suiteXmlFiles>
        </configuration>
      </plugin>
    [...]
</plugins>

Thursday, 21 September 2017

IDE - Most Used Shortcut In Eclipse/VisualStudio

Eclipse -
1. Going Back To Last Cursor Position - Alt + Left/Alt + Right
2. Ctrl+Q - moves the cursor to the last edit location




Visual Studio
1. Going Back To Last Cursor Position - CTRL + "-"

Maven: How To Add Local Dependency In Maven POM.XML

<dependencies>
  <dependency>
 <groupId>reporter</groupId>
 <artifactId>reporter</artifactId>
 <version>1.0.0</version>
 <scope>system</scope>
 <systemPath>${project.basedir}\lib\CignitiReporter-1.0.jar</systemPath>
     </dependency>
</dependencies>

Monday, 5 June 2017

Adding Ranorex.PDF plugin Using NuGet/Package Management Console

About - Ranorex.PDF plugin - It converts Ranorex Default Report To PDF format.
http://www.ranorex.com/blog/ranorex-report-to-pdf-conversion/ 

Editors/IDEs such as Visual Studio/Ranorex may not show up Ranorex.PDF package using Manage Package interface of Editors.

Ranorex.PDF can be installed from Package Management Console.

Type - Install-Package Ranorex.PDF by selecting the project you wish to be installed on.

Project can be selected using Install-Package switch parameter or selecting Project from Package Management Console.


Friday, 21 October 2016

MSTest Jenkins Integration


Plugins Required :
1. Active Choice Parameter
2. Html Report Publisher
3. File System SCM
4. To publish Extent report, you have do some setting in jenkins. The setting details have been covered as other topic.







Monday, 17 October 2016

Where Jenkins Login Password is saved

Jenkins places admin login password in file - ${Home Path}\.jenkins\secrets\initialAdminPassword file.
It's different than where Jenkins is installed.
Normally, Home location = C:\Users\{User}


Friday, 23 September 2016

Maven Error When Executed Using Eclipse - No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?

One may see following error for the first time when maven project is tried to be run using POM -

Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project Json: Compilation failure
[ERROR] No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?

Problems is about setting JRE version in eclipse/setting javac in POM.

To fix the eclipse to run Maven test -

1. Go to Installed JREs in following way through Eclipse Menu options
Menu ->Windows->Preferences->Installed JREs.

2. Select/Add Installed JRE

Another Approach -
To fix the POM - Set Maven-compiler-plugin

Reference -
http://maven.apache.org/plugins/maven-compiler-plugin/examples/compile-using-different-jdk.html

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.apache.maven.plugins</groupId>
  5. <artifactId>maven-compiler-plugin</artifactId>
  6. <version>3.5.1</version>
  7. <configuration>
  8. <verbose>true</verbose>
  9. <fork>true</fork>
  10. <executable><!-- path-to-javac --></executable>
  11. <compilerVersion>1.3</compilerVersion>
  12. </configuration>
  13. </plugin>
  14. </plugins>
  15. </build>

Some times, in-appropriate testng version causes issue.
For example I got following issue with 6.9.13.6 -

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test (default-test) on project Json: Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test failed: The forked VM terminated without saying properly goodbye. VM crash or System.exit called ? -> [Help 1]

The complete stack trace was - 
org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException; nested exception is java.lang.reflect.InvocationTargetException: null
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: org.apache.maven.surefire.testset.TestSetFailedException: Unknown TestNG version 6.9.13.6
at org.apache.maven.surefire.testng.TestNGExecutor.getConfigurator(TestNGExecutor.java:207)
at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:72)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:110)
at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:106)
... 9 more

Solution - 
TestNG version 6.9.9 worked well for me.

Monday, 19 September 2016

Why Sometimes Visual Studio IDE compiles Code But MSBuild Throws Compilation Error Because Of Assembly Reference Not Found


1. I had a CodedUI Test which used CodedUI library such as -
using Microsoft.VisualStudio.TestTools.UITesting;
using Microsoft.VisualStudio.TestTools.UITesting.WinControls;
using Microsoft.VisualStudio.TestTools.UITesting.WpfControls;

I was successfully able to compile the entire solution using Visual Stduio IDE 2013 Ultimate.
But, while I was trying to compile the same using MSBuild tool, I was getting errors because of not able to find assemblies
Following errors were thrown:
05:44:41 FunctionalTests\CodedUITest1.cs(7,40): error CS0234: The type or namespace name 'UITesting' does not exist in the namespace 'Microsoft.VisualStudio.TestTools' (are you missing an assembly reference?) [C:\Users\Administrator\.jenkins\workspace\Bodycote\AutomatedTest\AutomatedTest.csproj]
05:44:41 FunctionalTests\CodedUITest1.cs(9,40): error CS0234: The type or namespace name 'UITest' does not exist in the namespace 'Microsoft.VisualStudio.TestTools' (are you missing an assembly reference?)

Solution - 
This error appears, when MSBuild does not find references added to project of specific version. 
Visual studio facilitates to go with any version of references. 
To go with any available reference, not to be very much strict about particular version, we have to set the property - "Specific Version" to false for used references. By default its true.

By setting Specific Version for all references to false, I solved the issue. MSBuild tool started compiling.








Sunday, 18 September 2016

C# Vs Java

My experience with C# after working with Java for almost 5 years is :

1. Until Java 1.8, most of advanced features available in other languages such as C# were missing.

C# features that stand out because of coding experience -
1. Lambda/LINQ (Available in Java 1.8)
2. Extension Methods ( Its awesome feature where existing classes which can not be accessed because they may belong to .Net library/third party library, can be introduced with additional new methods, without touching its code. Surprised, why java did not have this feature. Coming from Java background, makes me little strange, even sealed classes are allowed to be extended in some way through Extension Methods)

Example :
static class Extension
{

     public static String substr(this String str, int startIndex, int lastIndex)
    {
          return str.substr(startIndex,lastIndex)
     }
}

3. Detecting DataType during compilation time using var in C#
4. optional parameter by setting default value to certain parameter in C#
5. Properties for getter/setter ; Example = public string Name {get;set;}. Here get/set can be controlled. If set is not defined, then Name becomes readonly. No need for methods like GetName(), SetName(String name);
6. out parameter
7. By default methods can not be overridden (Non Virtual). Explicit use of virtual/overridden to make method overridden. [I don't feel this is good feature. By default methods should be overridden, if a class is inherited. Java does not have concept of keywords virtual which will then allow method to be overridden, though annotation @override is possible for sake of clarity ]
8. nullable datatype ;
example - int ? x = null; provides property Value to access value. Also, HasValue will let one know, if x is assigned to some value or not assigned.


I really find coding experience in C# much better than Java. Having said that, I also like to make a point, languages that come later always know the shortcomings and come with its handling to overcome known limitation/shortcomings.
That is the case with C#, which is inspired by Java and took birth to compete with Java.
On other side, Java is opensource, very much popular, has large community, technology stack is hard to beat. Most of applications are built upon Java. Next thing is unbeatable - It's platform support/cross platform. Write once, run on many different Operating Systems.