Using Registry in StructureMap to create a pluggable architechture - c#

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());
});

Related

How to override config.json data using C# code?

I have followed this blog here on how to use IOC with Autofac, this is the first time hearing about IOC and autoFac.
I have downloaded the project from the link the blog provided and I have been looking through the project and I am trying to find out how the classes:
public class DatabaseSettings
{
public string ConnectionString { get; protected set; }
public int TimeoutSeconds { get; protected set; }
}
public class UserSettings
{
public string DefaultUsername { get; protected set; }
public bool ActiveByDefault { get; protected set; }
}
... gets populated without no invocation of the load function in 'Database reader'?
Is it because of (these) :
public T Load<T>() where T : class, new() => Load(typeof(T)) as T;
public T LoadSection<T>() where T : class, new() => LoadSection(typeof(T)) as T;
If it is the above codes what are they(so I can read up on how they work)?
Final Question, Is it possible to save the data back to the config.json using this approach?
The entries like
public T Load<T>() where T : class, new() => Load(typeof(T)) as T;
just mean you can use the "generic" syntax when accessing in the functions. It's a bit neater than passing in the Type as a method parameter, and also means you get a strongly-typed object back. Another way of writing the above is:
public T Load<T>() where T : class, new()
{
var type = typeof(T);
var loaded = Load(type);
return loaded as T;
}
It's a useful language feature but nothing to do with IoC itself. The IoC magic itself is mostly contained in SettingsModule. This bit:
builder.RegisterInstance(new SettingsReader(_configurationFilePath, _sectionNameSuffix))
.As<ISettingsReader>()
.SingleInstance();
tells Autofac to provide a SettingsReader (the RegisterInstance part) whenever anyone requests an ISettingsReader (the As<> bit). .SingleInstance means it will treat the SettingsReader as a singleton: only one of them will be created and that same object is passed to everywhere an ISettingsReader is requested.
This other part
var settings = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.Name.EndsWith(_sectionNameSuffix, StringComparison.InvariantCulture))
.ToList();
settings.ForEach(type =>
{
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(type))
.As(type)
.SingleInstance();
});
is just a fancy way of automatically telling it what to do whenever it sees a request for DatabaseSettings or UserSettings. As per the original question, this is where the Load function is actually called. A simpler way of doing the same would just be:
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(typeof(DatabaseSettings))).As<DatabaseSettings>();
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(typeof(UserSettings))).As<UserSettings>();
You could write out the logic for those as "when a DatabaseSettings object is requested (.As), find an implementation for ISettingsReader, and then call LoadSection on that (the first part)"
Elsewhere in the Container class there's also this:
builder.RegisterType<UserService>().As<IUserService>();
which just tells Autofac what to do for an IUserService.
The result is that where in the main application method we have:
using (var scope = container.BeginLifetimeScope())
{
var userService = scope.Resolve<IUserService>();
Without that main method "knowing" anything about the concrete types it uses, we'll get a fully functioning IUserService back. Internally, Autofac will resolve the chain of dependencies required by plugging all of the constructor parameters for each type in the chain. That might look something like:
IUserService requested
Resolve UserService
Resolve IDatabase
return Database
Resolve UserSettings
Resolve ISettingsReader
return SettingsReader
Call LoadSection on ISettingsReader
return generated UserSettings object
For your Final Question - yes! However, IoC isn't necessarily what would enable you to do so. It just lets you bind together and access whichever custom classes you'd create to allow saving.
You might create a new interface like
public interface ISettingsWriter
{
void Save<T>(T settings);
}
And then for some reason you add a method which accesses that in the UserService:
public class UserService : IUserService
{
private readonly IDatabase _database;
private readonly UserSettings _userSettings;
private readonly ISettingsWriter _settingsWriter;
public UserService(IDatabase database, UserSettings userSettings, ISettingsWriter settingsWriter)
{
_database = database;
_userSettings = userSettings;
_settingsWriter = settingsWriter;
}
public void UpdateUserSettings()
{
_settingsWriter.Save(new UserSettings());
}
Using it in this way is a bit simpler than in the original sample code - I'd recommend taking this approach until you get more used to it. It means that the only other thing you'd need to add would be the registration for the settings writer, like:
builder.RegisterType<SettingsWriter>()
.As<ISettingsWriter>();

Access automapper from other class library in .net core

I am using asp.net core 2.0. I have DataAccess project and 20 API service project in my solution. And this number increasing every day. I will use AutoMapper. But I don't want to add automapper from NuGet for all projects. So, I want to add to the only DataAccess solution and adding profiles to DataAccess solution. And I want to call from API project by writing "mapper.Map(originalObject)". We can add Automapper to API project by adding startup.cs. But my DataAccess project is a class library. So it hasn't got startup.cs. How can I do this and can I access automapper from service projects? (I don't want to add automapper from NuGet to API)
There may be many solutions to this problem, I suggest only two of them and these aproaches may also change depending on your choice and scenario. Whether your helper class knows all the types that will be mapped or other user libraries need to register their own POCO classes, whether you prefer creating a mapper... You may also want to cache mappers and return it if it requested again.
Simple code samples are as follows
class Foo
{
public string Name { get; set; }
}
class Bar
{
public string Name { get; set; }
}
static void Main(string[] args)
{
//First approach usage
Bar _bar1 = MapperHelper.MapFrom<Bar>(new Foo() { Name = "bbbbb" });
//Second approach usage
IMyMapper _myMapper = MapperHelper.GetMapperFor<Foo, Bar>();
Bar _bar2 = _myMapper.MapFrom<Bar>(new Foo() { Name = "aaaAAA" });
//Third approach usage
Bar _bar3 = MapperHelper.Map<Bar, Foo>(new Foo() { Name = "cccc" });
}
public interface IMyMapper
{
T MapFrom<T>(object entity);
}
class MyMapper : IMyMapper
{
IMapper mapper;
public MyMapper(IMapper mapper)
{
this.mapper = mapper;
}
public T MapFrom<T>(object entity)
{
return mapper.Map<T>(entity);
}
}
public static class MapperHelper
{
static IMapper staticMapper;
static MapperHelper()
{
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Foo, Bar>();
});
staticMapper = config.CreateMapper();
}
//First approach, create a mapper and use it from a static method
public static T MapFrom<T>(object entity)
{
return staticMapper.Map<T>(entity);
}
//Second approach (if users need to use their own types which are not known by this project)
//Create you own mapper interface ans return it
public static IMyMapper GetMapperFor<TSource, TDestination>()
{
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<TSource, TDestination>();
});
var _mapper = config.CreateMapper();
return new MyMapper(_mapper);
}
//Third sample, create and use mapper inside a static helper method
//This is for mapping foreign types that this project does not
//include (e.g POCO or model types in other projects)
public static TDestination Map<TDestination, TSource>(TSource entity)
{
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<TSource, TDestination>();
});
var _mapper = config.CreateMapper();
return _mapper.Map<TDestination>(entity);
}
}
First one creates the configuration for known types and uses this mapper.
Second one creates a mapper and returns it in a wrapper class.
Third one creates and uses a mapper for mapping operation and only returns the mapped object.
Most people do not like static classes and methods since they cause strict unwanted dependencies, they can not be replaced easily. So, creating factory or utility classes, registering them to a dependency injection container and in jecting them where needed is preferred.

AutoMapper 5.2 how to configure

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());

Bootstrapping AutoMapper & StructureMap via ConstructServicesUsing

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.

Where to place AutoMapper map registration in referenced dll

This is my first AutoMapper project and may be obvious to some but the tutorials and examples are not clicking with me. I am trying to understand where and to a certain degree how to register(I think I want profiles) my maps for use. There are plenty of MVC examples saying to use the global asax and this makes sense but what is the equivalent in a library project?
In my sandbox I have a winform app and a core library. The winform app calls methods made available by the library and it is one of these library methods that makes use of automapper.
So for some background here is my map:
(and to be clear the mapping is in the SAME core library project)
public class Raw_Full_Map
{
public Raw_Full_Map()
{
Mapper.CreateMap<IEnumerable<RawData>, FullData>()
.ForMember(d => d.Acres, m => m.ResolveUsing(new RawLeadDataNameResolver("Acres")));
//this is clearly just a snip to show it's a basic map
}
}
This is the core library method being called: (note it is a static..which means I won't have a constructor...if this is the problem am I to understand then that AutoMapper can't be utilized by static helper classes...that doesn't make sense....so likely I'm just not doing it right.
public static class RawDataProcessing
{
public static FullData HTMLDataScrape(string htmlScrape)
{
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(htmlScrape);
var list = Recurse(doc.DocumentNode);
//HTML agility stuff that turns my html doc into a List<RawData> object
return Mapper.Map<FullData>(list);
}
My test harness calls it like this:
var _data = RawDataProcessing.HTMLDataScrape(rawHTML);
This of course errors because the map isn't "registered".
If I do this in the test harness:
var x = new RawData_FullData();
var _data = RawDataProcessing.HTMLDataScrape(rawHTML);
Then everything works as my map get's registered albeit I think in a really bogus way...but it does work.
So the question is how do I register my mapping in the core library project...so that ANY method can use it...there isn't really an equivalent global.asax in a dll is there?
Thank you for helping me connect the missing pieces.
Put it in the static constructor of either the source or the target type of the mapping.
public class FullData
{
static FullData()
{
Mapper.CreateMap<IEnumerable<RawData>, FullData>()
.ForMember(d => d.Acres, m => m.ResolveUsing(new RawLeadDataNameResolver("Acres")));
}
}
The static constructor will automatically get called the first time you try to use the type FullData for anything (for example a mapping).
You can use PreApplicationStartMethod for any class and it's method in your class library which will be referenced from your startup project if you want automatically to call this on startup. And then you can register all your mappings in that method. By the way, I suggest to use AddProfile for registering all mappings.
[assembly: PreApplicationStartMethod(typeof(MyClassLibrary.Startup), "Start")]
namespace MyClassLibrary
{
public class Startup
{
// Automatically will work on startup
public static void Start()
{
Mapper.Initialize(cfg =>
{
Assembly.GetExecutingAssembly().FindAllDerivedTypes<Profile>().ForEach(match =>
{
cfg.AddProfile(Activator.CreateInstance(match) as Profile);
});
});
}
}
}
You just need to create new classes which derived from Profile class and then override it's Configure() method:
...
public class FooMapperProfile:Profile
{
protected override void Configure()
{
Mapper.CreateMap<OtherFoo, Foo>()
.ForMember(...
... // so on
}
}
public class AnotherFooMapperProfile:Profile
{
protected override void Configure()
{
Mapper.CreateMap<OtherFoo, AnotherFoo>()
.ForMember(...
... // so on;
}
}
...
// and so on
Additional information:
If you have seen I have initialized all mappings with that code:
Mapper.Initialize(cfg =>
{
Assembly.GetExecutingAssembly().FindAllDerivedTypes<Profile>().ForEach(match =>
{
cfg.AddProfile(Activator.CreateInstance(match) as Profile);
});
});
It will automatically find all types derived from Profile and will add all profiles after createing their new instances.
Update1:
As #Scott Chamberlain commented, PreApplicationStartMethod only works for ASP.NET applications. This would not work with a desktop app. If you are working with Wpf, then you can use Application.OnStartup method. Or just call Start.Startup (); in load event.
Update2:
FindAllDerivedTypes extension method:
public static class AssemblyExtensions
{
public static List<Type> FindAllDerivedTypes<T>(this Assembly assembly)
{
var derivedType = typeof(T);
return assembly.GetTypes()
.Where(t => t != derivedType && derivedType.IsAssignableFrom(t))
.ToList();
}
}

Categories