How to tell AutoMapper 5 to use StructureMap for constructing services without creating a bootstrapping problem, i.e. new MapperConfiguration(cfg => cfg.ConstructServicesUsing(some_IContainer)) when the config is being made via StructureMap?
Custom resolvers need a service locator to be used by AutoMapper, but IContainer does not exist yet while AutoMapper is being initialised inside a StructureMap registry. The static ObjectFactory.Container has been deprecated in StructureMap, so I have a lazy ObjectFactory:
public static class ObjectFactory
{
private static readonly Lazy<Container> _containerBuilder =
new Lazy<Container>(defaultContainer, LazyThreadSafetyMode.ExecutionAndPublication);
public static IContainer Container
{
get { return _containerBuilder.Value; }
}
private static Container defaultContainer()
{
return new Container(x =>
{
x.AddRegistry<MyRegistry>(); // AutoMapper is configured here
});
}
}
I can't reference ObjectFactory.Container from an AutoMapper Profile because I get a stack overflow or "Value referenced inside lazy factory".
Is there a way to tack on .ConstructUsing(some_IContainer) after configuring AutoMapper?
You can leverage the container - even if it's not built yet - by using lamdba-based registrations.
Your registration of MapperConfiguration could look something like:
class MyRegistry : Registry
{
public MyRegistry()
{
For<MapperConfiguration>()
.Use("Use StructureMap context to resolve AutoMapper services", ctx =>
{
return new MapperConfiguration(config =>
{
config.ConstructServicesUsing(type => ctx.GetInstance(type));
});
});
}
}
This way you avoid the chicken-and-egg problem.
WARNING
I haven't tested this code, and I'm not familiar with StructureMap.
Related
I have a Redis store similar to this one. My problem is, since I am using .Net Core, on line 15, I should use configuration object that I normally inject in the constructor.
However, one cannot inject the configuration object in the static constructor, as static constructor should be parameterless in C#.
I tried adding a static method to initialise the config object, but then the constructor throws NullReferenceException because obviously the ctor is still called first, before the Init method, and it needs the config object... so what to do?
Doesn't seem like a good workaround.
Instead of doing all that work with statics and trying to get it to work (hint: it'd never work with a static constructor), I'd suggest you to move to newer patterns and use DI correctly.
If you don't really need the lazyness, this is as simple as injecting IConnectionMultiplexer:
services.AddScoped<IConnectionMultiplexer>(s => ConnectionMultiplexer.Connect(configuration["someSettings"]));
If you do need the lazyness:
// public interface IRedisStore { IConnectionMultiplexer RedisConnection { get; } }
public class RedisStore : IRedisStore
{
private readonly Lazy<ConnectionMultiplexer> LazyConnection;
public RedisStore(IConfiguration configuration)
{
var configurationOptions = new ConfigurationOptions
{
EndPoints = { configuration["someSettings"] }
};
LazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(configurationOptions));
}
public IConnectionMultiplexer RedisConnection => LazyConnection.Value;
}
and you'd inject it with:
services.AddScoped<IRedisStore, RedisStore>());
I'm using SimpleInjector 4 and FluentValidation 7. My AbstractValidators have a dependency on my DbContext.
public class Validator : AbstractValidator<LocationModel>
{
public LocationModelValidator(IReadOnlyRepository repository)
{
// Check the database to see if this location is already present
RuleFor(x => x.LocationId).Must(x => !repository.Location.Any(i => i.LocationId == x)).WithMessage("A Location with this ID already exists.");
}
}
My composition root looks as follows:
var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
container.Register<IReadOnlyRepository, LocationDbContext>(Lifestyle.Scoped);
container.Register<IValidatorFactory>(() => new ServiceProviderValidatorFactory(GlobalConfiguration.Configuration));
container.Register(typeof(IValidator<>), assemblies, Lifestyle.Scoped);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
ValidatorFactory implementation
public class ServiceProviderValidatorFactory : ValidatorFactoryBase
{
private readonly HttpConfiguration _config;
public ServiceProviderValidatorFactory(HttpConfiguration config)
{
_config = config;
}
public override IValidator CreateInstance(Type validatorType)
{
return (IValidator) _config.DependencyResolver.GetService(validatorType);
}
}
WebApiConfig.cs
// throws error: instance is requested outside the context of an active (Async Scoped) scope
// FluentValidationModelValidatorProvider.Configure(GlobalConfiguration.Configuration, x => x.ValidatorFactory = container.GetInstance<IValidatorFactory>());
FluentValidationModelValidatorProvider.Configure(config, x => x.ValidatorFactory = new ServiceProviderValidatorFactory(config));
The validation kicks in and works fine for the first API request but all subsequent API requests give the The operation cannot be completed because the DbContext has been disposed. error.
I've also tried setting up ServiceProviderValidatorFactory to use IServiceProvider approach and calling FluentValidationModelValidatorProvider.Configure(config, x => x.ValidatorFactory = new ServiceProviderValidatorFactory(container));
as shown here:
https://stackoverflow.com/a/43883455/654708
but that doesn't work either.
It looks as though once the AbstractValidators have loaded, they are cached/never disposed of but the DbContext is.
I'm guessing a hybrid lifestyle might work here (as setting the IReadOnlyRepository to a singleton lifestyle works fine) but I haven't had any luck there either.
UPDATE
Looks as though the AbstractValidator classes are Singletons. I've updated the validators and factory to be transient in the composition root but it doesn't seem to work as they are still only getting instantiated once.
container.Register<IValidatorFactory>(() => new ServiceProviderValidatorFactory(container), Lifestyle.Scoped);
container.Register(typeof(IValidator<>), assemblies, Lifestyle.Transient);
I've verified this by setting a break point inside one my AbstractValidator classes and can see that it only gets called once, i.e. on the first web api request but not on subsequent requests.
UPDATE 2
I was able to somewhat get around this problem by inject a Func<IReadOnlyRepository> repository into my AbstractValidator classes:
public class LocationModelValidator : AbstractValidator<LocationModel>
{
public LocationModelValidator(Func<IReadOnlyRepository> repository)
{
// Check the database to see if this location is already present
RuleFor(x => x.LocationId).Must(x => !repository.Invoke().Locations.Any(i => i.LocationId == x)).WithMessage("A Location with this ID already exists.");
}
}
And updating my composition root with the following:
container.RegisterSingleton<Func<IReadOnlyRepository>>(() => container.GetInstance<IReadOnlyRepository>);
I'd rather not have to do this but given I can't figure out why the AbstractValidators are always singletons, it will do for now.
What is the correct way to configure AutoMapper for global use.
I want to set it once and then used though out the app.
i have a strong feeling this is wrong.
in fact i know this is wrong as this calls an new instance.
I want a global config and then how do you call it.
Can not find a good example!
this is what ive got: but its not what im wanting
public static class AutoMapperConfig
{
public static IMapper GetMapper()
{
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<R_Logo, LogoDto>();
//lots more maps...?
});
IMapper mapper = config.CreateMapper();
return mapper;
}
}
and then usage:
var imapper = AutoMapperConfig.GetMapper();
var dest = imapper.Map<R_Logo, LogoDto>(logo);
UPDATE based on: pinkfloydx33
Call this once and then the config is done.
public static class AutoMapperConfig
{
public static void RegisterMappings()
{
AutoMapper.Mapper.Initialize(cfg => {
cfg.CreateMap<R_Logo, LogoDto>();
/* etc */
});
}
}
Here is the steps to configure the automapper in asp.net core mvc.
1. Create the mapping profile class which extends from Profile
public class ClientMappingProfile : Profile
{
public ClientMappingProfile ()
{
CreateMap<R_Logo, LogoDto>().ReverseMap();
}
}
2. Create the AutoMapper Configuration Class and add your mapping profile class here.
public class AutoMapperConfiguration
{
public MapperConfiguration Configure()
{
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<ClientMappingProfile>();
});
return config;
}
}
3. How we can use it.
var config = new AutoMapperConfiguration().Configure();
var iMapper = config.CreateMapper();
var dest = iMapper.Map<R_Logo, LogoDto>(logo);
Set this in your StartupConfig or StartUp file.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
.....
MappingDTOModelToModel.Configure();
}
}
Configuration of Mappings,
public static class MappingDTOModelToModel
{
private static void Configure()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<R_Logo, LogoDto>()
.ForMember(x => x.ID,
m => m.MapFrom(a => a.ID))
.ForMember(x => x.FirstName,
m => m.MapFrom(a => a.FirstName)).ReverseMap();
}
}
}
Calling it in a method,
public class MyService
{
public void MyMethod(var model)
{
var myModel = Mapper.Map<LogoDto, R_Logo>(model);
}
}
Hope this helps,
You can use the static mapper api as outlined here.
For example, somewhere in your application, probably during startup you would configure the static (global) mapper using something like:
AutoMapper.Mapper.Initialize(cfg => {
cfg.CreateMap<Type1, Type2>();
/* etc */
});
Then, any time you need to use your "globally" configured mapper, you access it via the static Mapper property (which is an IMapper):
Type1 objectOfType1 = new Type1();
var result = AutoMapper.Mapper.Map<Type2>(objectOfType1);
You then have one mapper that has been configured for all the types/configurations/profiles you provide for the duration of your application without needing to configure individual mapper instances.
In short, you configure it once (perhaps at application startup). The static mapper instance (the IMapper) is then available anywhere throughout your application by accessing it via AutoMapper.Mapper.
Access via this static property is what you refer to as "globally" in your comments. Anywhere you need it just use AutoMapper.Mapper.Map(...) So long as you've called Initialize once first.
Note that if you call Initialize more than once on the static instance, each subsequent call overwrites the existing configuration.
WARNING
In a previous release of AutoMapper, the static mapper was removed. It was later added back in and I don't know if they guarantee that it will remain in future versions. The recommendation is to use your own configured instances of a mapper. You can store it in a static property somewhere if you need it. Otherwise you can look into profiles, etc for easy ways to configure your mapper so that having your own instance isn't necessarily a "hassle".
Our solution to this problem was to first create a selection of attributes that can decorate a class as being "Mappable" (either To, From or Both). Then you can initialize the AutoMapper in a single location, usually post application initialization and use Reflection to dynamically create a map for each instance of the decorated classes.
Here's an example:
var types = _myTypeFinder.Find(type =>
type.IsDefined(typeof(AutoMapperAttribute)) ||
type.IsDefined(typeof(AutoMapperFromAttribute)) ||
type.IsDefined(typeof(AutoMapperToAttribute))
);
Mapper.Initialize(cfg =>
{
foreach (var type in types)
{
AutoMapperHelper.CreateMap(type, cfg);
}
});
I have find best solution for configuration auto mapper in .Net Core.
Multiple Profile.
Just use this:
services.AddSingleton(provider => new MapperConfiguration(cfg =>
{
cfg.AddProfile(new sampleProfileMapper());
}).CreateMapper());
I want to inject a AutoMapper.IMapper single instance as a singleton using NInject.
Actually, I'm un/mapping from/to objects using the AutoMapper static API. It's turned out obsolete and I'm looking forward to taking advantage of the ocassion to inject it using NInject.
Currently, I'm using this code in order to create my IMapper instance:
AutoMapper.Mapper.AddProfile(new UI.Mappings.Profiles.DigitalResourceProfile());
AutoMapper.Mapper.AddProfile(new UI.Mappings.Profiles.DigitalInputProfile());
AutoMapper.Mapper.AddProfile(new UI.Mappings.Profiles.FollowUpActivityProfile());
AutoMapper.Mapper.AddProfile(new UI.Mappings.Profiles.ResourceProfile());
As you can see, I've some profiles to initialize as well.
How should I build all that?
Until now, I've only been able to create a Module but I don't know how to make the bindings up.
public class AutoMapperModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
this.Bind<AutoMapper.MapperConfiguration>().ToProvider<AutoMapperconfigurationProvider>().InSingletonScope();
this.Bind<AutoMapper.IMapper>().To<AutoMapper.Mapper>();
}
private class AutoMapperconfigurationProvider : IProvider<AutoMapper.MapperConfiguration>
{
public object Create(IContext context)
{
AutoMapper.MapperConfiguration instance = new AutoMapper.MapperConfiguration(
cfg =>
{
cfg.AddProfile(new UI.Mappings.Profiles.DigitalResourceProfile());
cfg.AddProfile(new UI.Mappings.Profiles.DigitalInputProfile());
cfg.AddProfile(new UI.Mappings.Profiles.FollowUpActivityProfile());
cfg.AddProfile(new UI.Mappings.Profiles.ResourceProfile());
}
);
return instance;
}
public Type Type
{
get { throw new NotImplementedException(); }
}
}
}
I'd like to write this sentence each time I need a IMapper to map objects:
IMapper mapper = kernel.Get<IMapper>();
Any ideas?
I investigated this.
And I found the following:
In documentation we can found that we can do something like:
var config = new MapperConfiguration(cfg => {
cfg.AddProfile<SomeProfile>();
cfg.CreateMap<Source, Dest>();
});
var mapper = config.CreateMapper(); // option 1
// or
var mapper = new Mapper(config); // option 2
Your code would work with using the option 2, because you have binding for configuration and for mapper.
But here we have two problems.
1) You need to change your first binding to bind MapperConfiguration as an interface IConfigurationProvider because the constructor of Mapper needs it:
public Mapper(IConfigurationProvider configurationProvider)
: this(configurationProvider, configurationProvider.ServiceCtor)
{
}
But here we got the second problem.
2) In automapper version 4.2.1 (as I believe you downloaded from NuGet) the Mapper class has only internal constructors. It has a public constructors in documentation (which is weird) and I think will have in a future release.
Therefore, for now you need to modify Load method to use option 1:
public override void Load()
{
this.Bind<AutoMapper.MapperConfiguration>().ToProvider<AutoMapperconfigurationProvider>().InSingletonScope();
this.Bind<AutoMapper.IMapper>().ToMethod(context => context.Kernel.Get<MapperConfiguration>().CreateMapper());
}
And then you can call IMapper mapper = kernel.Get<IMapper>(); to get the mapper instance.
It will use public IMapper CreateMapper() => new Mapper(this); and will create the instance of IMapper. Note: you need to use MapperConfiguration (not IConfiguration provider) to call CreateMapper method, it has the same situation as with public/internal constructors of Mapper.
That should help.
I have a web project and I want it to work with ravendb and ravendb-embedded.
So this is how I think I should solve it.
Two projects, MvcRavendb and MvcRavendb-Embedded where the two projects references two different nuget packages, one for ravendb and one for ravendb embedded.
In my core project I have an interface IDocumentStoreInitializer which has one method, IDocumentStore InitializeDocumentStore()
MvcRavenDb and MvcRavenDb-Embedded has one class like this
public class RegisterRavenDb : IDocumentStoreInitializer {
public IDocumentStore InitializeDocumentStore() {
return new DocumentStore OR EmbeddableDocumentStore();
}
}
Then I have a class that registers the concrete implementation like this
public class RavenRegistry : Registry {
public RavenRegistry() {
For<IDocumentStoreInitializer>().Use<RegisterRavenDb>();
}
}
So far so good but then I have bootstrapper that configures structuremap like this
public class Bootstrapper {
public static IContainer Initialize() {
ObjectFactory.Initialize(x =>
{
// here I want to use the registered concrete implmentaiton of IDocumentStore
var documentStore = new DocumentStore { ConnectionStringName = "RavenDB" };
documentStore.Initialize();
}
}
}
So how can I tell structuremap to use InitializeDocumentStore from the RavenRegistry class?
Maybe I have missed something or I'm taking the wrong approach here
Just use the EmbeddableDocumentStore instance, using the connection string, you can control whatever it will be embedded or server/client.
This should do as you wish. In OnCreation the ConnectionString can be set, too.
ObjectFactory.Initialize(x =>
{
// here I want to use the registered concrete implmentaiton of IDocumentStore
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.AssembliesFromApplicationBaseDirectory();
scan.LookForRegistries();
});
x.For<IDocumentStore>().Use(c =>
c.GetInstance<IDocumentStoreInitializer>().
InitializeDocumentStore()).OnCreation<IDocumentStore>(z => z.Initialize());
});