Wednesday, October 20, 2010

Solution to ‘No symbols are loaded for any call stack frame’ error

I’ve been working on a .NET 3.5 Framework (VS 2008) solution for months, and all of a sudden I started getting a series of very mysterious error and warning messages while trying to debug a class library in my solution.  I’m posting my findings because I couldn’t find a viable solution after much Google searching.

MessageBox:  “No symbols are loaded for any call stack frame. The source code cannot be displayed.”

Output window: “Stepping over method without symbols”

Output window: “Stepping over non-user code”

The code I was trying to debug was a class library of my own code within my solution.  I had not changed any of my Options > Debugging settings.  I tried a variety of suggested fixes, all without success, including a complete rebuild of my solution (delete, restore from source code control, rebuild), various Options > Debugging settings changes (such as uncheck the “Enable Just My Code” option), and so on.

I finally determined the source of my problem.  I had made a code change to use Reflection to load one of my class library assemblies into a static method.  It was that very assembly that I was no longer able to debug.  The solution was to create a new class library containing only the classes/methods that I needed for the reflection call, and then all the rest of my original class library was again available for debugging because that code was no longer included in the Reflection call.

I hope others find this solution to be helpful!

Wednesday, January 20, 2010

Unit Tests for DataReaderHelper Class

Here are the unit tests I wrote for the DataReaderHelper class described in yesterday’s post.  These unit tests are written using NUnit 2.5.2 and Rhino.Mocks 3.6.  I followed Roy Osherove’s naming standards for unit tests.  I found help with the Rhino.Mocks WhenCalled method from Graham Nash’s blog.

using System;
using NUnit.Framework;
using Rhino.Mocks;
using System.Data;
using DataAccessLibrary.Common;
using System.Collections.Generic;

[TestFixture]
public class DataReaderHelperTests
{
#region Variables and Constants
private MockRepository _mocks;
private DataReaderHelper.CreateConnection _mockCreateConnection;
private IDbConnection _mockConnection;
private IDbCommand _mockCommand;
private IDataReader _mockReader;
private DataReaderHelper.ReadDatabaseValue<object> _mockDelegate;
private object _obj;
#endregion


#region
Setup

[SetUp]
public void InitTest()
{
_mocks = new MockRepository();
_mockCreateConnection = _mocks.StrictMock<DataReaderHelper.CreateConnection>();
_mockConnection = _mocks.StrictMock<IDbConnection>();
_mockCommand = _mocks.StrictMock<IDbCommand>();
_mockReader = _mocks.StrictMock<IDataReader>();
_mockDelegate = _mocks.StrictMock<DataReaderHelper.ReadDatabaseValue<object>>();
_obj = null;
}

#endregion


#region
Unit Tests

[Test]
public void GetData_ListInt_ReturnsFromDelegateUsingReader()
{
DataReaderHelper.CreateConnection stubCreateConnection = MockRepository.GenerateStub<DataReaderHelper.CreateConnection>();
IDbConnection stubConnection = MockRepository.GenerateStub<IDbConnection>();
IDbCommand stubCommand = MockRepository.GenerateStub<IDbCommand>();
IDataReader stubReader = MockRepository.GenerateStub<IDataReader>();
DataReaderHelper.ReadDatabaseValue<List<int>> stubDelegate =
MockRepository.GenerateStub<DataReaderHelper.ReadDatabaseValue<List<int>>>();
List<int> testList = new List<int>();

stubCreateConnection.Stub(get => get()).Return(stubConnection);
stubConnection.Stub(conn => conn.CreateCommand()).Return(stubCommand);
stubCommand.Stub(comm => comm.ExecuteReader()).Return(stubReader);
stubReader.Stub(rdr => rdr.Read()).Return(true).Repeat.Times(2);
stubReader.Stub(rdr => rdr.Read()).Return(false).Repeat.Once();
stubReader.Stub(rdr => rdr.GetInt32(0)).Return(2).Repeat.Once();
stubReader.Stub(rdr => rdr.GetInt32(0)).Return(4).Repeat.Once();
stubDelegate.Stub(del => del(stubReader, ref testList))
.WhenCalled(invocation => testList.Add(stubReader.GetInt32(0))).Repeat.Times(2).OutRef(testList);

DataReaderHelper.GetData<List<int>>(stubCreateConnection, "sql", stubDelegate, ref testList);

Assert.That(testList.Count, Is.EqualTo(2));
Assert.That(testList[0], Is.EqualTo(2));
Assert.That(testList[1], Is.EqualTo(4));
}

[Test]
public void GetData_CreateConnectionException_NoDisposals()
{
using (_mocks.Ordered())
{
Expect.Call(_mockCreateConnection()).Throw(MockRepository.GenerateStub<Exception>()).Repeat.Once();
Expect.Call(_mockConnection.State).Repeat.Never();
Expect.Call(() => _mockConnection.Open()).Repeat.Never();
Expect.Call(_mockConnection.CreateCommand()).Return(_mockCommand).Repeat.Never();
Expect.Call(_mockCommand.CommandText = "sql").Repeat.Never();
Expect.Call(_mockCommand.ExecuteReader()).Return(_mockReader).Repeat.Never();
Expect.Call(_mockReader.Read()).Repeat.Never();
Expect.Call(() => _mockDelegate(_mockReader, ref _obj)).Repeat.Never();
Expect.Call(_mockReader.GetValue(0)).Repeat.Never();
Expect.Call(() => _mockConnection.Dispose()).Repeat.Never();
Expect.Call(() => _mockCommand.Dispose()).Repeat.Never();
Expect.Call(() => _mockReader.Dispose()).Repeat.Never();
}
_mocks.ReplayAll();
VerifyBehavior();
}

[Test]
public void GetData_ConnectionOpenException_DisposesOfConnection()
{
using (_mocks.Ordered())
{
Expect.Call(_mockCreateConnection()).Return(_mockConnection).Repeat.Once();
Expect.Call(_mockConnection.State).Return(ConnectionState.Closed).Repeat.Once();
Expect.Call(() => _mockConnection.Open()).Throw(MockRepository.GenerateStub<Exception>()).Repeat.Once();
Expect.Call(_mockConnection.CreateCommand()).Return(_mockCommand).Repeat.Never();
Expect.Call(_mockCommand.CommandText = "sql").Repeat.Never();
Expect.Call(_mockCommand.ExecuteReader()).Return(_mockReader).Repeat.Never();
Expect.Call(_mockReader.Read()).Repeat.Never();
Expect.Call(() => _mockDelegate(_mockReader, ref _obj)).Repeat.Never();
Expect.Call(_mockReader.GetValue(0)).Repeat.Never();
Expect.Call(() => _mockConnection.Dispose()).Repeat.Once();
Expect.Call(() => _mockCommand.Dispose()).Repeat.Never();
Expect.Call(() => _mockReader.Dispose()).Repeat.Never();
}
_mocks.ReplayAll();
VerifyBehavior();
}

[Test]
public void GetData_ConnectionCreateCommandException_DisposesOfConnection()
{
using (_mocks.Ordered())
{
Expect.Call(_mockCreateConnection()).Return(_mockConnection).Repeat.Once();
Expect.Call(_mockConnection.State).Return(ConnectionState.Closed).Repeat.Once();
Expect.Call(() => _mockConnection.Open()).Repeat.Once();
Expect.Call(_mockConnection.CreateCommand()).Return(_mockCommand)
.Throw(MockRepository.GenerateStub<Exception>()).Repeat.Once();
Expect.Call(_mockCommand.CommandText = "sql").Repeat.Never();
Expect.Call(_mockCommand.ExecuteReader()).Return(_mockReader).Repeat.Never();
Expect.Call(_mockReader.Read()).Repeat.Never();
Expect.Call(() => _mockDelegate(_mockReader, ref _obj)).Repeat.Never();
Expect.Call(_mockReader.GetValue(0)).Repeat.Never();
Expect.Call(() => _mockConnection.Dispose()).Repeat.Once();
Expect.Call(() => _mockCommand.Dispose()).Repeat.Never();
Expect.Call(() => _mockReader.Dispose()).Repeat.Never();
}
VerifyBehavior();
}

[Test]
public void GetData_CommandExecuteReaderException_DisposesOfConnectionAndCommand()
{
using (_mocks.Ordered())
{
Expect.Call(_mockCreateConnection()).Return(_mockConnection).Repeat.Once();
Expect.Call(_mockConnection.State).Return(ConnectionState.Closed).Repeat.Once();
Expect.Call(() => _mockConnection.Open()).Repeat.Once();
Expect.Call(_mockConnection.CreateCommand()).Return(_mockCommand).Repeat.Once();
Expect.Call(_mockCommand.CommandText = "sql").Repeat.Once();
Expect.Call(_mockCommand.ExecuteReader()).Return(_mockReader)
.Throw(MockRepository.GenerateStub<Exception>()).Repeat.Once();
Expect.Call(_mockReader.Read()).Repeat.Never();
Expect.Call(() => _mockDelegate(_mockReader, ref _obj)).Repeat.Never();
Expect.Call(_mockReader.GetValue(0)).Repeat.Never();
Expect.Call(() => _mockConnection.Dispose()).Repeat.Once();
Expect.Call(() => _mockCommand.Dispose()).Repeat.Once();
Expect.Call(() => _mockReader.Dispose()).Repeat.Never();
}
VerifyBehavior();
}

[Test]
public void GetData_ReaderReadException_DisposesOfConnectionAndCommandAndReader()
{
using (_mocks.Ordered())
{
Expect.Call(_mockCreateConnection()).Return(_mockConnection).Repeat.Once();
Expect.Call(_mockConnection.State).Return(ConnectionState.Closed).Repeat.Once();
Expect.Call(() => _mockConnection.Open()).Repeat.Once();
Expect.Call(_mockConnection.CreateCommand()).Return(_mockCommand).Repeat.Once();
Expect.Call(_mockCommand.CommandText = "sql").Repeat.Once();
Expect.Call(_mockCommand.ExecuteReader()).Return(_mockReader).Repeat.Once();
Expect.Call(_mockReader.Read()).Throw(MockRepository.GenerateStub<Exception>()).Repeat.Once();
Expect.Call(() => _mockDelegate(_mockReader, ref _obj)).Repeat.Never();
Expect.Call(_mockReader.GetValue(0)).Repeat.Never();
Expect.Call(() => _mockConnection.Dispose()).Repeat.Once();
Expect.Call(() => _mockCommand.Dispose()).Repeat.Once();
Expect.Call(() => _mockReader.Dispose()).Repeat.Once();
}
VerifyBehavior();
}

[Test]
public void GetData_ReaderGetValueException_DisposesOfConnectionAndCommandAndReader()
{
using (_mocks.Ordered())
{
Expect.Call(_mockCreateConnection()).Return(_mockConnection).Repeat.Once();
Expect.Call(_mockConnection.State).Return(ConnectionState.Closed).Repeat.Once();
Expect.Call(() => _mockConnection.Open()).Repeat.Once();
Expect.Call(_mockConnection.CreateCommand()).Return(_mockCommand).Repeat.Once();
Expect.Call(_mockCommand.CommandText = "sql").Repeat.Once();
Expect.Call(_mockCommand.ExecuteReader()).Return(_mockReader).Repeat.Once();
Expect.Call(_mockReader.Read()).Return(true).Repeat.Once();
Expect.Call(() => _mockDelegate(_mockReader, ref _obj))
.WhenCalled(invocation => _obj = _mockReader.GetValue(0)).OutRef(_obj).Repeat.Once();
Expect.Call(_mockReader.GetValue(0)).Throw(MockRepository.GenerateStub<Exception>()).Repeat.Once();
Expect.Call(() => _mockConnection.Dispose()).Repeat.Once();
Expect.Call(() => _mockCommand.Dispose()).Repeat.Once();
Expect.Call(() => _mockReader.Dispose()).Repeat.Once();
}
VerifyBehavior();
}

[Test]
public void GetData_NoExceptionsConnectionClosed_AllBehaviorIsCorrect()
{
using (_mocks.Ordered())
{
Expect.Call(_mockCreateConnection()).Return(_mockConnection).Repeat.Once();
Expect.Call(_mockConnection.State).Return(ConnectionState.Closed).Repeat.Once();
Expect.Call(() => _mockConnection.Open()).Repeat.Once();
Expect.Call(_mockConnection.CreateCommand()).Return(_mockCommand).Repeat.Once();
Expect.Call(_mockCommand.CommandText = "sql").Repeat.Once();
Expect.Call(_mockCommand.ExecuteReader()).Return(_mockReader).Repeat.Once();
Expect.Call(_mockReader.Read()).Return(true).Repeat.Once();
Expect.Call(() => _mockDelegate(_mockReader, ref _obj))
.WhenCalled(invocation => _obj = _mockReader.GetValue(0)).OutRef(_obj).Repeat.Once();
Expect.Call(_mockReader.GetValue(0)).Return(new object()).Repeat.Once();
Expect.Call(_mockReader.Read()).Return(false).Repeat.Once();
Expect.Call(() => _mockConnection.Dispose()).Repeat.Once();
Expect.Call(() => _mockCommand.Dispose()).Repeat.Once();
Expect.Call(() => _mockReader.Dispose()).Repeat.Once();
}
VerifyBehavior();
}

[Test]
public void GetData_NoExceptionsConnectionAlreadyOpen_AllBehaviorIsCorrect()
{
using (_mocks.Ordered())
{
Expect.Call(_mockCreateConnection()).Return(_mockConnection).Repeat.Once();
Expect.Call(_mockConnection.State).Return(ConnectionState.Open).Repeat.Once();
Expect.Call(_mockConnection.CreateCommand()).Return(_mockCommand).Repeat.Once();
Expect.Call(_mockCommand.CommandText = "sql").Repeat.Once();
Expect.Call(_mockCommand.ExecuteReader()).Return(_mockReader).Repeat.Once();
Expect.Call(_mockReader.Read()).Return(true).Repeat.Once();
Expect.Call(() => _mockDelegate(_mockReader, ref _obj))
.WhenCalled(invocation => _obj = _mockReader.GetValue(0)).OutRef(_obj).Repeat.Once();
Expect.Call(_mockReader.GetValue(0)).Return(new object()).Repeat.Once();
Expect.Call(_mockReader.Read()).Return(false).Repeat.Once();
Expect.Call(() => _mockConnection.Dispose()).Repeat.Once();
Expect.Call(() => _mockCommand.Dispose()).Repeat.Once();
Expect.Call(() => _mockReader.Dispose()).Repeat.Once();
}
VerifyBehavior();
}

#endregion


#region
Helper Methods

// common unit test code
private void VerifyBehavior()
{
_mocks.ReplayAll();
try
{
DataReaderHelper.GetData<object>(_mockCreateConnection, "sql", _mockDelegate, ref _obj);
}
catch (Exception) { }
finally
{
_mocks.VerifyAll();
}
}

#endregion
}

Tuesday, January 19, 2010

A Generic Database Reader Class

I’ve been doing a lot of CRUD-type work recently against a reporting database.  The application does not utilize an ORM because of the complexity of selection SQL, so I’ve been designing a custom ORM framework.

One of my top priorities is to route all database access through a single class, so I developed this generic database reader.  The code is shown below.

The generic reader class is DataReaderHelper.  It has a GetData generic method that accepts a generic delegate and returns read data using a referenced generic parameter.  This combination of generics and delegates provides an exceptionally flexible class that I can use for any database reads, ensuring that my connections are centrally managed.

The code sample below also provides sample usage in the Mapper class.

// generic class for reading database data
public class DataReaderHelper
{
// generic delegate passed into the GetData method to manipulate the IDataReader object
public delegate void ReadDatabaseValue<T>(IDataReader reader, ref T businessObject);
// delegate is passed into the GetData method to create a new connection
public delegate IDbConnection CreateConnection();

public static void GetData<T>(CreateConnection createConnection, string sql,
ReadDatabaseValue<T> readDelegate, ref T businessObject)
{
IDbConnection dbConnection = null;
IDbCommand command = null;
IDataReader reader = null;
try
{
dbConnection = createConnection();
if (dbConnection.State != ConnectionState.Open) { dbConnection.Open(); }
command = dbConnection.CreateCommand();
command.CommandText = sql;
reader = command.ExecuteReader();
while (reader.Read())
{
readDelegate(reader, ref businessObject);
}
}
catch { throw; }
finally
{
if (dbConnection != null) dbConnection.Dispose();
if (command != null) command.Dispose();
if (reader != null) reader.Dispose();
}
}
}

// provides the database connection delegate
internal class ConnectionFactory
{
internal static SqlConnection GetConnection()
{
try
{
return new SqlConnection(ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString);
}
catch { throw; }
}
}

// provides delegates used to read data
internal class DataReaderFactory
{
internal static void ReadFirstColumnIntoString(IDataReader reader, ref string value)
{
value = reader.GetString(0);
}
internal static void ReadFirstColumnIntoStringCollection(IDataReader reader,
ref StringCollection value)
{
value.Add(reader.GetString(0));
}
}

// example DataReaderHelper usage
internal class Mapper
{
internal static string DemoGetString()
{
string demo = null;
DataReaderHelper.GetData<string>(ConnectionFactory.GetConnection, "my sql",
DataReaderFactory.ReadFirstColumnAsValue, ref demo);
return demo;
}

internal static StringCollection DemoGetStringCollection()
{
StringCollection demo = null;
DataReaderHelper.GetData<StringCollection>(ConnectionFactory.GetConnection, "my sql",
DataReaderFactory.ReadFirstColumnAsInt32IdList, ref demo);
return demo;
}
}