Using Ninject in asp.net mvc GenerateUserIdentityAsync to add custom claim - asp.net-mvc

I need to add custom claims when a user signs in (external sign in from Google) by performing a read to the database and adding the values returned. I am using Ninject for dependency injection to inject controllers with interfaces to my business layer services.
So I have located the identityModels.cs method to add claims:
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
string userId = userIdentity.GetUserId();
//var _iUserBLL = (IUserBLL)System.Web.Mvc.DependencyResolver.Current.GetService(typeof(IUserBLL));
//UserBO objUser = _iUserBLL.GetById(userId);
//userIdentity.AddClaim(new Claim("Value1", objUser.Value1));
//userIdentity.AddClaim(new Claim("Value2", objUser.Value2));
return userIdentity;
}
Here the System.Web.Mvc.DependencyResolver.Current.GetService line fails and causes it to crash. This works elsewhere and I've also tried the same approach I use to inject controllers like:
public class MyController : Controller
{
private readonly IUserBLL _iUserBLL;
public MyController (IUserBLL iUserBLL)
{
_iUserBLL = iUserBLL;
}
}
And even:
[Inject]
public IUserBLL _iUserBLL { get; set; }
But when used in the GenerateUserIdentityAsync method the _iUserBLL is null. Any ideas how I can inject my IUserBLL to make a custom database call here?
A bit more info - if you aren't familiar with this method, it's part of the Identity code generated in a visual studio project with individual user accounts.
The full class is like so:
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity>
GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
...
}
}
So I tried the constructor in here, which doesn't work:
public class ApplicationUser : IdentityUser
{
private readonly IUserBLL _iUserBLL;
public ApplicationUser (IUserBLL iUserBLL)
{
_iUserBLL = iUserBLL;
}
...
}
The IdentityUser is declared in the inner workings of the pre supplied identity.entityframework class and is called from within that which I can't edit, so I'm confused how to approach this?
Thanks for your reply Sam, it put me onto a solution. Here is the code I ended up with. I had trouble with the static 'Create' method so I used the [Inject] attribute instead. Is there a way to alter the static 'Create' method to use IUserBLL in the constructor? Here is the code that I have working:
In App_Start/IdentityConfig.cs
// Configure the application sign-in manager which is used in this application.
public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
{
[Inject]
public IUserBLL _iUserBLL { get; set; }
public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{
}
public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
{
var userIdentity = user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
UserBO objUser = _iUserBLL.GetById(user.Id);
userIdentity.Result.AddClaim(new Claim("Claim1", objUser.Value1));
userIdentity.Result.AddClaim(new Claim("Claim2", objUser.Value2));
return userIdentity;
}
public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
{
return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
}
}
In my NinjectWebCommon.cs I also include these lines, extra to all my bindings:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<System.Security.Principal.IPrincipal>().ToMethod(context => HttpContext.Current.User).InRequestScope();
kernel.Bind<ApplicationUserManager>().ToMethod(context => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>()).InRequestScope();
kernel.Bind<ApplicationSignInManager>().ToMethod((context) =>
{
var cbase = new HttpContextWrapper(HttpContext.Current);
return cbase.GetOwinContext().Get<ApplicationSignInManager>();
});
...
}

ApplicationUser is an entity object and this kind of objects are responsible to holding data not doing logic. It will be much better if you add your custom claim in UserManager rather than ApplicationUser. Consider this:
public class ApplicationUserManager: UserManager<ApplicationUser>
{
private readonly IUserBLL _iUserBLL;
public ApplicationSignInManager(IUserStore<ApplicationUser> store,
IUserBLL iUserBLL)
: base(store)
{
// if you already fully integrated Identity with ninject,
// ninject could automatically resolve this for you.
_iUserBLL=iUserBLL;
// other configurations here
}
public override async Task<ClaimsIdentity> CreateIdentityAsync(
ApplicationUser user,
string authenticationType)
{
var userIdentity=await base.CreateIdentityAsync(user, authenticationType);
UserBO objUser = _iUserBLL.GetById(userId);
userIdentity.AddClaim(new Claim("Value1", objUser.Value1));
userIdentity.AddClaim(new Claim("Value2", objUser.Value2));
return userIdentity;
}
}

Related

can't return roles in AspNetRoles

i need to return all role in identity tabel for create a dropdown list .
public class ApplicationRoleManager : RoleManager<IdentityRole>
{
public ApplicationRoleManager(RoleStore<IdentityRole> store)
: base(store)
{
}
public static ApplicationRoleManager Create(IOwinContext context)
{
var Store = new RoleStore<IdentityRole>(context.Get<ApplicationDbContext>());
// Configure validation logic for usernames
return new ApplicationRoleManager(Store);
}
}
how should i do this ?
Edit
/*******************************************************************************************************/
The process to get all roles via setting up ApplicationRoleManager is the following (as per Identity samples provided by Microsoft found here).
Add the code below to your IdentityConfig.cs
public class ApplicationRoleManager : RoleManager<IdentityRole>
{
public ApplicationRoleManager(IRoleStore<IdentityRole, string> roleStore)
: base(roleStore)
{
}
public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
{
return new ApplicationRoleManager(new RoleStore<IdentityRole>(context.Get<ApplicationDbContext>()));
}
}
Then initialize the single instance per Owin context of your RoleManager in Startup.Auth.cs:
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
In your controller where you want to get all roles, do the following:
private ApplicationRoleManager _roleManager;
public ApplicationRoleManager RoleManager
{
get
{
return _roleManager ?? HttpContext.GetOwinContext().Get<ApplicationRoleManager>();
}
private set
{
_roleManager = value;
}
}
After that you can simply use RoleManager.Roles in any of your action methods to get all roles.
This answer contains all the steps you need to get this to work but refer to the link to the nuget package above if you're still unclear on the process.

how to implement dependency injection in mvc?

I'm trying to implement dependency injection but i know how to implement the interface and repository of classes then i don't know what shall i do.
This my sample:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
}
This is my interface:
public interface IUser
{
IEnumerable<User> GetUsers();
void AddUser(User user);
void EditUser(User user);
void DeleteUser(int id);
User UserGetById(int id);
void Save();
}
This is my repository:
public class UserRepsitory:IUser
{
private _Context _context;
public UserRepsitory(_Context _context)
{
this._context = _context;
}
public IEnumerable<User> GetUsers()
{
return _context.User.ToList();
}
public void AddUser(User user)
{
_context.User.Add(user);
}
public void EditUser(User user)
{
_context.Entry(user).State = System.Data.Entity.EntityState.Modified;
}
public User UserGetById(int id)
{
return _context.User.Find(id);
}
public void Save()
{
_context.SaveChanges();
}
public void DeleteUser(int id)
{
var Search = _context.User.Find(id);
_context.User.Remove(Search);
}
}
And one of method in controller:
private IUser userRepsitory;
public UsersController()
{
this.userRepsitory = new UserRepsitory(new _Context());
}
public UsersController(IUser UserRepository)
{
this.userRepsitory = UserRepository;
}
public ActionResult Index()
{
return View(userRepsitory.GetUsers());
}
What is the next step?
The first thing is, get rid of the default constructor where we are hard coding the initialization of UserRepository ! We will do that in the dependency injection way.
public UsersController : Controller
{
private readonly IUser userRepsitory;
public UsersController(IUser UserRepository)
{
this.userRepsitory = UserRepository;
}
public ActionResult Index()
{
return View(userRepsitory.GetUsers());
}
}
Now we need something to tell the MVC framework which version/implementation of IUser should be used when the code runs. you can use any dependency injection frameworks to do that. For example, If you are in MVC 6, you can use the inbuilt dependency injection framework to do that. So go to your Startup class and in your ConfigureServices method, you can map an interface to a concrete implementation.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IUser, UserRepository>();
}
}
If you are in a previous version of MVC, you may consider using any of the dependency injection frameworks available like Unity, Ninject etc.
It is pretty much same, you map an interface to a concrete implementation
Ninject
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUser>().To<UserRepository>();
}
You do not need to put the mapping in a cs file. You can define that in a config file. For example, when you use Unity you can do something like this in your config file (web config or an external config file for unity configuration)
Unity
<alias alias="IUser" type="YourNamespace.IUser, YourAssemblyName" />
<register type="IUser" mapTo="YourNamespace.UseRepository, YourAssemblyName">
In order to create and configure your project with Spring DI(Dependency Feature) you must configure beans.
Create an xml file (if its not there) and add references to bean
In this xml file, provide references to the classes you want to inject. Example:
<bean id="Name of the JAVA Class" class="the Full path of the JAVA class"/>
And in your class where you are supposed to call the referencing class(above), calling procedure would be like :
#Controller
public class MyController {
private full.path.of.my.class.named.MyJavaClass _class;
#Autowired
private MyController (full.path.of.my.class.MyJavaClass class)
{
this._class= class;
}
}
Now say if you a function in MyJavaClass
public int sum(int x, int y){
return x+y;
}
Then without creating object of MyJavaClass you can inject like the following in your controller:
_class.Sum(10,15);
YOU DO NOT CREATE AN INSTANCE OF THIS CLASS.

Accessing UserManager outside AccountController

I am trying to set the value of a column in aspnetuser table from a different controller (not accountcontroller). I have been trying to access UserManager but I can't figure our how to do it.
So far I have tried the following in the controller I want to use it in:
ApplicationUser u = UserManager.FindById(User.Identity.GetUserId());
u.IsRegComplete = true;
UserManager.Update(u);
This would not compile (I think because UserManager has not been instantiated the controller)
I also tried to create a public method in the AccountController to accept the value I want to change the value to and do it there but I can't figure out how to call it.
public void setIsRegComplete(Boolean setValue)
{
ApplicationUser u = UserManager.FindById(User.Identity.GetUserId());
u.IsRegComplete = setValue;
UserManager.Update(u);
return;
}
How do you access and edit user data outside of the Account Controller?
UPDATE:
I tried to instantiate the UserManager in the other controller like so:
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
ApplicationUser u = userManager.FindById(User.Identity.GetUserId());
I the project complied (got a little excited) but when I ran the code I get the following error:
Additional information: The entity type ApplicationUser is not part of the model for the current context.
UPDATE 2:
I have moved the function to the IdentityModel (don't ask I am clutching at straws here) like so:
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
public Boolean IsRegComplete { get; set; }
public void SetIsRegComplete(string userId, Boolean valueToSet)
{
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>());
ApplicationUser u = new ApplicationUser();
u = userManager.FindById(userId);
u.IsRegComplete = valueToSet;
return;
}
}
However I am still getting the following:
The entity type ApplicationUser is not part of the model for the current context.
There is also the following class in IdentitiesModels.cs:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
What am I doing wrong here? It feels like I am completely barking up the wrong tree. All I am trying to do is update a column in aspnetuser table from the action of a different controller (i.e not the AccountsController).
If you're using the default project template, the UserManager gets created the following way:
In the Startup.Auth.cs file, there's a line like this:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
that makes OWIN pipeline instantiate an instance of ApplicationUserManager each time a request arrives at the server. You can get that instance from OWIN pipeline using the following code inside a controller:
Request.GetOwinContext().GetUserManager<ApplicationUserManager>()
If you look carefully at your AccountController class, you'll see the following pieces of code that makes access to the ApplicationUserManager possible:
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
Please note, that in case you need to instantiate the ApplicationUserManager class, you need to use the ApplicationUserManager.Create static method so that you have the appropriate settings and configuration applied to it.
If you have to get UserManager's instance in another Controller just add its parameter in Controller's constructor like this
public class MyController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public MyController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;;
}
}
But I have to get UserManager in a class that is not controller !
Any help would be appreciated.
UPDATE
I am considering you are using asp.net core
I ran into this same problem and modified my code to pass a reference to the UserManager class from the Controller to the Model:
//snippet from Controller
public async Task<JsonResult> UpdateUser(ApplicationUser applicationUser)
{
return Json(await UserIdentityDataAccess.UpdateUser(UserManager, applicationUser));
}
//snippet from Data Model
public static async Task<IdentityResult> UpdateUser(ApplicationUserManager userManager, ApplicationUser applicationUser)
{
applicationUser.UserName = applicationUser.Email;
var result = await userManager.UpdateAsync(applicationUser);
return result;
}
FOR MVC 5
The steps to access usermanger or createUser outside Account controller is easy. Follow the below steps
Create a controller, consider SuperAdminController
Decorate the SuperAdminController same as the AccountController as below,
private readonly IAdminOrganizationService _organizationService;
private readonly ICommonService _commonService;
private ApplicationSignInManager _signInManager;
private ApplicationUserManager _userManager;
public SuperAdminController()
{
}
public SuperAdminController(ApplicationUserManager userManager, ApplicationSignInManager signInManager)
{
UserManager = userManager;
SignInManager = signInManager;
}
public SuperAdminController(IAdminOrganizationService organizationService, ICommonService commonService)
{
if (organizationService == null)
throw new ArgumentNullException("organizationService");
if (commonService == null)
throw new ArgumentNullException("commonService");
_organizationService = organizationService;
_commonService = commonService;
}
public ApplicationSignInManager SignInManager
{
get
{
return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
private set
{
_signInManager = value;
}
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
Create User in Action method
[HttpPost]
public async Task<ActionResult> AddNewOrganizationAdminUser(UserViewModel userViewModel)
{
if (!ModelState.IsValid)
{
return View(userViewModel);
}
var user = new ApplicationUser { UserName = userViewModel.Email, Email = userViewModel.Email };
var result = await UserManager.CreateAsync(user, userViewModel.Password);
if (result.Succeeded)
{
var model = Mapper.Map<UserViewModel, tblUser>(userViewModel);
var success = _organizationService.AddNewOrganizationAdminUser(model);
return RedirectToAction("OrganizationAdminUsers", "SuperAdmin");
}
AddErrors(result);
return View(userViewModel);
}
If you need access to the UserManager outside of a controller you can use the following:
var userStore = new UserStore<ApplicationUser>(new ApplicationDbContext());
var applicationManager = new ApplicationUserManager(userStore);

How to implement IIdentity for a custom User object in ASP.NET MVC?

In my ASP.NET MVC app, I'm trying to create a custom HttpContent.User object. I've started by creating a Member class, which implements IPrincioal.
public class Member : IPrincipal
{
public string Id { get; set; }
public IIdentity Identity { get; set; }
public bool IsInRole(string role) { throw new NotImplementedException(); }
...
}
Then at authentication time I set HttpContext.User to an instance of a Member class:
FormsAuthentication.SetAuthCookie(email, false);
HttpContext.User = member;
Then later I want to check if the user is authenticated, like so:
if (User.Identity.IsAuthenticated) { ... }
That's where I'm stuck. I'm not sure what I need to do for the public IIdentity Identity property on the instance of the Member. So that I can use the HttpContext.User object something like this:
IsAuthenticated = HttpContext.User.Identity.IsAuthenticated;
ViewBag.IsAuthenticated = IsAuthenticated;
if (IsAuthenticated) {
CurrentMember = (Member)HttpContext.User;
ViewBag.CurrentMember = CurrentMember;
}
A Principal is not something you can just set once when writing the auth cookie and forget later. During subsequent requests, the auth cookie is read and the IPrincipal / IIdentity is reconstructed before executing an action method. When that happens, trying to cast the HttpContext.User to your custom Member type will throw an exception.
One option would be to intercept in an ActionFilter, and just wrap the standard implementation.
public class UsesCustomPrincipalAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var systemPrincipal = filterContext.HttpContext.User;
var customPrincipal = new Member(systemPrincipal)
{
Id = "not sure where this comes from",
};
filterContext.HttpContext.User = customPrincipal;
}
}
public class Member : IPrincipal
{
private readonly IPrincipal _systemPrincipal;
public Member(IPrincipal principal)
{
if (principal == null) throw new ArgumentNullException("principal");
_systemPrincipal = principal;
}
public string Id { get; set; }
public IIdentity Identity { get { return _systemPrincipal.Identity; } }
public bool IsInRole(string role)
{
return _systemPrincipal.IsInRole(role);
}
}
This way, you're not losing anything that comes out of the box with the default IPrincipal and IIdentity implementations. You can still invoke IsAuthenticated on the IIdentity, or even IsInRole(string) on the IPrincipal. The only thing you're gaining is the extra Id property on your custom IPrincipal implementation (though I'm not sure where this comes from or why you need it).

Where to place AutoMapper.CreateMaps?

I'm using AutoMapper in an ASP.NET MVC application. I was told that I should move the AutoMapper.CreateMap elsewhere as they have a lot of overhead. I'm not too sure how to design my application to put these calls in just 1 place.
I have a web layer, service layer and a data layer. Each a project of its own. I use Ninject to DI everything. I'll utilize AutoMapper in both web and service layers.
So what are your setup for AutoMapper's CreateMap? Where do you put it? How do you call it?
Doesn't matter, as long as it's a static class. It's all about convention.
Our convention is that each "layer" (web, services, data) has a single file called AutoMapperXConfiguration.cs, with a single method called Configure(), where X is the layer.
The Configure() method then calls private methods for each area.
Here's an example of our web tier config:
public static class AutoMapperWebConfiguration
{
public static void Configure()
{
ConfigureUserMapping();
ConfigurePostMapping();
}
private static void ConfigureUserMapping()
{
Mapper.CreateMap<User,UserViewModel>();
}
// ... etc
}
We create a method for each "aggregate" (User, Post), so things are separated nicely.
Then your Global.asax:
AutoMapperWebConfiguration.Configure();
AutoMapperServicesConfiguration.Configure();
AutoMapperDomainConfiguration.Configure();
// etc
It's kind of like an "interface of words" - can't enforce it, but you expect it, so you can code (and refactor) if necessary.
EDIT:
Just thought I'd mention that I now use AutoMapper profiles, so the above example becomes:
public static class AutoMapperWebConfiguration
{
public static void Configure()
{
Mapper.Initialize(cfg =>
{
cfg.AddProfile(new UserProfile());
cfg.AddProfile(new PostProfile());
});
}
}
public class UserProfile : Profile
{
protected override void Configure()
{
Mapper.CreateMap<User,UserViewModel>();
}
}
Much cleaner/more robust.
You can really put it anywhere as long as your web project references the assembly that it is in. In your situation I would put it in the service layer as that will be accessible by the web layer and the service layer and later if you decide to do a console app or you are doing a unit test project the mapping configuration will be available from those projects as well.
In your Global.asax you will then call the method that sets all of your maps. See below:
File AutoMapperBootStrapper.cs
public static class AutoMapperBootStrapper
{
public static void BootStrap()
{
AutoMapper.CreateMap<Object1, Object2>();
// So on...
}
}
Global.asax on application start
just call
AutoMapperBootStrapper.BootStrap();
Now some people will argue against this method violates some SOLID principles, which they have valid arguments. Here they are for the reading.
Configuring Automapper in Bootstrapper violates Open-Closed Principle?
Update: The approach posted here is no more valid as SelfProfiler has been removed as of AutoMapper v2.
I would take a similar approach as Thoai. But I would use the built-in SelfProfiler<> class to handle the maps, then use the Mapper.SelfConfigure function to initialize.
Using this object as the source:
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public string GetFullName()
{
return string.Format("{0} {1}", FirstName, LastName);
}
}
And these as the destination:
public class UserViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class UserWithAgeViewModel
{
public int Id { get; set; }
public string FullName { get; set; }
public int Age { get; set; }
}
You can create these profiles:
public class UserViewModelProfile : SelfProfiler<User,UserViewModel>
{
protected override void DescribeConfiguration(IMappingExpression<User, UserViewModel> map)
{
//This maps by convention, so no configuration needed
}
}
public class UserWithAgeViewModelProfile : SelfProfiler<User, UserWithAgeViewModel>
{
protected override void DescribeConfiguration(IMappingExpression<User, UserWithAgeViewModel> map)
{
//This map needs a little configuration
map.ForMember(d => d.Age, o => o.MapFrom(s => DateTime.Now.Year - s.BirthDate.Year));
}
}
To initialize in your application, create this class
public class AutoMapperConfiguration
{
public static void Initialize()
{
Mapper.Initialize(x=>
{
x.SelfConfigure(typeof (UserViewModel).Assembly);
// add assemblies as necessary
});
}
}
Add this line to your global.asax.cs file: AutoMapperConfiguration.Initialize()
Now you can place your mapping classes where they make sense to you and not worry about one monolithic mapping class.
For those of you who adhere to the following:
using an ioc container
don't like to break open closed for this
don't like a monolithic config file
I did a combo between profiles and leveraging my ioc container:
IoC configuration:
public class Automapper : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<Profile>().WithServiceBase());
container.Register(Component.For<IMappingEngine>().UsingFactoryMethod(k =>
{
Profile[] profiles = k.ResolveAll<Profile>();
Mapper.Initialize(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
profiles.ForEach(k.ReleaseComponent);
return Mapper.Engine;
}));
}
}
Configuration example:
public class TagStatusViewModelMappings : Profile
{
protected override void Configure()
{
Mapper.CreateMap<Service.Contracts.TagStatusViewModel, TagStatusViewModel>();
}
}
Usage example:
public class TagStatusController : ApiController
{
private readonly IFooService _service;
private readonly IMappingEngine _mapper;
public TagStatusController(IFooService service, IMappingEngine mapper)
{
_service = service;
_mapper = mapper;
}
[Route("")]
public HttpResponseMessage Get()
{
var response = _service.GetTagStatus();
return Request.CreateResponse(HttpStatusCode.Accepted, _mapper.Map<List<ViewModels.TagStatusViewModel>>(response));
}
}
The trade-off is that you have to reference the Mapper by the IMappingEngine interface instead of the static Mapper, but that's a convention I can live with.
All of above solutions provide a static method to call (from app_start or any where) that it should call other methods to configure parts of mapping-configuration. But, if you have a modular application, that modules may plug in and out of application at any time, these solutions does not work. I suggest using WebActivator library that can register some methods to run on app_pre_start and app_post_start any where:
// in MyModule1.dll
public class InitMapInModule1 {
static void Init() {
Mapper.CreateMap<User, UserViewModel>();
// other stuffs
}
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule1), "Init")]
// in MyModule2.dll
public class InitMapInModule2 {
static void Init() {
Mapper.CreateMap<Blog, BlogViewModel>();
// other stuffs
}
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule2), "Init")]
// in MyModule3.dll
public class InitMapInModule3 {
static void Init() {
Mapper.CreateMap<Comment, CommentViewModel>();
// other stuffs
}
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule2), "Init")]
// and in other libraries...
You can install WebActivator via NuGet.
In addition to the best answer, a good way is using Autofac IoC liberary to add some automation. With this you just define your profiles regardless of initiations.
public static class MapperConfig
{
internal static void Configure()
{
var myAssembly = Assembly.GetExecutingAssembly();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(myAssembly)
.Where(t => t.IsSubclassOf(typeof(Profile))).As<Profile>();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var profiles = container.Resolve<IEnumerable<Profile>>();
foreach (var profile in profiles)
{
Mapper.Initialize(cfg =>
{
cfg.AddProfile(profile);
});
}
}
}
}
and calling this line in Application_Start method:
MapperConfig.Configure();
The above code finds all Profile sub classes and initiate them automatically.
Putting all the mapping logic in 1 location is not a good practice for me. Because the mapping class will be extremely large and very hard to maintain.
I recommend put the mapping stuff together with the ViewModel class in the same cs file. You can easily navigate to the mapping definition you want following this convention. Moreover, while creating the mapping class, you can reference to the ViewModel properties faster since they are in the same file.
So your view model class will look like:
public class UserViewModel
{
public ObjectId Id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class UserViewModelMapping : IBootStrapper // Whatever
{
public void Start()
{
Mapper.CreateMap<User, UserViewModel>();
}
}
From new version of AutoMapper using static method Mapper.Map() is deprecated. So you can add MapperConfiguration as static property to MvcApplication (Global.asax.cs) and use it to create instance of Mapper.
App_Start
public class MapperConfig
{
public static MapperConfiguration MapperConfiguration()
{
return new MapperConfiguration(_ =>
{
_.AddProfile(new FileProfile());
_.AddProfile(new ChartProfile());
});
}
}
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
internal static MapperConfiguration MapperConfiguration { get; private set; }
protected void Application_Start()
{
MapperConfiguration = MapperConfig.MapperConfiguration();
...
}
}
BaseController.cs
public class BaseController : Controller
{
//
// GET: /Base/
private IMapper _mapper = null;
protected IMapper Mapper
{
get
{
if (_mapper == null) _mapper = MvcApplication.MapperConfiguration.CreateMapper();
return _mapper;
}
}
}
https://github.com/AutoMapper/AutoMapper/wiki/Migrating-from-static-API
For those who are (lost) using:
WebAPI 2
SimpleInjector 3.1
AutoMapper 4.2.1 (With Profiles)
Here's how I managed integrating AutoMapper in the "new way". Also,
a Huge thanks to this answer(and question)
1 - Created a folder in the WebAPI project called "ProfileMappers". In this folder I place all my profiles classes which creates my mappings:
public class EntityToViewModelProfile : Profile
{
protected override void Configure()
{
CreateMap<User, UserViewModel>();
}
public override string ProfileName
{
get
{
return this.GetType().Name;
}
}
}
2 - In my App_Start, I have a SimpleInjectorApiInitializer which configures my SimpleInjector container:
public static Container Initialize(HttpConfiguration httpConfig)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
//Register Installers
Register(container);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
//Verify container
container.Verify();
//Set SimpleInjector as the Dependency Resolver for the API
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
httpConfig.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
return container;
}
private static void Register(Container container)
{
container.Register<ISingleton, Singleton>(Lifestyle.Singleton);
//Get all my Profiles from the assembly (in my case was the webapi)
var profiles = from t in typeof(SimpleInjectorApiInitializer).Assembly.GetTypes()
where typeof(Profile).IsAssignableFrom(t)
select (Profile)Activator.CreateInstance(t);
//add all profiles found to the MapperConfiguration
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
//Register IMapper instance in the container.
container.Register<IMapper>(() => config.CreateMapper(container.GetInstance));
//If you need the config for LinqProjections, inject also the config
//container.RegisterSingleton<MapperConfiguration>(config);
}
3 - Startup.cs
//Just call the Initialize method on the SimpleInjector class above
var container = SimpleInjectorApiInitializer.Initialize(configuration);
4 - Then, in your controller just inject as usually a IMapper interface:
private readonly IMapper mapper;
public AccountController( IMapper mapper)
{
this.mapper = mapper;
}
//Using..
var userEntity = mapper.Map<UserViewModel, User>(entity);
For vb.net programmers using the new Version (5.x) of AutoMapper.
Global.asax.vb:
Public Class MvcApplication
Inherits System.Web.HttpApplication
Protected Sub Application_Start()
AutoMapperConfiguration.Configure()
End Sub
End Class
AutoMapperConfiguration:
Imports AutoMapper
Module AutoMapperConfiguration
Public MapperConfiguration As IMapper
Public Sub Configure()
Dim config = New MapperConfiguration(
Sub(cfg)
cfg.AddProfile(New UserProfile())
cfg.AddProfile(New PostProfile())
End Sub)
MapperConfiguration = config.CreateMapper()
End Sub
End Module
Profiles:
Public Class UserProfile
Inherits AutoMapper.Profile
Protected Overrides Sub Configure()
Me.CreateMap(Of User, UserViewModel)()
End Sub
End Class
Mapping:
Dim ViewUser = MapperConfiguration.Map(Of UserViewModel)(User)

Resources