Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StructureMap DBServiceRegistry and MVC-mini-profiler?

If I use this code in each Repository class then I get SQL profiling to work but I want to move that code from each class into the class where StructureMap handles the DB.

Example of a Repository class:

public DB CreateNewContext()
    {
        var sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["connection"].ConnectionString);
        var profiledConnection = ProfiledDbConnection.Get(sqlConnection);
        return DataContextUtils.CreateDataContext<DB>(profiledConnection);
    }

    public SqlRecipeRepository(DB dataContext)
    {         
        _db = CreateNewContext();
    }

Now I want the dataContext variable to be the profiled version and so come from my DBServiceRegistry class.

Here is the DBServiceRegistry class:

public class DBServiceRegistry : Registry
{
    public DBServiceRegistry()
    {
        var sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["GetMeCooking.Data.Properties.Settings.server"].ConnectionString);
        var profiledConnection = ProfiledDbConnection.Get(sqlConnection);
        For<DB>().HybridHttpOrThreadLocalScoped().Use(() => DataContextUtils.CreateDataContext<DB>(profiledConnection));

        //Original method just had this:
        //For<DB>().HybridHttpOrThreadLocalScoped().Use(() => new DB());

    }
}

This code does not cause any errors but I don't get the SQL profiling, what am I doing wrong?

like image 369
KevinUK Avatar asked Jun 24 '11 09:06

KevinUK


1 Answers

The comment is correct, by creating the sql connection outwith the For line, you are overriding the scope command.

Far better to encapsulate the whole lot into an anonymous delegate

using System.Configuration;
using System.Data.SqlClient;
using System.Threading.Tasks;

using StructureMap;
using StructureMap.Configuration.DSL;

using Xunit;

public class DBServiceRegistry : Registry
{
    private string connString = ConfigurationManager.ConnectionStrings["GetMeCooking.Data.Properties.Settings.server"].ConnectionString;

    public DBServiceRegistry()
    {
        For<DB>().HybridHttpOrThreadLocalScoped().Use(
            () =>
                {
                    var sqlConnection = new SqlConnection(connString);
                    var profiledConnection = new StackExchange.Profiling.Data.ProfiledDbConnection(sqlConnection,  MiniProfiler.Current);
                    return DataContextUtils.CreateDataContext<DB>(profiledConnection);
                });
    }
}

You can use unit tests to verify that the scope is correct (test syntax is xunit.net)

public class DBRegistryTests : IDisposable
{
    private Container container;

    public DBRegistryTests()
    {
        // Arrange (or test setup)
        container = new Container(new DBServiceRegistry());
    }

    [Fact]
    public void ConnectionsAreSameInThread()
    {
        // Create two connections on same thread
        var conn1 = container.GetInstance<DB>();
        var conn2 = container.GetInstance<DB>();

        // Assert should be equal because hybrid thread is scope 
        // and test executes on same thread
        Assert.Equal(conn1, conn2);

        // Other assertions that connection is profiled
    }

    [Fact]
    public void ConnectionAreNotSameInDifferentThreads()
    {
        var conn1 = container.GetInstance<DB>();

        // Request second connection from a different thread 
        // (for < c# 4.0 use Thread instead of task)
        var conn2 = new Task<DB>(() => this.container.GetInstance<DB>());
        conn2.Start();
        conn2.Wait();

        // Assert that request from two different threads 
        // are not the same
        Assert.NotEqual(conn1, conn2.Result);
    }

    public void Dispose()
    {
        // Test teardown
        container.Dispose();
    }
}
like image 103
Scott Mackay Avatar answered Oct 18 '22 20:10

Scott Mackay