Search code examples
asp.net-mvcentity-frameworkasp.net-identity-2

Identity 2.0 User with partial DbContext MVC 5


I want in my context partial class to add some "automated" functionalities such as CreatedBy and ModifiedBy.

enter image description here

I have 2 projects: DataAccess and MVC (StartUp project).

I cannot get an assembly reference in my context partial class in folder Context (please, see the photo), is there any way to do this? I have installed all necessary nu-get components

So, I have red underline when I try to call User.Identity.GetUserId(); As you can see on the image, I even pulled out class IdentityModels.cs in that Project (DataAccess), but with no luck.

my context class looks like:

 using System;
 using System.Collections.Generic;
 using System.Data.Entity;
 using System.Data.Entity.Core.Objects;
 using System.Data.Entity.Infrastructure;
 using System.Data.SqlClient;
 using System.Linq;
 using System.Net;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web; 
 using System.Web.Mvc;
 using Microsoft.AspNet.Identity;
 using Microsoft.VisualBasic.ApplicationServices;
 using Owin;

 namespace DataAccess
{
public partial class SalesManagementEntities
{

    private bool doSaveChangesOverride = true;

    public bool DoSaveChangesOverride
    {
        set { doSaveChangesOverride = value; }
        get { return doSaveChangesOverride; }
    }

    public override int SaveChanges()
    {
        try
        {
            if (DoSaveChangesOverride)
                SaveChangesOverride();
            return base.SaveChanges();
        }
        catch (Exception ex)
        {

            throw ex;
        }

    }

    public override Task<int> SaveChangesAsync()
    {
        if (DoSaveChangesOverride)
            SaveChangesOverride();

        return base.SaveChangesAsync();
    }

    private void SaveChangesOverride()
    {
        ObjectContext context = ((IObjectContextAdapter)this).ObjectContext;

        //Find all Entities that are Added/Modified that inherit from my EntityBase
        IEnumerable<ObjectStateEntry> objectStateEntries =
            from e in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified)
            where
                e.IsRelationship == false &&
                e.Entity is IEntityBase
            select e;

        var currentTime = DateTime.Now;

        string userId = User.Identity.GetUserId();

        foreach (var entry in objectStateEntries)
        {
            var entityBase = entry.Entity as IEntityBase;

            if (entry.State == EntityState.Added)
            {
                entityBase.SetCreatedDateTime(currentTime);
                entityBase.SetCreatedBy(userId);

            }

            entityBase.SetModifiedDateTime(currentTime);
            entityBase.SetModifiedBy(userId);
        }
    }

}
}

Solution

  • The following code :

    User.Identity.GetUserId();
    

    will work only if you are inside a mvc controller because a mvc controller exposes a property named User which is in IPrincipal type that let you get access to IPrincipal members like Identity etc...

    Your DbContext doesn't have a User property but a User class and the compiler attempts to check if a static property named Identity exist into a that class and will not find that property and finally raises an error for that.

    To get the current user Id in your DAL layer you must use the following code :

    // There is no nuget package to install to get the user name.
    // If the user name is unique into your database table then 
    // you can request your DbContext and get the user id.
    var userName = System.Web.HttpContext.Current.User.Identity.Name;
    

    If you want to get the user id like you will do into your controller by using GetUserId or GetUserId<T> extension methods then use the following code :

    // You need to install the Microsoft.AspNet.Identity.Core nuget package
    // and get the user id like this:
    var userId = System.Web.HttpContext.Current.User.Identity.GetUserId();
    

    I recommend you to use a service that will give you the current IIdentity. Doing that will help for unit tests because mocking the current user will be easy.