Explicitly implemented ICustomQueryParameter fails with an ArgumentNullException
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 18.4k
- Forks
- 3.7k
- Avg merge
- 5h 8m
- Merged PRs (30d)
- 1
Description
When a custom parameter explicitly implements the ICustomQueryParameter interface Dapper throws and ArgumentNullException.
See the following example (modified from an existing Unit Test)
private class IntExplicitCustomParam : SqlMapper.ICustomQueryParameter
{
private readonly IEnumerable<int> numbers;
public IntExplicitCustomParam(IEnumerable<int> numbers)
{
this.numbers = numbers;
}
void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string name)
{
command.CommandType = CommandType.StoredProcedure;
var number_list = CreateSqlDataRecordList(command, numbers);
// Add the table parameter.
AddStructured(command, number_list);
}
}
[Fact]
public void TestExplicitTVPWithAnonymousObject()
{
try
{
connection.Execute("CREATE TYPE int_list_type AS TABLE (n int NOT NULL PRIMARY KEY)");
connection.Execute("CREATE PROC get_ints @integers int_list_type READONLY AS select * from @integers");
var nums = connection.Query<int>("get_ints", new { integers = new IntExplicitCustomParam(new int[] { 1, 2, 3 }) }, commandType: CommandType.StoredProcedure).ToList();
Assert.Equal(1, nums[0]);
Assert.Equal(2, nums[1]);
Assert.Equal(3, nums[2]);
Assert.Equal(3, nums.Count);
}
finally
{
try
{
connection.Execute("DROP PROC get_ints");
}
finally
{
connection.Execute("DROP TYPE int_list_type");
}
}
}
The issue is caused by the CreateParamInfoGenerator method using the PropertyType to find the method instead of typeof(ICustomQueryParameter), this can be seen in the following lines of code on the il.EmitCall line as GetMethod is unable to find that method:
if (typeof(ICustomQueryParameter).IsAssignableFrom(prop.PropertyType))
{
il.Emit(OpCodes.Ldloc, typedParameterLocal); // stack is now [parameters] [typed-param]
il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [custom]
il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [custom] [command]
il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [custom] [command] [name]
il.EmitCall(OpCodes.Callvirt, prop.PropertyType.GetMethod(nameof(ICustomQueryParameter.AddParameter)), null); // stack is now [parameters]
continue;
}
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in CreateParamInfoGenerator at the ICustomQueryParameter branch and inspect the il.EmitCall line shown in the issue. Use the existing TestExplicitTVPWithAnonymousObject unit test as the reproduction, then verify the stored-procedure query returns 1, 2, and 3 without throwing an ArgumentNullException.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, sql
- Domain
- database
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100