Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SaveChanges with a UserManager does not record username #128

Open
jono-royle opened this issue Oct 26, 2016 · 14 comments
Open

SaveChanges with a UserManager does not record username #128

jono-royle opened this issue Oct 26, 2016 · 14 comments

Comments

@jono-royle
Copy link

Hi,
We are using an ASP.NET UserManager in our project. When we SaveChanges with the UserManager, it isn't using SaveChanges(userName) from the TrackerIdentityContext in your project, so we end up with the UserName column reading NULL for these changes in the AuditLog table.

Is there a way to solve this problem while still using the UserManager?
Thanks

@bilal-fazlani
Copy link
Owner

https://github.com/bilal-fazlani/tracker-enabled-dbcontext/wiki/4.-Username

Configure the username using above method.
Then use this configured trackercontext while creating user manager and it
should solve your problem.

Ps: I am just hoping that you can somehow pass the dbcontext while creating
a user manager.

Let me know.

On Wed 26 Oct, 2016 7:33 pm jono-royle, notifications@github.com wrote:

Hi,
We are using an ASP.NET UserManager in our project. When we SaveChanges
with the UserManager, it isn't using SaveChanges(userName) from the
TrackerIdentityContext in your project, so we end up with the UserName
column reading NULL for these changes in the AuditLog table.

Is there a way to solve this problem while still using the UserManager?
Thanks


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#128,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ADPSr8UdCHBnPXfxuK7At4ikPHt6Am32ks5q3126gaJpZM4KhNZE
.

@jono-royle
Copy link
Author

Hi, thanks for your help.
Configuring the username as you suggested worked for editing existing users, but we are still having the same problem when creating new users - the UserName column in the AuditLog table is NULL.

We are using the SaveChangesAsync() method for both editing existing users and creating new users. Do you know why these two might be different?
Thanks

@xsoheilalizadeh
Copy link

Do You Want Know About Differnce Between SaveChangesAsync() And SaveChanges() ?

@jono-royle
Copy link
Author

No sorry, both our EditUser method and CreateUser method are using the SaveChangesAsync() method, but it is only working correctly in the EditUser method.

@bilal-fazlani
Copy link
Owner

Show me your code

@jono-royle
Copy link
Author

jono-royle commented Oct 31, 2016

        [HttpPost]
        [ValidateAntiForgeryToken]
        [Route("create")]
        public async Task<ActionResult> Create(UserCreateViewModel model)
        {
            if (ModelState.IsValid)
            {
                var user = model.PopulateUser();
                user.Components = ParseSelectedComponents(model.Components);
                user.DateCreated = DateTime.UtcNow;

                user.UniqueId = GetNextUId();
                user.UserPermit = GenerateUserPermit(user.UniqueId);

                var result = await UserManager.CreateAsync(user);
                if (result.Succeeded)
                {
                    user = await UserManager.FindByIdAsync(user.Id);

                    if (user == null)
                    {
                        SetError(string.Format("User '{0}' successfully created, but we were unable to update user roles.", model.Email));
                        return RedirectToAction("Index");
                    }

                    var selectedRoleName = RoleNameFromId(model.RoleId);
                    UpdateUserRoles(selectedRoleName, user);

                    await _db.SaveChangesAsync();

                    return await SendUserTokenEmail(user.Id);
                }
            }

            // Need to reset list items for roles as these are not returned from the view model
            var roles = GetAllRoles().Where(r => IsSuperUser() ? true : r.Name !=  Role.SuperUser.ToString());
            model.ResetRolesListItems(roles);
            model.ResetCompanies(_db.Companies.Where(c => c.Enabled).ToList());

            // If we got this far, something failed, redisplay form
            return View(model);
        }

This is the code we have to create a new user. As you can see we call await _db.SaveChangesAsync(). We have other methods which edit users in the same class that also call SaveChangesAsync(), and those work as expected, but this doesn't. We configure the username in the class constructor as you suggested

@bilal-fazlani
Copy link
Owner

Show me
how _db is created ?
how UserManager is created ?
and where have you configured username ?

@jono-royle
Copy link
Author

jono-royle commented Oct 31, 2016

Creation of _db and username configured in class constructor:

        public BaseController()
        {
            Logger.SetGlobalContextProperty("SiteName", Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME"));
            _db = new DbContext();
            _db.ConfigureUsername(()=> User.Identity.Name);
        }

@jono-royle
Copy link
Author

jono-royle commented Oct 31, 2016

_db is created here:

    public class DBContext : TrackerIdentityContext<User>, IDbContext
    {
        public DbSet<Activation> Activations { get; set; }

        public DbSet<Company> Companies { get; set; }

        public DbSet<VersionInformation> VersionInformation { get; set; }

        private static string ContextName = "DbContext";

        static DbContext()
        {
            var dbName = ConfigurationManager.AppSettings["DatabaseName"];

            if (string.IsNullOrEmpty(dbName))
            {
                return;
            }

            var connStr = ConfigurationManager.ConnectionStrings[dbName];

            if (connStr == null)
            {
                throw new ConfigurationErrorsException(string.Format("ConnectionString '{0}' was not found", dbName));
            }

            ContextName = dbName;
        }

        public DbContext(string contextName)
            : base(contextName)
        {
            Database.SetInitializer<DbContext>(null);
            ((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized +=
                (sender, e) => DateTimeKindAttribute.Apply(e.Entity);
        }

        public DbContext()
            : this(ContextName)
        {
        }

@jono-royle
Copy link
Author

jono-royle commented Oct 31, 2016

How UserManager is created:

    public class AdeptUserManager : UserManager<AdeptUser>
    {
        public AdeptUserManager(IUserStore<AdeptUser> store)
            : base(store)
        {
        }

        public static AdeptUserManager Create(IdentityFactoryOptions<AdeptUserManager> options, IOwinContext context)
        {
            var manager = new AdeptUserManager(new UserStore<AdeptUser>(context.Get<AdeptContext>()));
            // Configure validation logic for usernames
            manager.UserValidator = new UserValidator<AdeptUser>(manager)
            {
                AllowOnlyAlphanumericUserNames = false,
                RequireUniqueEmail = true
            };

            // Configure validation logic for passwords
            manager.PasswordValidator = new PasswordValidator
            {
                RequiredLength = 8,
                RequireNonLetterOrDigit = false,
                RequireDigit = true,
                RequireLowercase = true,
                RequireUppercase = true,
            };

            // Configure user lockout defaults
            manager.UserLockoutEnabledByDefault = true;
            manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
            manager.MaxFailedAccessAttemptsBeforeLockout = 5;

            var apiKey = ConfigurationManager.AppSettings["sendGridApiKey"];

            if (string.IsNullOrEmpty(apiKey))
            {
                var smtp = new SmtpClient();
                manager.EmailService = new EmailService(
                    ConfigurationManager.AppSettings["mailFromAddress"],
                    smtp.Credentials,
                    ConfigurationManager.AppSettings["mailTemplateId"]);
            }
            else
            {
                manager.EmailService = new EmailService(
                    ConfigurationManager.AppSettings["mailFromAddress"],
                    apiKey,
                    ConfigurationManager.AppSettings["mailTemplateId"]);
            }

            var dataProtectionProvider = options.DataProtectionProvider;
            if (dataProtectionProvider != null)
            {
                manager.UserTokenProvider =
                    new DataProtectorTokenProvider<AdeptUser>(dataProtectionProvider.Create("Adept User Identity"))
                    {
                        TokenLifespan = TimeSpan.FromHours(48)
                    };
            }
            return manager;
        }
    }

@bilal-fazlani
Copy link
Owner

Your context class name is DBContext but you are creating an instance if DbContext in base controller ?

@bilal-fazlani
Copy link
Owner

Anyways,
try these things,

  1. Debug and find out the value of username at runtime. If the value of username is NULL it will be null in database.

  2. if at runtime it is not NULL, try setting GlobalTrackingConfig.DisconnectedContext = true; on application start.

@jono-royle
Copy link
Author

Sorry the DBContext DbContext was a typo, I changed the type names to remove some application specific jargon

  1. The username is not NULL at runtime
  2. I tried this, but there was no change

@jannohordijk
Copy link

_db.ConfigureUsername(()=> User.Identity.Name);

Maybe the cause for username being null is that there is no HttpContext available in the constructor of the controller. So, User is null and therefor no username is written in the logging?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants