Click to Rate and Give Feedback
MSDN
MSDN Library
.NET Development
.NET Framework 3.5
SqlConnection Class
 InfoMessage Event

  Switch on low bandwidth view
This page is specific to
Microsoft Visual Studio 2008/.NET Framework 3.5

Other versions are also available for the following:
.NET Framework Class Library
SqlConnection..::.InfoMessage Event

Occurs when SQL Server returns a warning or informational message.

Namespace:  System.Data.SqlClient
Assembly:  System.Data (in System.Data.dll)
Visual Basic (Declaration)
Public Event InfoMessage As SqlInfoMessageEventHandler
Visual Basic (Usage)
Dim instance As SqlConnection
Dim handler As SqlInfoMessageEventHandler

AddHandler instance.InfoMessage, handler
C#
public event SqlInfoMessageEventHandler InfoMessage
Visual C++
public:
 event SqlInfoMessageEventHandler^ InfoMessage {
    void add (SqlInfoMessageEventHandler^ value);
    void remove (SqlInfoMessageEventHandler^ value);
}
JScript
JScript does not support events.

Clients that want to process warnings or informational messages sent by the server should create an SqlInfoMessageEventHandler delegate to listen to this event.

The InfoMessage event occurs when a message with a severity of 10 or less is returned by SQL Server. Messages that have a severity between 11 and 20 raise an error and messages that have a severity over 20 causes the connection to close. For more information on SQL Server error levels, see "Database Engine Error Severities" in SQL Server 2005 Books Online.

For more information and an example, see Connection Events (ADO.NET).

Windows 7, Windows Vista, Windows XP SP2, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP Starter Edition, Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, Windows Server 2000 SP4, Windows Millennium Edition, Windows 98, Windows CE, Windows Mobile for Smartphone, Windows Mobile for Pocket PC

The .NET Framework and .NET Compact Framework do not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.

.NET Framework

Supported in: 3.5, 3.0, 2.0, 1.1, 1.0

.NET Compact Framework

Supported in: 3.5, 2.0, 1.0
Tags What's this?: Add a tag
Community Content   What is Community Content?
Add new content RSS  Annotations
Using InfoMessage Event of SqlConnection object      balamurali balaji   |   Edit   |   Show History

This article explores the usage of InfoMessage event of SqlConnection and how it is useful in real-world applications. It also examines a small loop-hole when it is used along with transactions.

Introduction

ADO.NET SqlConnecion object has InfoMessage event that would get raised when any informational message or warning returned by the Sql Server Database. To be precise, it is raised for errors with severity levels less than 10 and those with severity levels 11 or above causes an exception to be thrown. This event has SqlInfoMessageEventArgs object as an argument that contains Error property. This Error object is a collection of errors with error number and text besides giving us the information about the database, stored procedure and line numbers where the error occurs.
InfoMessage event works in synch with the SqlConnection’s FireInfoMessageEventOnUserErrors property which takes a Boolean value, true or false. If this property is set to true, InfoMessage event is handled and our application would wait for warnings and errors with severity levels from 11 or more from Sql Server Database.

The main advantage of using this event in our applications is really interesting and let me narrate few circumstances where it could help us out.

1. Assume that we are performing a series of Execute operations (ExecuteNonQuery or ExecuteReader) using SqlCommand objects that are common to a single SqlConnection object without using transactions. Problem is that when any one of the command doesn’t get executed for some reason, we are forced to abandon the rest of the operations by simply notifying the user of the nature of Exception being thrown out.

2. Assume that we perform multiple Sql command executions with-in a transaction; InfoMessage event can still be raised and helps us to override the transactional behaviour. This is the most unfavourable situation one wants to implement in their applications. Overriding the transactional behavior would surely dis-integrate the ACID properties of a transaction.

Let us examine both the scenarios one by one.

Scenario 1:

The following example uses two tables’ product and productdetails in the sales database. The code below do not use transactions.
SqlConnection conn = new SqlConnection(@"Data Source=.\SQLEXPRESS;AttachDbFilename=D:\Users\bala\Documents\sales.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True");
conn.InfoMessage += new SqlInfoMessageEventHandler(conn_InfoMessage);
conn.FireInfoMessageEventOnUserErrors = true;
conn.Open();

try
{
// sql insert for product row
string myDataCmds = "insert into product (productid, prodname, desc) values ('abc', 'Driver Kit', 'Kit useful for driver functions')";
SqlCommand comm = new SqlCommand(myDataCmds, conn);
int rows = comm.ExecuteNonQuery();
if (rows > 0)
MessageBox.Show("A row inserted into product table");
else
MessageBox.Show("Product not inserted in the product table");
myDataCmds = "insert into productdetail (productid, model, manufacturer) values (101, 'ModelA', 'Simpson Co.')";
comm = new SqlCommand(myDataCmds, conn);
rows = comm.ExecuteNonQuery();
if (rows > 0)
MessageBox.Show("A row inserted into productdetail table");
else
MessageBox.Show("Detail not inserted in the productdetail table");
}
catch (Exception e)
{
MessageBox.Show("Exception thrown: " + e.Message);
}

conn.Close();
}

static void conn_InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
MessageBox.Show("InfoMessage Handled Error Level-" + e.Errors[0].Class.ToString() + ":" + e.Message);

}
There are few things we need to notice here in the above code.
1. This example does not use transaction objects and it just performs two insert operations one by one.
2. Because the FireInfoMessageEventOnUserErrors property is set to true, due to the error (invalid type of data passed in the insert statement) in the first Sql statement, second Sql Statement only gets executed. As a result, product row is not inserted; productdetails row is inserted.
3. On the other hand, if the FireInfoMessageEventOnUserErrors property is set to false, due to the error (invalid type of data passed in the insert statement) in the first Sql statement, an exception is thrown stopping the further proceedings of the program. As a result, both the product row and productdetails row is not inserted.

Scenario 2:

To include transactional capability in the above example, we may have to add commit and rollback operations in the code as below. As expected, there are changes in the program results too.
SqlConnection conn = new SqlConnection(@"Data Source=.\SQLEXPRESS;AttachDbFilename=D:\Users\bala\Documents\sales.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True");
conn.InfoMessage += new SqlInfoMessageEventHandler(conn_InfoMessage);
conn.FireInfoMessageEventOnUserErrors = true;
conn.Open();
SqlTransaction tran = conn.BeginTransaction();

try
{
// sql insert for product row
string myDataCmds = "insert into product (productid, prodname, desc) values ('abc', 'Driver Kit', 'Kit useful for driver functions')";
SqlCommand comm = new SqlCommand(myDataCmds, conn);
comm.Transaction = tran;
int rows = comm.ExecuteNonQuery();
if (rows > 0)
MessageBox.Show("A row inserted into product table");
else
MessageBox.Show("Product not inserted in the product table");
myDataCmds = "insert into productdetail (productid, model, manufacturer) values (101, 'ModelA', 'Simpson Co.')";
comm = new SqlCommand(myDataCmds, conn);
comm.Transaction = tran;
rows = comm.ExecuteNonQuery();
if (rows > 0)
MessageBox.Show("A row inserted into productdetail table");
else
MessageBox.Show("Detail not inserted in the productdetail table");
tran.Commit();
}
catch (InvalidOperationException ioe)
{
MessageBox.Show("Exception thrown but transaction performed partially! ");
}
catch (Exception e)
{
MessageBox.Show("Exception thrown: " + e.Message);
tran.Rollback();
}

conn.Close();
}

static void conn_InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
MessageBox.Show("InfoMessage Handled Error Level-" + e.Errors[0].Class.ToString() + ":" + e.Message);

}
In the transactional scenario, we may have to look into following behaviour of the code.

1. When the FireInfoMessageEventOnUserErrors property is set to false, due to the error (invalid type of data passed in the insert statement) in the first Sql statement, an exception is thrown stopping the further proceedings of the program. As a result, both the product row and productdetails row is not inserted.

2. On the other hand, when the FireInfoMessageEventOnUserErrors property is set to true, due to the error (invalid type of data passed in the insert statement) in the first Sql statement, second Sql Statement gets executed overriding the default nature of transaction. It tries to rollback the committed change which is not allowed and hence InvalidOperationException is thrown. But as for as the database changes are concerned, it is similar to the one we saw in the non-transactional execution. If we remove the catch block for InvalidOperationException, the application hangs and need to be stopped manually.

Conclusion

This program is tested and run in recently released version of Visual Studio 2008 Beta2. The inclusion of FireInfoMessageEventOnUserErrors property in the SqlConnection is really useful for performing multiple Sql commands in non-transactional mode. In a transactional mode, it behaves abnormally forcing the developers to include an additional Exception check; When the final product comes out, I hope the strange behaviour is modified and new improvements be made. More importantly, developers are looking for a much cleaner way to override Sql transactions.

Processing
© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Page view tracker