1

I have spent the last couple of days refactoring a project. This project uses Dapper and the SqlMapper functionality to map the result of Sql queries onto objects. As part of my refactoring I moved some of the objects to a separate assembly and that's where things went a bit awry.

    public async Task<IEnumerable<HL7Control>> GetHl7ControlRecords()
    {
        _log.Info("Obtaining a list of required transfer service agents.");

        var agentList = StatementBuilder.BuildDapperGetAllHl7ControlRecords();

        return await SqlMapper.QueryAsync<HL7Control>(_db, agentList.Sql,agentList.Param);
    }

This kept throwing a RuntimeBinder exception saying that 'QueryAsync<>' was not a member of SqlMapper. This is code that has been fine for over six months.

I've finally tracked down the problem and I'd appreciate some thoughts from others. The 'solution' is to replace project references to the assembly containing 'HL7Control' with browse references (ie; <Project Reference Include...> becomes <Reference Include...> in the project file.

The solution is being built by vs2015 and targets .NET4.6 except for the new assembly that targets .NET4.0.

Any thoughts welcome as I'm not happy when I don't understand a 'fix'.

Thanks.

Update 1. Some more info. I neglected to mention that agentList is not only badly named but is actually a class:

public class DapperStatement
{
    public string Sql { get;  }

    public dynamic Param { get; }

    public DapperStatement(string sql, dynamic param)
    {
        Sql = sql;
        Param = param;
    }
}

And it's because Param is a dynamic that the RuntimeBinder is involved. Now I know that dynamic doesn't cross assembly boundaries and that is something else I had to address during this refactoring. But in this case although DapperStatement is defined in a different assembly the object instance is not passing across an assembly boundary. And DapperStatement always was in another assembly to where it's used.

Also note that SqlMapper.Query<> always works so apparently being async is a factor in this.

I also rebooted my machine overnight and rebuilt from scratch and the issue remains.

Oh and changing the new assembly to be .NET4.6 doesn't change anything (other than breaking the external client project that it is being developed for, lol).

Update 2. The problem seems to be specific to Dapper. Explaining further requires a bit more detail so here goes: Originally we had one solution with multiple projects. One of these projects (project A) used Dapper to access and manipulate some SQL tables. Several other projects then depended on that.

Meanwhile another external project needed to access the same tables but was using DevExpress XPO. So what I've been doing this week is moving things around so that the tables are no longer access by XPO. The original Dapper code does far more table work so we decided to only hive off the stuff that the external project needs. That leaves us with two assemblies that use Dapper to manipulate a SQL database. It looks that the problem I'm seeing is that in that scenario having a project reference rather than a browse reference screws things up.

This morning I've removed the Dapper reference from the new project and suddenly the old code works again with a browser reference (as long as avoid calls that I've had to hack).

Andrue Cope
  • 249
  • 3
  • 8

3 Answers3

2

While encountering this issue with Dapper in VS 2017, I had to do the following:

  • under project using Dapper right-click "Manage NuGet Packages", select Dapper, then in the install/uninstall side of screen, expand Options and change "Install and Update Options - Dependency behavior" to "Highest". This got the latest version of Dapper.dll appearing in the project's bin folder (instead of the version from 2012).
  • in App.config of the top level project including the library containing the Dapper dependency, remove the following section (this article gave me the hint - https://blogs.msdn.microsoft.com/bclteam/p/asynctargetingpackkb/ Issue #6)

    <dependentAssembly>
        <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
    </dependentAssembly>
    

With these two changes, my application started working correctly with my custom assemblies targeting .Net Framework v4.7.1

Jubilsoft-Scott
  • 172
  • 1
  • 10
1

Sounds like you've gone from 1 sln to 2. I've had some troubles with 2 sln files including the same projects when NuGet in involved. The HintPath is a relative to the proj and can get screwy depending on the folder structure.

If:

Source -app1 --sln1 ---proj1WithNugetDep -app2 --sln2 ---proj2WithSameNugetDep

Then:

I've found that replacing with "$(SolutionFolder)/packages" usually works in this scenario.

phil v
  • 191
  • 1
  • 4
0

I'm now pretty sure it's down to the framework mismatch. When project references are used the Dapper assembly copied into the executable folder(s) is for .NET4 and the .NET4.6 code apparently chokes on this. When a browse reference is used the .NET4.6 Dapper assembly is copied instead and everything is fine.

Andrue Cope
  • 249
  • 3
  • 8