I have definitely painted myself into this particular corner before!
There are a few strategies you can take to resolve this, including the two you listed. The approach I‘d recommend, however, is to use interfaces.
Summary
Instead of having a concrete User class, you’ll instead have an IUser interface which you’ll reference from the models in Project A. You’ll then apply the IUser interface to your ApplicationUser class. This will allow instances of ApplicationUser to be assigned to your e.g. Address.User property, despite the fact that Address isn’t aware of ApplicationUser.
Example
In Project A, you’ll update your classes to something like the following:
public class Address
{
public int Id {get;set;}
public string AddressText {get;set;}
public virtual IUser User {get;set;}
}
public interface IUser
{
int UserId {get;set;}
int UserName {get;set;}
ICollection<Address> {get;set;}
}
Then, in Project B, you’ll apply the IUser interface to your ApplicationUser class and ensure it implements the required properties:
public class ApplicationUser: IdentityUser, IUser
{
…
public int UserId {get;set;}
public ICollection<Address> {get;set;}
}
Note: You don’t need to implement UserName, as that’s already been implemented on IdentityUser. Though, of course, you can always override the property, should the need arise (e.g., to add validation attributes).
Limitations
When you access e.g., your Address.User property, you’ll only be able to access the members you defined on IUser. If you need to access any additional members defined on either ApplicationUser or IdentityUser, you will first need to cast your IUser reference to an ApplicationUser; e.g.,
var user = address.User as ApplicationUser;
var emailConfirmed = user?.EmailConfirmed?? false;
Of course, if you know you’re going to need access to these members, you can just make sure they’re defined on your interface, and not have to worry about this.
Caveats
There are a couple of considerations worth being aware of. These may not apply to you, but I want to include them for completeness.
O/RM
As mentioned in my comment, if you’re using an O/RM to populate your models—such as Entity Framework (EF) Core—you may run into problems identifying a concrete implementation of your interface in a separate assembly. This can be done, but it definitely adds complexity which you may not want to contend with! If you’re manually constructing your object graph, though, this won’t be an issue.
Identity vs User Models
The IdentityUser is meant to represent the currently authenticated user, not a general user reference. For instance, in an e-commerce app, it doesn’t make sense to construct an IdentityUser for references to the seller of each product. There is obviously overlap here, and using one data source to feed both is fine. But there are also properties—such as PasswordHash or SecurityStamp—which don’t make sense to populate on a general user model. You may eventually find these needs in conflict with one another.
In either of the above cases, you may find it easier to differentiate between your ApplicationUser and your User classes. That’s not what you asked for, but it’s worth considering. In that case, @RomanKalinchuk‘s approach makes more sense. Though, even then, you can still unify them by applying the same IUser interface to each, thus ensuring they share a core set of properties.