-
Notifications
You must be signed in to change notification settings - Fork 332
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mapster.Tool and DI #519
Comments
Hi @heggi, This might be a long shot, but can you try to inject IMapper? Like this: If that doesn't work, could you post a complete code sample please? |
I want use generated code for mapping with using service from DI in mapping config. Runtime mapper (standard Mapper) work good. More simple example (console app) Program.cs using Mapster;
using mapster_test;
using MapsterMapper;
using Microsoft.Extensions.DependencyInjection;
TypeAdapterConfig.GlobalSettings.Scan(AppDomain.CurrentDomain.GetAssemblies());
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(TypeAdapterConfig.GlobalSettings);
serviceCollection.AddScoped<IMapper, ServiceMapper>();
serviceCollection.AddScoped<SomeService>();
using var sp = serviceCollection.BuildServiceProvider();
var source = new Source { Name = "test" };
var mapper = sp.GetRequiredService<IMapper>();
var dest1 = mapper.Map<Dest>(source);
Console.WriteLine($"{dest1.Name} {dest1.String}"); Other classes namespace mapster_test;
public class Mapping : IRegister
{
public void Register(TypeAdapterConfig config)
{
config.NewConfig<Source, Dest>()
.Map(d => d.String, s => MapContext.Current.GetService<SomeService>().SomeValue())
.Ignore(s => s.Ignore);
}
}
public struct Dest
{
public string Name { get; set; }
public string Ignore { get; set; }
public string String { get; set; }
}
public struct Source
{
public string Name { get; set; }
}
public class SomeService
{
public string SomeValue()
{
return "Some string";
}
} Use codegen (got error). In Program.cs replace some string and got next code: // See https://aka.ms/new-console-template for more information
using Mapster;
using mapster_test;
using MapsterMapper;
using Microsoft.Extensions.DependencyInjection;
// Mapster config
TypeAdapterConfig.GlobalSettings.Scan(AppDomain.CurrentDomain.GetAssemblies());
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(TypeAdapterConfig.GlobalSettings);
serviceCollection.AddScoped<IMapper, ServiceMapper>();
serviceCollection.AddScoped<SomeService>();
// serviceCollection.AddTransient<ITestMapping, TestMapping>(); // uncomment after first build
using var sp = serviceCollection.BuildServiceProvider();
var source = new Source { Name = "test" };
var codeGenMapper = sp.GetRequiredService<ITestMapping>();
var dest2 = codeGenMapper.MapToDest(source);
Console.WriteLine($"{dest1.Name} {dest1.String}"); Add Interface using Mapster;
namespace mapster_test;
[Mapper]
public interface ITestMapping
{
Dest MapToDest(Source source);
} |
Okay, I narrowed it down to MapContext.Current being null. I will investigate some more :) |
Basically the way Mapster works now we have to choose between two evils -- ThreadStatic or AsyncLocal. Currently Mapster will use AsyncLocal in .NET 6 and .NET Standard, and ThreadStatic in older frameworks. I'm guessing that ThreadStatic will probably mostly work in ASP.NET Core 6 workloads, but will also probably break in peculiar ways if used in async contexts. As a quickfix, I can add a check for a preprocessing directive in the code linked above to force ThreadStatic to be used, which might solve some of these issues temporarily (but could also introduce new issues in different parts of the code). On a longer-term horizon, the whole MapContext code probably needs to be revamped and either implement AsyncLocal properly to transfer state properly between scopes, or require injection of the MapContext by the end user and let the end user handle state and contexts (which should be trivial with ASP.NET Core DI). I'm just thinking aloud here, but very eager to hear if there are other ideas on how to solve this. Tag: @Geestarraw |
Hello, using
without using |
Try codegen with DI.
Standard NetCore webapi template (7.0)
Program.cs
IApiMapper interface
Mapping register
Controller method
And got error:
Generated code:
If I use runtime mapper (using ServiceMapper) it works good, but if I use codegen mapper (IApiMapper) I get the error.
Mapster version 7.4.0-pre05
Mapster.Tool version 8.4.0-pre05
.Net 7.0
The text was updated successfully, but these errors were encountered: