0

I'm working on an MVC site that is using ASP.Net Identity for the log in piece.

There is a user table where the pk is an FK for another table (table 2). Because of this, the user cannot be deleted. As well, there are reports that are generated from table 2. This report displays the data from table 2 as long as the user name that generated the data. Another reason why deleting the user information should not be done.

So instead of deleting the user I thought I would add a column to the user table called "Deleted". It uses a bit datatype.

The column was added to my local copy of the database using code-first migrations. When the user logs on, this value is checked in this column is checked (0 = not deleted; 1 = deleted).

Everything was working great on my local machine. I had no errors, code ran fine. I was able to log in with any user. I then deployed to our test server and added the "Deleted" column to the table on the test SQL server using a script.

When I went to log in, with any user, I couldn't. I kept getting the "Error logging in. Please re-enter credentials and try again" even though my credentials were correct.

I deleted the files on the server and deployed again. Same thing.

I backed out all of my changes and deployed again and was able to log in. So, I started adding things a piece at a time:

  • I ran the script to add a Deleted column with a bit datatype and set to not null on our test SQL server
  • Tested logging in and was able to
  • Added public bool Deleted {get; set;} to my BL Entity and deployed to test
  • Tried logging in and failed

  • Removed the Deleted bool and re-deployed

  • Was able to log in

I'm not understanding why this addition is causing issues. "Deleted" columns are used in other tables in the application and have not caused any issues. And because it's working fine when I run it locally I'm having a hard time determining what the issue is.

Here is my BL Entity:

using Microsoft.AspNet.Identity.EntityFramework;
     using System;
 using System.Collections.Generic;
namespace BlahBlah.BusinessLogic.Entities
 {
public class User : IdentityUser
{
    public User() : base() { }

    public User(string username) : base(username) { }

    public Guid CompanyId { get; set; }

    public Company Company { get; set; }

    public bool PrimaryAccount { get; set; }

    public Guid DefaultCompanyId { get; set; }

    public ICollection<Transaction> Transactions { get; set; }

   // public bool Deleted { get; set; }

}
}   

Here is a piece of my user.js code:

...
$http(call)
            .success(function (data) {
                userData.isAuthenticated = true;
                userData.username = data.userName;
                userData.role = data.role;
                userData.bearerToken = data.access_token;
                userData.expirationDate = new Date(data['.expires']);

                setHttpAuthHeader();

                if (typeof successCallback === 'function') {
                    successCallback();
                }
            })
            .error(function (data) {

                if (typeof errorCallback === 'function') {
                    if (data.error_description) {
                        errorCallback(data.error_description);
                    }
                    else {

                        errorCallback('Unable to contact server; please, try again later.');
                    }
                }
            });
    };
... 

Here is a piece of my login.js code:

...
 function login(common, $location, config) {
    var getLogFn = common.logger.getLogFn;
    var log = getLogFn(controllerId);

    var vm = this;

    vm.title = 'Login';
    vm.credentials = {
        username: '',
        password: ''
    };
    vm.hideError = true;
    vm.errorMessage = 'xx.';

    vm.login = function login() {
        vm.hideError = true;
        common.$broadcast(config.events.spinnerToggle, { show: true });
        common.user.authenticate(vm.credentials.username, vm.credentials.password, onSuccessfullLogin, onFailedLogin);
    };
...
function onFailedLogin(error) {
        common.$broadcast(config.events.spinnerToggle, { show: false });
        console.log('error ' + error);
        vm.hideError = false;
    }
...  

Any ideas as to what is going on or how I can find out what is going on? Thanks for your time!

UPDATE I shouldn't have gotten too excited. After performing some testing in the application I thought I would test the reports. Everything was working beautifully up until then. When I viewed a report I got the following error:

The model backing the 'BabDbContext' context has changed since the database was created. Consider using Code First Migrations to update the database

The reports are using SSRS. If I ran the script to create the column AND update the _Migrations table I'm not understanding why I'm getting this error. The stack trace points to the last line. I've read suggestions but where I need to add some code to the OnModelCreating method but I'm not sure if that's the way to go. There have been other deploys done by others prior to me so I'm missing something.

public class AbaDbContext : IdentityDbContext<User>, IDbContext
{
    public const int UnknownCTId = 1;
    private IEncryptionService _encryptionService;
    private static Dictionary<Guid, string> _cipherCache = new Dictionary<Guid,string>();

    public BabDbContext()
        : base("BabDbContext")
    {
        ((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += new ObjectMaterializedEventHandler(ObjectMaterialized);
0

1 Answer 1

1

It looks like your context is trying to run migrations on the production server and is failing due to either insufficient permissions or that the Deleted column already exists. Your options are:

  1. Run your production migrations by creating a script. You can do this by running the following command:

    Update-Database -Script
    

    This will create a SQL script that yuo can run against your database to create the column and, critically, insert a row into the __MigrationHistory table that tells EF that it doesn't need to run migrations again.

  2. Create a context initialiser that effectively disables migrations. Add a class that inherits from NullDatabaseInitializer<T>:

    public class DisableMigrations : NullDatabaseInitializer<YourContext>
    {
    }
    

    And in your production web.config:

    <entityFramework>
      <contexts>
        <context type="YourNamespace.Domain.YourContext, YourNamespace.Domain">
          <databaseInitializer 
                  type="YourNamespace.Domain.DisableMigrations, YourNamespace.Domain"/>
        </context>
      </contexts>
    </entityFramework>
    
Sign up to request clarification or add additional context in comments.

3 Comments

THAT DID IT! I did use that command to generate a script but I only grabbed the part that added the "Deleted" column. I restored a backed up copy of the database and took the whole generated script this time and it worked. THANKS SO MUCH!
Glad it worked. Most people don't realise that the migrations table actually holds an entire EDMX model and if it doesn't match what EF has internally, it will run migrations again.
I shouldn't have gotten excited though. I updated my original question. I ended up adding this to the gobal.asax.cs file in the Reportviewer project: ` Database.SetInitializer<AbaDbContext>(null);`. I'm not understanding why I had to do that when it didn't need to be done by previous developers making changes?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.