I'm inserting Automapper (latest version from Nuget) into my project (WebApi2, framework 4.5.1) and using SimpleInjector (latest version from Nuget).
My problem is that before using Automapper everything worked. Now I'm not sure why it is telling me that a reverse mapping is missing (when I know it's not needed for the service being called).
I'm using the IMappingEngine interface.
I have a AutoMapperConfig class with all the Mapper.CreateMap
Example of AutoMapperConfig
public static class AutoMapperConfig
{
public static void Configure(IMappingEngine mappingEngine)
{
Mapper.CreateMap<Entity, EntityModel>()
...
}
}
The reason AutoMapperConfig.Configure is receiving an IMappingEngine is that some mappings attributs have other mapping inside. For example (snippet of code):
(Note the Mapper.Map inside the Mapper.CreateMap)
Mapper.CreateMap<Req, ReqModel>()
.ForMember(
opt => opt.MapFrom(
src => new ServiceModel(mappingEngine)
{
Id = src.Plan.Id,
Name = src.Plan.Service.Name,
ServiceTypeId = src.Plan.Service.Type.Id,
Type = Mapper.Map<TypeModel>(src.Plan.Service.Type)
}))
In Global.asax (method Application_Start()) I'm calling:
AutoMapperConfig.Configure(Mapper.Engine);
In SimpleInjector registrations I'm using:
container.RegisterSingleton<IMappingEngine>(Mapper.Engine);
AutoMapper.Mapper.Configuration.ConstructServicesUsing(container.GetInstance);
Then each Controller receives a IMappingEngine and uses:
MappingEngine.Map
Anything missing or wrong?
Thanks in advance! Guillermo.
Related
I am trying to inject the IApplicationConfigurationSection implementation into this MVC5 Controller, so that I can have access to some of the information (various strings) from my web.config custom section in all of my views:
public class BaseController : Controller
{
public IApplicationConfigurationSection AppConfig { get; set; }
public BaseController()
{
ViewBag.AppConfig = AppConfig; // AppConfig is always null
}
}
I want to use setter injection so I don't have to clutter up my derived Controller constructors with parameters that they don't really care about.
Note: If there is a better way to inject base class dependencies, please let me know. I admit I may not be on the right track here.
In my Global.asax I load my StructureMap configurations:
private static IContainer _container;
protected void Application_Start()
{
_container = new Container();
StructureMapConfig.Configure(_container, () => Container ?? _container);
// redacted other registrations
}
My StructureMapConfig class loads my registries:
public class StructureMapConfig
{
public static void Configure(IContainer container, Func<IContainer> func)
{
DependencyResolver.SetResolver(new StructureMapDependencyResolver(func));
container.Configure(cfg =>
{
cfg.AddRegistries(new Registry[]
{
new MvcRegistry(),
// other registries redacted
});
});
}
}
My MvcRegistry provides the mapping for StructureMap:
public class MvcRegistry : Registry
{
public MvcRegistry()
{
For<BundleCollection>().Use(BundleTable.Bundles);
For<RouteCollection>().Use(RouteTable.Routes);
For<IPrincipal>().Use(() => HttpContext.Current.User);
For<IIdentity>().Use(() => HttpContext.Current.User.Identity);
For<ICurrentUser>().Use<CurrentUser>();
For<HttpSessionStateBase>()
.Use(() => new HttpSessionStateWrapper(HttpContext.Current.Session));
For<HttpContextBase>()
.Use(() => new HttpContextWrapper(HttpContext.Current));
For<HttpServerUtilityBase>()
.Use(() => new HttpServerUtilityWrapper(HttpContext.Current.Server));
For<IApplicationConfigurationSection>()
.Use(GetConfig());
Policies.SetAllProperties(p => p.OfType<IApplicationConfigurationSection>());
}
private IApplicationConfigurationSection GetConfig()
{
var config = ConfigurationManager.GetSection("application") as ApplicationConfigurationSection;
return config; // this always returns a valid instance
}
}
I have also "thrown my hands up" and tried using the [SetterProperty] attribute on the BaseController - that technique failed as well.
Despite my best efforts to find a solution, the AppConfig property in my controller's constructor is always null. I thought that
`Policies.SetAllProperties(p => p.OfType<IApplicationConfigurationSection>());`
would do the trick, but it didn't.
I have found that if I discard setter injection and go with constructor injection, it works as advertised. I'd still like to know where I'm going wrong, but I'd like to stress that I'm not a StructureMap guru - there may be a better way to avoid having to constructor-inject my base class dependencies. If you know how I should be doing this but am not, please share.
While constructor injection in this scenario appears to be the better solution to the stated problem as it follows The Explicit Dependencies Principle
Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.
The mention of only needing to access the AppConfig in your views leads me to think that this is more of an XY problem and a cross cutting concern.
It appears that the controllers themselves have no need to use the dependency so stands to reason that there is no need to be injecting them into the controller explicitly just so that the dependency is available to the View.
Consider using an action filter that can resolve the dependency and make it available to the View via the same ViewBag as the request goes through the pipeline.
public class AccessesAppConfigAttribute : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
var resolver = DependencyResolver.Current;
var appConfig = (IApplicationConfigurationSection)resolver.GetService(typeof(IApplicationConfigurationSection));
filterContext.Controller.ViewBag.AppConfig = appConfig;
}
}
This now makes the required information available to the views with out tight coupling of the controllers that may have a use for it. Removing the need to inject the dependency into derived classes.
Either via adorning Controller/Action with the filter attribute
[AccessesAppConfig] //available to all its actions
public class HomeController : Controller {
//[AccessesAppConfig] //Use directly if want to isolate to single action/view
public ActionResult Index() {
//...
return View();
}
}
or globally for all requests.
public class FilterConfig {
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
filters.Add(new AccessesAppConfigAttribute());
}
}
At this point it really does not matter which IoC container is used. Once the dependency resolver has been configured, Views should have access to the required information in the ViewBag
I make use of a 3rd party DLL which internally uses AutoMapper and initializes it with AutoMapper.Initialize() but then from what I understand, I cannot also call Initialize() as it clear existing maps.
What is the best solution for a 3rd party to use AutoMapper without conflicting with my own code?
Or another way.. how should a shared assembly set itself up with AutoMapper which guarantees it's own profiles are initializes but allows the consumer of that assembly to initialize it's own profiles?
Should the 3rd party assembly just define it's profiles and rely on the calling code to initialize all enabled profiles - manually adding profiles from the 3rd part assembly?
I am using AutoMapper 5.1 at the moment.
The best way to do this is not to use the static instance of Mapper - create your own, and use Dependency Injection to inject an instance of IMapper wherever you need to use AutoMapper. This also makes it a lot easier to test your code.
This is how I do things using autofac as my DI container:
builder.Register<IMapper>(c =>
{
var profiles = c.Resolve<IEnumerable<Profile>>();
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
return config.CreateMapper();
}).SingleInstance();
This way, whenever I need to use automapper, I just add it to my constructor:
public class MyClass
{
private readonly IMapper _mapper;
public MyClass(IMapper mapper)
{
_mapper = mapper;
}
public void DoSomething()
{
var mapped = _mapper.Map<Dto>(....);
}
}
I'm trying to inject Signalr dependencies with Funq D.I.
The process is explained pretty well here and I tried also to follow this question.
and the Ninject version works pretty well.
Now I am trying to convert it to a Funq version using this gist for FunqDependencyResolver.
but this Funq version is not working and gives the "System.MissingMethodException: No parameterless constructor defined for this object" that should be because it's not registering dependencies.
Is this because the Ninject version is resolving to a method?
We used Windsor, but the process is the same for any IoC:
First create your resolver, inherit from signalR DefaultDependencyResolver:
public class CustomContainerResolver: DefaultDependencyResolver
{
public CustomContainerResolver(IocContainer instance)
{
_instance = instance;
}
public override object GetService(Type serviceType)
{
return _instance.Instance.Kernel.HasComponent(serviceType) ? _instance.GetService(serviceType) : base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
return _instance.Instance.Kernel.HasComponent(serviceType) ? _instance.GetAllInstances(serviceType): base.GetServices(serviceType);
}
}
In your Startup:
var signalrDependency = new CustomContainerResolver(container);
then, as usual
app.MapSignalR(hubConfiguration);
I'm maintaining an app which is using AutoMapper like this:
public class UserDomainService
{
public UserDTO GetUser(int id)
{
Mapper.Reset();
Mapper.CreateMap<User, UserDTO>();
var user = ....;
return Mapper.Map<User, UserDTO>(user);
}
}
This domain service is used by web-services.
I think it can be a problem when two web-service requests come in and on separate threads Reset and Map are called.
The Mapper can become in a state where the Map() fails.
I know I should probably setup CreateMap() mappings in Application_Start, but for now I am trying to do this:
public class UserDomainService
{
public UserDTO GetUser(int id)
{
var config = new AutoMapper.Configuration(new TypeMapFactory(), MapperRegistry.AllMappers());
config.CreateMap<User, UserDTO>();
var mapper = new MappingEngine(configuration);
var user = ....;
return mapper.Map<User, UserDTO>(user);
}
}
Leaving aside performance, is it anything which could potentially make the app crash?
Sometimes I am getting an exception like this:
System.ArgumentException: An item with the same key has already been added.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
at AutoMapper.TypeMapFactory.GetTypeInfo(Type type)
at AutoMapper.TypeMapFactory.CreateTypeMap(Type sourceType, Type destinationType, IMappingOptions options)
at AutoMapper.Configuration.CreateTypeMap(Type source, Type destination, String profileName)
at AutoMapper.Configuration.CreateMap[TSource,TDestination](String profileName)
at AutoMapper.Configuration.CreateMap[TSource,TDestination]()
Note that the above sample mapping is just an example.
I am using AutoMapper v1.1.0.188 in a 3.5 Net app.
EDIT:
There's a specific reason why it's not easy for me to put the configuration in the Application_Start.
I have different mapping requirements depending on the context. For example, for the same User to UserDTO, I need two different types of mapping.
It's the same problem described in this old question:
Link
https://github.com/AutoMapper/AutoMapper/wiki/Getting-started
Where do I configure AutoMapper?
If you're using the static Mapper method, configuration should only happen once per AppDomain. That means the best place to put the configuration code is in application startup, such as the Global.asax file for ASP.NET applications. Typically, the configuration bootstrapper class is in its own class, and this bootstrapper class is called from the startup method.
I have the following NinjectModule derived class:
class MainModule : NinjectModule
{
public override void Load()
{
Bind<IMyClass>().To<MyClass>();
Bind<IMainClass>().To<MainClass>().OnActivation((context,myClass) =>
{ myClass.Add("Something", context.Kernel.Get<IMyClass>()); });
}
}
My problem is that IKernel does not exposed the .Get<T> extension method.
Is there a pattern for doing this?
Caveats: I don't want to have to decorate my classes with Ninject attributes, as the Add is specific to how MainClass works I wanted all the code to do with its creation to be held in this module.
TIA
Hmmm, silly oversight in the end it seems. The extension methods reside in the Ninject namespace, using a module only requires that you are using Ninject.Modules;
Adding using Ninject; meant that the following was possible:
Bind<IMainClass>().To<MainClass>()
.OnActivation((context,myClass) =>
{
foreach(var n in context.Kernel.GetAll<IMyClass>())
{
myClass.Add("Something", n);
}
});
I'll leave this open for a bit to see if anyone has a better way of doing this.