Skip to content

Weird Behavior with Class + Primary Constructor vs Record Type #1119

@ardalis

Description

@ardalis

Had a weird behavior today. ChatGPT solved it but I don't know exactly why the behavior was how it was.

Situation

I had a working set of code with basically 2 projects (web and usecases). I refactored it into 4 projects so I could share some of the base types involved and apply a modular monolith approach. After the refactor, I made sure to have MediatR scan all of the assemblies in play, but I was getting an error on a .Send() call.

"No service for type 'MediatR.IRequestHandler`2[myQuery,myResult]' has been registered." in System.Private.CoreLib.dll

The Query (which worked fine before!)

public class TasksByAssignedIdQuery(int employeeId) : IQuery<Result<List<TaskDto>>>
{
	public int EmployeeId { get; set; } = employeeId;
}

The Diagnosis

ChatGPT said:

By writing it as:

public class TasksByAssignedIdQuery(int employeeId) : IQuery<...>

you've created a class with a primary constructor, which was only added in C# 12 and does not behave like a record — it does not auto-generate value-based equality, and more importantly:

It does not automatically make the query implement IRequest unless everything aligns perfectly — and in practice, it often does not work well with frameworks expecting traditional constructor injection or reflection.

Use a record instead.

The Fix

I changed the message type to:

public record TasksByAssignedIdQuery(int EmployeeId) : IQuery<Result<List<TaskDto>>>
{
	//public int EmployeeId { get; set; } = employeeId;
}

and indeed that fixed it. My question is, why? And is this a bug in MediatR that it doesn't handle message types with primary constructors in some scenarios?

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions