use AutoMapper.EF6,but Mapper not initialized error happed - c#

the error info :
Mapper not initialized. Call Initialize with appropriate
configuration. If you are trying to use mapper instances through a
container or otherwise, make sure you do not have any calls to the
static Mapper.Map methods, and if you're using ProjectTo or
UseAsDataSource extension methods, make sure you pass in the
appropriate IConfigurationProvider instance. InnerException:
StackTrace: at AutoMapper.Mapper.get_Configuration()
the asp.net mvc5 controller code
public override ActionResult Kendo_Read(DataSourceRequest request, IQueryable<Activity> results)
{
var data = results.ProjectTo<ActivityViewModel>();
var rdata = data.ToDataSourceResult(request);
return Json(rdata);
}
AutoMapper Configure Code
public class CRMProfile : Profile
{
CreateMap<Activity, ActivityViewModel>();
}
public static class Configuration
{
public static MapperConfiguration MapperConfiguration()
{
return new MapperConfiguration(x =>
{
x.AddProfile(new CRMProfile());
}
}
}
Register Code
internal static MapperConfiguration MapperConfiguration { get; private set; }
public class MvcApplication : System.Web.HttpApplication
{
MapperConfiguration = Configuration.MapperConfiguration();
}
i home return data type is IQueryable in the controller,not List,
I See the Question and Issue in stackoverflow but could not solved my problem.

From AutoMapper's source code you can see that this exception will be thrown when configuration is not initialized at all:
public static IConfigurationProvider Configuration
{
get => _configuration ?? throw new InvalidOperationException(InvalidOperationMessage);
private set => _configuration = value;
}
Make sure that Mapper is correctly configured using static properties or correctly registered using IoC container if you are using that (please, refer to documentation for details). Are you perhaps missing the Mapper.Initialize() call?

Related

AutoMapper IValueResolver: Cannot access a disposed object. Object name: 'IServiceProvider'

I want to use IValueResolver in AutoMapper to map two class, and one value will be take from HttpRequest Context, so I want to use IValueResolver
CreateMap<Dto, ViewModel>().ForMember(x=>x.MemberID, opt=>opt.Mapfrom<SpecialResolver>())
and Resolver is simple
public string Resolve(ViewModel viewModel, Dto dto, string destMember, ResolutionContext context)
{
return "test";
}
inside startup class i put this:
services.AddAutoMapper(typeof(Startup));
but every time I map them for MemberID will throw out error say IServiceProvider been disposed.
so how to make these work? I tried inject this SpecialResolver in startup but also not work. BTW, I'm use .net core 3.0
I'm strongly convinced that a bug has crept in your code somewhere and hence your problems. On my side, everything works just fine. I tried to recrete what you are trying to do, based on your question and comments. It will surely differ more or less, but you should be able to grasp the idea and get it going on your own.
I'm starting with a mapping profile, where I'm explicitly specifying usage of HttpContextValueResolver for MemberId property of ViewModel class:
public class MyMappingProfile : Profile
{
public MyMappingProfile()
{
CreateMap<Dto, ViewModel>()
.ForMember(x => x.MemberId, opt => opt.MapFrom<HttpContextValueResolver>());
}
}
Then the value resolver:
public class HttpContextValueResolver : IValueResolver<Dto, ViewModel, string>
{
private readonly IHttpContextAccessor _httpContextAccessor;
public HttpContextValueResolver(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public string Resolve(Dto source, ViewModel destination, string destMember, ResolutionContext context)
{
// Obtain whatever you need from HTTP context.
// Warning! HTTP context may be null.
return _httpContextAccessor.HttpContext?.Request.Path;
}
}
To acess HttpContext outside a controller I used a dedicated for that purpose service called IHttpContextAccessor. Read more about it in the docs.
It isn't automatically available, so I need to register it in Startup alongside with the AutoMapper:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddAutoMapper(typeof(Startup));
services.AddHttpContextAccessor();
}
Take notice that registering AutoMapper while passing just one type (of Startup), requires that all mapping profiles need to be in the same assembly (project) as the Startup. With mapping profiles in more than one assembly, you need to specify those assemblies or types with a suitable overload of the AddAutoMapper() method.
And finally usage in an example controller:
public class HomeController : Controller
{
private readonly IMapper mapper;
public HomeController(IMapper mapper)
{
this.mapper = mapper;
}
public IActionResult Index()
{
var source = new Dto
{
MemberID = "123",
};
var result = mapper.Map<ViewModel>(source);
return View();
}
}
And here are the dto and view model I used:
public class Dto
{
public string MemberID { get; set; }
}
public class ViewModel
{
public string MemberId { get; set; }
}

How do I handle a configuration class that are loaded at runtime with dependency injection?

I'm currently trying to work with dependency injection and so far I love. But it's one thing I can't really get my head around and where my current solution just seems wrong.
I'm working with WPF, MVVM and many of the classes I inject need an instance of a project configuration class that isn't initialized until the user create or open a new project in the application.
So my current solution is to have a "ConfigurationHandler" with load/save method and a property that hold an instance of the configuration class after it's loaded. I inject ConfigurationHandler to the others classes and then they can access the configuration after it's loaded. But it seems weird to let classes that never should save/load configuration handle the whole "ConfigurationHandler" and 100% they would just use it to access the configuration instance likt this:
var configuration = configurationHandler.Configuration;
Another problem is that if they try to access the configuration before it's loaded they will get exception (should not really happen as you can't do anything before a project is created/loaded, but still).
But the only other solution I can think of is to use "intialize" methods after a project is created/open but that seems just as bad.
So how do you usually handle cases like this?
Edit: Should add that this configuration class handle information like project path, project name, etc so have nothing to do with the dependency injection itself.
If your configuration is static (read: It's only read during startup of your application, such as from project.json or Web.Config), you can also set it during app startup/the composition root.
The new ASP.NET 5 uses it heavily and it works very well. Basically you will have an IConfiguration<T> interface and a POCO class, which you set up during the app startup and can resolve/inject it into your services.
public interface IConfiguration<T> where T : class
{
T Configuration { get; }
}
And it's default implementation
public interface DefaultConfiguration<T> where T : class
{
private readonly T configuration;
public T Configuration {
return configuration;
}
public DefaultConfiguration<T>(T config)
{
this.configuration = this.configuration;
}
}
And your POCO class
public class AppConfiguration
{
public string OneOption { get; set; }
public string OtherOption { get; set; }
}
In your composition root, you would then register it, like
// read Web.Config
Configuration rootWebConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(null);
container.AddSingleton<IConfiguration<AppConfiguration>>(new DefaultConfiguration<AppConfiguration>(
new AppConfiguration
{
OneOption = rootWebConfig.AppSettings.Settings["oneSetting"],
OtherOption = rootWebConfig.AppSettings.Settings["otherSetting"],
})
);
And finally, all you have to declare in your services is
public class MyService : IMyService
{
public MyService(IUserRepository, IConfiguration<AppConfiguration> appConfig)
{
...
if(appConfig.OneOption=="someValue") {
// do something
};
}
}
Finally you can make this a bit easier to configure, if you write an extension method like
public static class MyContainerExtension
{
public static void Configure<T>(this IMyContainer container, Action<T> config) where T : class, new()
{
var t = new T();
config(t);
container.AddSingelton<IConfiguration<T>>(t);
}
}
Then all you need to do is
container.Configure<AppConfiguration>(
config =>
{
config.OneOption = rootWebConfig.AppSettings.Settings["oneSetting"],
config.OtherOption = rootWebConfig.AppSettings.Settings["otherSetting"],
})
);
to set it up
Instead of Constructor Injection, consider using an Ambient Context approach.
The last type of DI we’ll discuss is making dependencies available
through a static accessor. It is also called injection through the
ambient context. It is used when implementing cross-cutting concerns.
This is a good option if the classes that need access to your configuration are of different types in different layers or libraries - i.e. is a true cross-cutting concern.
(Quote source)
Example, based on the classic Time Provider one from [Dependency Injection in .NET][2]
abstract class CustomConfiguration
{
//current dependency stored in static field
private static CustomConfiguration current;
//static property which gives access to dependency
public static CustomConfiguration Current
{
get
{
if (current == null)
{
//Ambient Context can't return null, so we assign a Local Default
current = new DefaultCustomConfiguration();
}
return current;
}
set
{
//allows to set different implementation of abstraction than Local Default
current = (value == null) ? new DefaultCustomConfiguration() : value;
}
}
//service which should be override by subclass
public virtual string SomeSetting { get; }
}
//Local Default
class DefaultCustomConfiguration : CustomConfiguration
{
public override string SomeSetting
{
get { return "setting"; }
}
}
Usage
CustomConfiguration.Current.SomeSetting;
There are other DI Patterns that could be used, but require changes to the class that need it. If Configuration is a cross cutting concern Ambient Context could be the best fit.
Constructor Injection Example
public SomeClass(IConfiguration config)
{
}
Property Injection
public SomeClass()
{
IConfiguration configuration { get; set; }
}
Method Injection
public SomeClass()
{
public void DoSomethingNeedingConfiguation(IConfiguration config)
{
}
}
There is also Service Locator, but Service Locator is (IMO) an anti-pattern.

IServiceProvider in ASP.NET Core

I starting to learn changes in ASP.NET 5(vNext)
and cannot find how to get IServiceProvider, for example in "Model"'s method
public class Entity
{
public void DoSomething()
{
var dbContext = ServiceContainer.GetService<DataContext>(); //Where is ServiceContainer or something like that ?
}
}
I know, we configuring services at startup, but where all service collection staying or IServiceProvider?
You have to bring in Microsoft.Extensions.DependencyInjection namespace to gain access to the generic
GetService<T>();
extension method that should be used on
IServiceProvider
Also note that you can directly inject services into controllers in ASP.NET 5. See below example.
public interface ISomeService
{
string ServiceValue { get; set; }
}
public class ServiceImplementation : ISomeService
{
public ServiceImplementation()
{
ServiceValue = "Injected from Startup";
}
public string ServiceValue { get; set; }
}
Startup.cs
public void ConfigureService(IServiceCollection services)
{
...
services.AddSingleton<ISomeService, ServiceImplementation>();
}
HomeController
using Microsoft.Extensions.DependencyInjection;
...
public IServiceProvider Provider { get; set; }
public ISomeService InjectedService { get; set; }
public HomeController(IServiceProvider provider, ISomeService injectedService)
{
Provider = provider;
InjectedService = Provider.GetService<ISomeService>();
}
Either approach can be used to get access to the service. Additional service extensions for Startup.cs
AddInstance<IService>(new Service())
A single instance is given all the time. You are responsible for initial object creation.
AddSingleton<IService, Service>()
A single instance is created and it acts like a singleton.
AddTransient<IService, Service>()
A new instance is created every time it is injected.
AddScoped<IService, Service>()
A single instance is created inside of the current HTTP Request scope. It is equivalent to Singleton in the current scope context.
Updated 18 October 2018
See: aspnet GitHub - ServiceCollectionServiceExtensions.cs
I don't think it is a good idea for an entity (or a model) to have access to any service.
Controllers, on the other hand, do have access to any registered service in their constructors, and you don't have to worry about it.
public class NotifyController : Controller
{
private static IEmailSender emailSender = null;
protected static ISessionService session = null;
protected static IMyContext dbContext = null;
protected static IHostingEnvironment hostingEnvironment = null;
public NotifyController(
IEmailSender mailSenderService,
IMyContext context,
IHostingEnvironment env,
ISessionService sessionContext)
{
emailSender = mailSenderService;
dbContext = context;
hostingEnvironment = env;
session = sessionContext;
}
}
use GetRequiredService instead of GetService, like the example on ASP.NET Core tutorials ( https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/working-with-sql )
documentation on the method:
https://learn.microsoft.com/en-us/aspnet/core/api/microsoft.extensions.dependencyinjection.serviceproviderserviceextensions#Microsoft_Extensions_DependencyInjection_ServiceProviderServiceExtensions_GetRequiredService__1_System_IServiceProvider_
using Microsoft.Extensions.DependencyInjection;
using (var context = new ApplicationDbContext(serviceProvicer.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
Do not use GetService()
The difference between GetService and GetRequiredService is related with exception.
GetService() returns null if a service does not exist.
GetRequiredService() will throw exception.
public static class ServiceProviderServiceExtensions
{
public static T GetService<T>(this IServiceProvider provider)
{
return (T)provider.GetService(typeof(T));
}
public static T GetRequiredService<T>(this IServiceProvider provider)
{
return (T)provider.GetRequiredService(typeof(T));
}
}
Generally you want to have the DI do its thing and inject that for you:
public class Entity
{
private readonly IDataContext dbContext;
// The DI will auto inject this for you
public class Entity(IDataContext dbContext)
{
this.dbContext = dbContext;
}
public void DoSomething()
{
// dbContext is already populated for you
var something = dbContext.Somethings.First();
}
}
However, Entity would have to be automatically instantiated for you... like a Controller or a ViewComponent. If you need to manually instantiate this from a place where this dbContext is not available to you, then you can do this:
using Microsoft.Extensions.PlatformAbstractions;
public class Entity
{
private readonly IDataContext dbContext;
public class Entity()
{
this.dbContext = (IDataContext)CallContextServiceLocator.Locator.ServiceProvider
.GetService(typeof(IDataContext));
}
public void DoSomething()
{
var something = dbContext.Somethings.First();
}
}
But just to emphasize, this is considered an anti-pattern and should be avoided unless absolutely necessary. And... at the risk of making some pattern people really upset... if all else fails, you can add a static IContainer in a helper class or something and assign it in your StartUp class in the ConfigureServices method: MyHelper.DIContainer = builder.Build(); And this is a really ugly way to do it, but sometimes you just need to get it working.
I think the OP is getting confused. Entities should be as “thin” as possible. They should try not to contain logic, and or external references other than navigation properties. Look up some common patterns like repository pattern which helps to abstract your logic away from the entities themselves
Instead of getting your service inline, try injecting it into the constructor.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient(typeof(DataContext));
}
}
public class Entity
{
private DataContext _context;
public Entity(DataContext context)
{
_context = context;
}
public void DoSomething()
{
// use _context here
}
}
I also suggest reading up on what AddTransient means, as it will have a significant impact on how your application shares instances of DbContext. This is a pattern called Dependency Injection. It takes a while to get used to, but you will never want to go back once you do.

How to configure Auto mapper in class library project?

I am using auto mapping first time.
I am working on c# application and I want to use auto mapper.
(I just want to know how to use it, so I don't have asp.net app neither MVC app.)
I have three class library projects.
I want to write transfer process in the service project.
So I want to know how and where should I configure the Auto Mapper ?
So based on Bruno's answer here and John Skeet's post about singletons I came up with the following solution to have this run only once and be completely isolated in class library unlike the accepted answer which relies on the consumer of the library to configure the mappings in the parent project:
public static class Mapping
{
private static readonly Lazy<IMapper> Lazy = new Lazy<IMapper>(() =>
{
var config = new MapperConfiguration(cfg => {
// This line ensures that internal properties are also mapped over.
cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
cfg.AddProfile<MappingProfile>();
});
var mapper = config.CreateMapper();
return mapper;
});
public static IMapper Mapper => Lazy.Value;
}
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Source, Destination>();
// Additional mappings here...
}
}
Then in your code where you need to map one object to another you can just do:
var destination = Mapping.Mapper.Map<Destination>(yourSourceInstance);
NOTE: This code is based on AutoMapper 6.2 and it might require some tweaking for older versions of AutoMapper.
You can place the configuration anywhere:
public class AutoMapperConfiguration
{
public static void Configure()
{
Mapper.Initialize(x =>
{
x.AddProfile<MyMappings>();
});
}
}
public class MyMappings : Profile
{
public override string ProfileName
{
get { return "MyMappings"; }
}
protected override void Configure()
{
......
}
But it has to be called by the application using the libraries at some point:
void Application_Start()
{
AutoMapperConfiguration.Configure();
}
Nobody outside of your library has to configure AutoMapper
I recommend that you use the instance based approach using an IMapper. That way no one outside your library has to call any configuration method. You can define a MapperConfiguration and create the mapper from there all inside the class library.
var config = new MapperConfiguration(cfg => {
cfg.AddProfile<AppProfile>();
cfg.CreateMap<Source, Dest>();
});
IMapper mapper = config.CreateMapper();
// or
IMapper mapper = new Mapper(config);
var dest = mapper.Map<Source, Dest>(new Source());
Marko's answer is correct.
We can also go by a below simple solution.
public static class ObjectMapper
{
public static IMapper Mapper
{
get
{
return AutoMapper.Mapper.Instance;
}
}
static ObjectMapper()
{
CreateMap();
}
private static void CreateMap()
{
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<SourceClass, DestinationClass>();
});
}
}
And we can use it like.
public class SourceClass
{
public string Name { get; set; }
}
public class DestinationClass
{
public string Name { get; set; }
}
SourceClass c1 = new SourceClass() { Name = "Mr.Ram" };
DestinationClass c2 = ObjectMapper.Mapper.Map<DestinationClass>(c1);
I have used the Patel Vishal's solution and customized it to my needs.
It's a generic class which makes sure only one instance of mapping is saved in memory per object mapping.
TModel - is a DTO object
TData - is a Database table object in Entity Framework
DTO.IBaseModel - is a base class for DTO object which has one property: ID
IBaseModel - is a base class for the entity framework database entity with ID property only
public static class ObjectMapper<TModel, TData>
where TModel : class, DTO.IBaseModel, new()
where TData : class, IBaseModel, new()
{
private static readonly MapperConfiguration _mapperConfiguration;
public static IMapper Mapper => new Mapper(_mapperConfiguration);
static ObjectMapper()
{
_mapperConfiguration ??= CreateMap();
}
private static MapperConfiguration CreateMap()
{
return new (cfg =>
{
cfg.CreateMap<TData, TModel>();
});
}
}
I am using this class in a BaseService<TData, TModel> (Service/Repository pattern) as such:
public virtual TModel Convert(TData t)
{
return ObjectMapper<TModel, TData>.Mapper.Map<TModel>(t);
}
As you can see, it's a virtual method. Mapping can be overwritten, if customization required by the inheriting Service.
I have come across this kind of requirement as well. What I have done in .Net 6.0 is, I create a library project and create the profile class:
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<Entity, Dto>();
CreateMap<Dto, Entity>();
......
}
}
while in the api or web project, I just create a child class to inherit from the profile above, and register it in startup.cs services.AddAutoMapper(typeof(Startup));.

How do I use AutoMapper with Ninject.Web.Mvc?

Setup
I have an AutoMapperConfiguration static class that sets up the AutoMapper mappings:
static class AutoMapperConfiguration()
{
internal static void SetupMappings()
{
Mapper.CreateMap<long, Category>.ConvertUsing<IdToEntityConverter<Category>>();
}
}
where IdToEntityConverter<T> is a custom ITypeConverter that looks like this:
class IdToEntityConverter<T> : ITypeConverter<long, T> where T : Entity
{
private readonly IRepository _repo;
public IdToEntityConverter(IRepository repo)
{
_repo = repo;
}
public T Convert(ResolutionContext context)
{
return _repo.GetSingle<T>(context.SourceValue);
}
}
IdToEntityConverter takes an IRepository in its constructor in order to convert an ID back to the actual entity by hitting up the database. Notice how it doesn't have a default constructor.
In my ASP.NET's Global.asax, this is what I have for OnApplicationStarted() and CreateKernel():
protected override void OnApplicationStarted()
{
// stuff that's required by MVC
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
// our setup stuff
AutoMapperConfiguration.SetupMappings();
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<IRepository>().To<NHibRepository>();
return kernel;
}
So OnApplicationCreated() will call AutoMapperConfiguration.SetupMappings() to set up the mappings and CreateKernel() will bind an instance of NHibRepository to the IRepository interface.
Problem
Whenever I run this code and try to get AutoMapper to convert a category ID back to a category entity, I get an AutoMapperMappingException that says no default constructor exists on IdToEntityConverter.
Attempts
Added a default constructor to IdToEntityConverter. Now I get a NullReferenceException, which indicates to me that the injection isn't working.
Made the private _repo field into a public property and added the [Inject] attribute. Still getting NullReferenceException.
Added the [Inject] attribute on the constructor that takes an IRepository. Still getting NullReferenceException.
Thinking that perhaps Ninject can't intercept the AutoMapperConfiguration.SetupMappings() call in OnApplicationStarted(), I moved it to something that I know is injecting correctly, one of my controllers, like so:
public class RepositoryController : Controller
{
static RepositoryController()
{
AutoMapperConfiguration.SetupMappings();
}
}
Still getting NullReferenceException.
Question
My question is, how do I get Ninject to inject an IRepository into IdToEntityConverter?
#ozczecho's answer is spot-on, but I'm posting the Ninject version of the code because it has one little caveat that caught us for a while:
IKernel kernel = null; // Make sure your kernel is initialized here
Mapper.Initialize(map =>
{
map.ConstructServicesUsing(t => kernel.Get(t));
});
You can't just pass in kernel.Get to map.ConstructServicesUsing because that method has a params parameter in addition to the Type. But since params are optional, you can just create the lambda expression to generate an anonymous function to get you what you need.
You have to give AutoMapper access to the DI container. We use StructureMap, but I guess the below should work with any DI.
We use this (in one of our Bootstrapper tasks)...
private IContainer _container; //Structuremap container
Mapper.Initialize(map =>
{
map.ConstructServicesUsing(_container.GetInstance);
map.AddProfile<MyMapperProfile>();
}

Categories

Resources