Closed cecbr closed 5 years ago
I am also experiencing this error. AutoMapper worked with Lamar 2.x, but began failing after updating Lamar to 3.0.1, and 3.1.0 also has the same problem.
I currently use Lamar and AutoMapper in a .NET Core 2.2 web app with no problems. How are you registering AutoMapper?
I'm using the AutoMapper.Extensions.Microsoft.DependencyInjection NuGet package and calling the following at the end of my Startup.ConfigureServices(..) method:
services.AddAutoMapper(typeof(Startup).Assembly);
I've done a bit more research into this and the issue seems to be related to registering a service using a manually created instance of ServiceDescriptor with an inline factory lambda. Here's how the extension method above registers the IMapper interface:
services.Add(new ServiceDescriptor(
typeof(IMapper),
sp => new Mapper(sp.GetRequiredService<IConfigurationProvider>(), sp.GetService),
serviceLifetime));
Because the factory parameter of ServiceDescriptor is of type Func<IServiceProvider, object>
, the lambda above that creates the new Mapper has return type object
but the service type is IMapper
. This is where the error in Lamar arises as it's trying to assign the result of calling the implementation factory function to a variable of type IMapper.
This can be fixed worked around by changing the AutoMapper registration like so:
Func<IServiceProvider, Mapper> factory = sp => new Mapper(sp.GetRequiredService<IConfigurationProvider>(), sp.GetService);
services.Add(new ServiceDescriptor(typeof(IMapper), factory, serviceLifetime));
With this change, the lambda is created with the correct type and the assignment works. I don't think this is really a problem with AutoMapper though as it is the compiler which is throwing away useful type information. Instead, I've tried adding a 'convert' expression to InlineLambdaCreationFrame
in Lamar if the factory method result type does not match the service type.
var invokeMethod = _setter.InitialValue.GetType().GetMethod("Invoke");
var invoke = Expression.Call(Expression.Constant(_setter.InitialValue), invokeMethod, scope);
// Added cast to convert factory method result to the service type
Expression cast = invoke;
if (invoke.Type != variableExpr.Type)
{
cast = Expression.Convert(invoke, variableExpr.Type);
}
definition.Body.Add(Expression.Assign(variableExpr, cast));
This also fixes the problem and will cover potentially more cases than just AutoMapper.
If this seems reasonable, let me know and I can prepare a pull request. Are there any tests for registering services through the .NET API as opposed to the Lamar native API?
Please,
I want to convert my StructureMap based project to Lamar.
All my classes that are using IMAPPER into constructor failed with message "Expression of type 'System.Object' cannot be used for assignment to type 'AutoMapper.IMapper'".
Can you help me?
Carlos. WebApplication22.zip