Adding a class which uses DbContext to ASP.NET Identity 2 project - c#

I'm working with ASP.NET MVC application which is based on Identity sample available via NuGet. Because of this I already have some classes to work with the database e.g. ApplicationDbContext.
Say, I decided to let users leave requests for the administrator. I've added the Request class to the models:
public class Request
{
public int Id { get; set; }
public string Message { get; set; }
public ApplicationUser User { get; set; }
}
Since the sample uses different managers to work with users, roles, etc, I've decided to create another one called ApplicationRequestManager inside the Identity.config file (though I'm not sure it's a good practice).
public class ApplicationRequestManager : IRequestManager
{
private ApplicationDbContext db = new ApplicationDbContext();
public void Add(Request request)
{
db.Requests.Add(request);
db.SaveChanges();
}
...
}
This class uses the ApplicationDbContext to work with the database and has some methods to create a request, find it and so on.
I've created a method responsible for sending request inside the Manage controller:
public ActionResult SendRequest(IndexViewModel model)
{
Request request = new Request { Message = model.Message, User = UserManager.FindById(User.Identity.GetUserId()) };
requestManager.Add(request);
return View();
}
When this method is invoked, I get the following exception:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
If I understood correctly, the reason of exception is that I use one ApplicationDbContext to get User - via UserManager and I use another ApplicationDbContext to add the request - via RequestManager, so my request is attached to two contexts. As far as I know, such mistake can be avoided by passing the same context to both UserManager and RequestManager. However, UserManager gets its context via the OwinContext together with other managers:
// Configure the db context, user manager and role manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
How can I make my own manager follow that pattern as well? I've tried to use the CreatePerOwinContext method like
app.CreatePerOwinContext<ApplicationRequestManager>(ApplicationRequestManager.Create);
And I've also tried to implement the Create method following the RoleManager example
public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
{
return new ApplicationRoleManager(new RoleStore<ApplicationRole>(context.Get<ApplicationDbContext>()));
}
But I don't have any Store for my requests so I don't know what I should do with the 'new RoleStore' part. How could I solve that problem?
Updated:
I've tried Gert's solution and it worked:
public class Request
{
public int Id { get; set; }
public string Message { get; set; }
[ForeignKey("User")]
public int ApplicationUserId { get; set; }
public ApplicationUser User { get; set; }
}
var userId = User.Identity.GetUserId();
Request request = new Request
{
Message = model.Message,
ApplicationUserId = userId
};
I've also tired another way using HttpConext.Current.GetOwinContext().Get method. I've added the following line to my ApplicationRequestMananger:
public ApplicationRequestManager()
{
this.db = HttpContext.Current.GetOwinContext().Get<ApplicationDbContext>();
}
And it worked fine with the original Request class.
The question is, what advantages and disadvantages does each way have? I've read about foreign keys and I understand the general idea quite well; but I don't really understand what problems can 'HttpContext.Current.GetOwinContext().Get()' cause. Should I use it since it's simpler than adding foreign keys?

The trouble with your design is that each manager has its own context. Seeing this example, I think each manager should call...
db = context.Get<ApplicationDbContext>();
...or receive the request-bounded context in their constructor.
Apart from that, you could make this much simpler by exposing the foreign field to ApplicationUser (ApplicationUserId?) as a primitive property in Request:
public class Request
{
public int Id { get; set; }
public string Message { get; set; }
[ForeignKey("User")]
public int ApplicationUserId { get; set; }
public ApplicationUser User { get; set; }
}
And then create Request like so:
var userId = User.Identity.GetUserId();
Request request = new Request
{
Message = model.Message,
ApplicationUserId = userId
};
This is refered to as foreign key associations, as opposed to independent associations that only have a reference navigation property.

Related

Too Many Dependency Inject

I currently have a class with around 40 dependency injection. It is a hard to maintain and unit test. I am not sure a good way around.
The code is done for any type of application process that is needed to process (New License, License Renewal, Student Registration, ...), there are around 80 different types applications and what sections are associated with each application type is determined by a database table.
I have a class with all of the possible properties, there are a several more than listed but you should get the idea. Each the properties have their own set of properties that are basic data types or object pointing to other classes.
class Application
{
[JsonProperty(PropertyName = "accounting")]
public Accounting Accounting { get; set; }
[JsonProperty(PropertyName = "application")]
public Application Application { get; set; }
[JsonProperty(PropertyName = "applicationType")]
public ApplicationType ApplicationType { get; set; }
[JsonProperty(PropertyName = "document")]
public List<Attachment> Document { get; set; }
[JsonProperty(PropertyName = "employment")]
public List<Employment> Employment { get; set; }
[JsonProperty(PropertyName = "enrollment")]
public Enrollment Enrollment { get; set; }
[JsonProperty(PropertyName = "individualAddressContact")]
public IndividualAddressContact IndividualAddressContact { get; set; }
[JsonProperty(PropertyName = "instructors")]
public List<Instructor> Instructors { get; set; }
[JsonProperty(PropertyName = "license")]
public License License { get; set; }
[JsonProperty(PropertyName = "licenseRenewal")]
public LicenseRenewal LicenseRenewal { get; set; }
[JsonProperty(PropertyName = "MilitaryService")]
public List<MilitaryService> MilitaryService { get; set; }
[JsonProperty(PropertyName = "paymentDetail")]
public PaymentDetail PaymentDetail { get; set; }
[JsonProperty(PropertyName = "photo")]
public List<Attachment> Photo { get; set; }
[JsonProperty(PropertyName = "portal")]
public Portal Portal { get; set; }
[JsonProperty(PropertyName = "section")]
public List<Section> Section { get; set; }
[JsonProperty(PropertyName = "testingCalendar")]
public TestingCalendar TestingCalendar { get; set; }
[JsonProperty(PropertyName = "testingScore")]
public List<TestingScore> TestingScore { get; set; }
[JsonProperty(PropertyName = "USCitizen")]
public USCitizen USCitizen { get; set; }
}
So this class is sent/received to an Angular 10 front end using Web API's.
When an application is requested the sections and the different properties are initiated and if the application has be started the progress will be reloaded. So it is possible some of properties will be pulled from the database and sent to the Angular app.
So I have something such as
Load(applicationTypeId, applicationId)
{
Get the sections for the application type
For each section in the sections
switch sectionid
case Documents
Load all of the documents required for the application type and get any documents uploaded
case Accounting
Load the payment details, if no payment made calculate the payment
case IndividualAddressContact
Load the person name/address/contact and set a few defaults if the person hasn't started.
.....
next
}
Save()
{
Save the application
switch current section
case Documents
Save all of the documents for the application
case Accounting
Save the payment details for the application
case IndividualAddressContact
Save the person name/address/contact for the application
.....
get the next section
Update the application current section
}
I have put all of the items in the switch into their own classes but in the end I still have 1 point for serialization/deserialization and still end up with to many dependencies injected. Creating a unit test with over 40 dependencies seems hard to maintain and given I won't know which properties will/won't used until an application is requested and loaded from database. I am unsure how to get around the switch, without at some point and time having to have all of the dependencies injected into 1 class.
I would appreciate some ideas of how to get around this.
"I currently have a class with around 40 dependency injection..." - Oh my gosh!
"It is a hard to maintain and unit test..." - I don't doubt that in the least!
SUGGESTED REFACTORING:
Create a class that manages "Applications" (e.g. "ApplicationManager").
Create an abstract class "Application".
One advantage of "abstract class" over "interface" here that you can put "common code" in the abstract base class.
Create a concrete subclass for each "Application" : public class NewLicense : Application, public class LicenseRenewal : Application, etc. etc.
... AND ...
Use DI primarily for those "services" that each concrete class needs.
I'll bet the constructors for your individual concrete classes will only need to inject three or four services ... instead of 40. Who knows - maybe your base class won't need any DI at all.
This is actually a design we're actually using in one of our production systems. It's simple; it's robust; it's flexible. It's working well for us :)
I would recommend using convention over configuration principle, with the Service Locator.
Declare something like IApplicationHandler interface in your program, e.g.
public interface IApplicationQueryHandler
{
Application Populate(Application application);
}
public interface IApplicationSaveHandler
{
Bool Save(Application application);
}
Then, write pieces of your code, with dependencies and such, e.g.
public class AccountingApplicationQueryHandler : IApplicationQueryHandler
{
public Application Populate(Application application) {
//// Load the payment details, if no payment made calculate the payment
return application;
}
}
public class AccountingApplicationSaveHandler : IApplicationSaveHandler
{
public Bool Save(Application application) {
//// Save the payment details for the application
return true; // this just flags for validation
}
}
// repeat for all other properties
Then in your controller, do something like
public class ApplicationController: Controller
{
public readonly IServiceProvider _serviceProvider;
public ApplicationController(IServiceProvider sp) {
_serviceProvider = sp;
}
public Application Load(string applicationTypeId, string applicationId)
{
var application = new Application(); // or get from db or whatever
var queryHandlers = _serviceProvider.GetServices(typeof(IApplicationQueryHandler));
foreach(var handler in queryHandlers) {
application = handler.Populate(application);
}
return application;
}
[HttpPost]
public bool Save(Application application)
{
var result = true;
var saveHandlers = _serviceProvider.GetServices(typeof(IApplicationSaveHandler));
foreach(var handler in queryHandlers) {
result = handler. Save(application);
}
return result;
}
}
You would need to register your handlers, which you can do e.g. like so:
var queryHandlers = Assembly.GetAssembly(typeof(IApplicationQueryHandler)).GetExportedTypes()
.Where(x => x.GetInterfaces().Any(y => y == typeof(IApplicationQueryHandler)));
foreach(queryHandler in queryHandlers) {
services.AddTransient(typeof(IApplicationQueryHandler), queryHandler);
}
// repeat the same for IApplicationSaveHandler
Now finally, you can write unit tests for part of the code like so
[TestClass]
public class AccountingApplicationQueryHandlerTests
{
[TestMethod]
public void TestPopulate()
{
// arrange
var application = new Application();
var handler = new AccountingApplicationQueryHandler(); // inject mocks here
// act
var result = handler.Populate(application);
// Assert
Assert.AreEqual(result. PaymentDetail, "whatever");
}
}
And you can test that your controller calls the right things by mocking IServiceProvider and injecting that with a couple of dummy handlers to confirm they are called correctly.
Following zaitsman's answer you also could create AggregatedApplicationQueryHandler and AggregatedApplicationSaveHandler and pass collection of concrete implementation of IApplicationQueryHandler and IApplicationSaveHandler to its constructor.
Then you don't need foreach loop inside controller(you loop over handlers inside aggregated handler) and always have only one handler passed to controller. Passing its by constructor parameter shouldn't be so much painful.
You also could create facade over some small services and aggregate theirs functions into one bigger facade service.

Creation of domain objects

I'm creating an application with employee and employer as a domain objects.
Both of them have a reference to User object where I store password and other account related stuff.
Example:
public class Employee
{
public Guid EmployeeId { get; set; }
public User User { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string About { get; set; }
...
//other properties
}
public class Employer
{
public Guid EmployerId { get; set; }
public User User { get; set; }
public string CompanyName { get; set; }
public string CompanyDescription { get; set; }
public string FoundedYear { get; set; }
...
//other properties
}
public class User
public Guid UserId { get; set; }
public string Email { get; set; }
public string PasswordHash { get; set; }
...
//other properties
}
I'm also using application services where a method represents a single use case.
Let's say I have RegisterEmpolyee method that should save employee to database set his role to "Employee" and send verification email.
This is my code right now. I'm using AspNet.Core.Idenity.UserManager to create user account:
public async Task<EmployeeDto> RegisterEmployee(RegisterEmployeeDto employee)
{
var validateResult = _validatorService.Validate(employee);
if (!validateResult.IsValid)
throw new ServerException
("RegisterEmployeeDto is not valid", validateResult.GetErrors());
await _db.BeginTransactionAsync();
var newUser = new User { UserName = employee.Email, Email = employee.Email };
var userCreationResult = await _userManager.CreateAsync(newUser, employee.Password);
if (!userCreationResult.Succeeded)
{
var userCreationErrors = userCreationResult.GetIdentityResultErrors();
throw new ServerException("Error during create User account.", userCreationErrors);
}
await _roleService.AddUserToRoleAsync(newUser.Id, ApplicationRoles.Employee);
var verificationCode = await _userManager.GenerateEmailConfirmationTokenAsync(newUser);
newUser.VerificationCode = verificationCode;
await _emailService.SendActivationEmail(newUser.Email, newUser.Id, verificationCode);
var newEmployee = new Employee(employee.Name, employee.Surname, newUser);
await _db.Employees.AddAsync(newEmployee);
await _db.CompleteAsync();
var employeeDto = _mapper.Map<Employee, EmployeeDto>(newEmployee);
_db.CommitTransaction();
return employeeDto;
}
And here are my questions:
Does this code and my approach are fine according to DDD?
Should I extract creation of employee to domain service? Or maybe factory? And if so should I call repository method from there? (I mean service of course)
Let's say should extract creation of employee to domain service. Should I create User internally then?
Like this:
public async Task<Employee> CreateEmployee(RegisterEmployeeDto employee)
{
var newUser = new User { UserName = employee.Email, Email = employee.Email };
var userCreationResult = await _userManager.CreateAsync(newUser, employee.Password);
if (!userCreationResult.Succeeded)
{
var userCreationErrors = userCreationResult.GetIdentityResultErrors();
throw new ServerException("Error during create User account.", userCreationErrors);
}
var newEmployee = new Employee(employee.Name, employee.Surname, newUser);
//Should I call repository here?
await _db.Employees.AddAsync(newEmployee);
await _db.CompleteAsync();
return newEmployee;
}
Or maybe pass User as a parameter?
And last question: Where is a right place to checking if user I want to create exist or not? Is Application service appropriate place to do so?
Thank you in advance for answers.
From what I see, User, Employee and Employer are Aggregate roots (AR).
Does this code and my approach are fine according to DDD?
In DDD it's not recommended that an Aggregate have references to other Aggregates other than by ID. Your Employee and Employer AR have such a bad reference so it is not OK. Instead Employee and Employer should contain only a UserId field.
Should I extract creation of employee to domain service? Or maybe factory? And if so should I call repository method from there? (I mean service of course)
From what I can see you have a complex process of creating multiple Aggregates. In DDD you cannot do this atomically, inside a single transaction. Instead, every Aggregate is created/mutated in its own transaction. There is however a tactical pattern of coordinating a long process: Saga/Process manager.
You should define a process of registering an employee as a Saga: RegisterEmployee. This process should have an interface with these methods: create, start, continue. The create method receive all the data it needs to start process. The start method tries to run the individual steps (like createEmployee, createUser etc); if the start method is run again, it should continue from where has stopped, so the Saga should record its status.
The architecture can be made better by making the command on Aggregates as idempotent. In this way, when a Saga restarts it can send again all the commands to the Aggregates; this effectively makes the Saga very simple.
Let's say should extract creation of employee to domain service. Should I create User internally then?
That domain service is in fact the Saga from the previous step. The Saga however should not contain logic that belongs to the Aggregates! Be carefully to not make your domain model anaemic. The Saga should contain only coordinating logic!
And last question: Where is a right place to checking if user I want to create exist or not? Is Application service appropriate place to do so?
What means that an User already exists? There is already an user with that username? If yes, then the simplest solution is to have an unique index on the username column, if possible. If it's not possible (i.e. you have sharding enabled) then you can have another Saga that checks for duplicates and reports to an Admin or something.

Mapping a User entity into a User DTO in .NET Core

I'm developing a web app that contains a User entity that is derived from .NET Core's IdentityUser. Lets suppose there is another entity called Comment which has a relation to a user (the user who posted the comment):
public class User : IdentityUser
{
public string SomeExtraField { get; set; }
}
public class Comment
{
//Owner (Creator) of the feedback
public User User { get; set; }
//body of the comment
public string Body { get; set; }
}
Now suppose I have an API endpoint that returns all of the comments in the system. If I query for all comments and include the User relation, when the object gets serialized, everything in the User class is serialized and sent to the client (including the users hashed password, etc). Obviously I don't want this. So I've created a CommentService layer that grabs the Comments from a CommentRepository. From my understanding, the service layer should do the job of mapping the raw Comment object into a Comment DTO, which only contains data that should be sent to the client. I've defined a comment and user DTO like this:
public class UserOutput
{
public string Id { get; set; }
public string SomeExtraField { get; set; }
}
public class CommentOutput
{
public UserOutput User { get; set; }
public string Body { get; set; }
}
Then in my service layer I have something like the following:
//Fetch all comments
var list = await _repository.ListAsync();
//Map comments to DTO
var result = list.Select(x => new CommentOutput
{
Body = x.Body,
User = new UserOutput
{
Id = x.User.Id,
SomeExtraField = x.User.SomeExtraField,
}
});
This all seems to work great. However I can foresee one problem. Lets say I have a large system with Comments, Posts, Likes, Private Messages, etc. I can map them all in a similar fashion above. Then one day I decide to add another field to the UserOutput DTO. Now I have to go through potentially hundreds of mapping code like the sample above to map the new field properly, and whats worse is the compiler wont tell me if I've missed anything. I would like to have a function somewhere that maps a User to a UserOutput but I don't know where it should go.
I've seen some suggestions to put a constructor to the DTO that does the mapping:
public class UserOutput
{
public UserOutput(User user)
{
Id = user.Id;
SomeExtraField = user.SomeExtraField
}
public string Id { get; set; }
public string SomeExtraField { get; set; }
}
but I've seen people against this because it tightly couples the DTO with the Entity. I've also seen suggestions of using Auto Mapper but is also seems an equal amount of people are against it.
Where should I place code that can perform these DTO->entity and entity->DTO mappings so I don't repeat myself all over the place?
Try to check out AutoMapper.
This library will help you to map the Entity Class into the ViewModel.
The way to use it is pretty straightforward.

Successfully implementing custom UserManager<IUser> in Identity 2.0

I'm trying to navigate the black hole that is the custom implementation of Identity Membership. My goal right now is simply to get this line from my ApiController to correctly retrieve my UserManager:
public IHttpActionResult Index()
{
var manager = HttpContext.Current.GetOwinContext().GetUserManager<UserManager<MyUser,int>>();
//manager is null
}
Here's my setup. In my Startup's Configuration I set up the WebApi and add my OwinContext:
app.CreatePerOwinContext<UserManager<MyUser,int>>(Create);
My Create method:
public static UserManager<User,int> Create(IdentityFactoryOptions<UserManager<MyUser,int>> options, IOwinContext context)
{
return new UserManager<MyUser,int>(new UserStore(new DbContext()));
}
the rest is the most basic implementation I can make.
MyUser:
public class MyUser : IUser<int>
{
public int Id { get; set; }
public string UserName { get; set; }
}
MyUserStore:
public class MyUserStore : IUserStore<MyUser,int>
{
private IdentityDbContext context;
public MyUserStore(IdentityDbContext c)
{
context = c;
}
//Create,Delete, etc implementations
}
MyDbContext:
public class MyDbContext : IdentityDbContext
{
public MyDbContext() : base("Conn")
{
}
}
This is all for the sake of learning how Identity works, which I'm pretty convinced no one actually knows. I want to be able to fully customize my Users and Roles eventually, avoiding Microsoft's IdentityUser.
Again, my issue right now is that in my controller, I am getting null when trying to retrieve my UserManager.
Any and all help is greatly appreciated.
I had several errors, but the main one was that my Startup class looked like :
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseWebApi(new WebApiConfig());
app.CreatePerOwinContext(MyDbContext.Create);
app.CreatePerOwinContext<MyUserManager>(MyUserManager.Create);
}
}
Of course, the OWIN pipeline will plug my dependencies after firing off the WebAPI calls. Switching those around was my main problem.
In addition, I finally found this great guide way down in my Google search. It answers pretty much everything I was getting at. I needed to implement a concrete class that was a UserManager<MyUser,int>
I hope this is able to help someone later on.
Are you using MyIdentity.User or MyIdentity.MyUser? You have two different objects passed into the TUser parameter in your examples.
I tested your implementation and did not have issues retrieving the registered instance of the UserManager.
To fully customize your Users and Roles, you will need to end up writing a new implementation of the UserManager in order to get your Authentication, Claims, Roles, method calls, etc to work.
If you are trying to learn how Identity works, I would suggest working with the default implementation of UserManager and IdentityUser. Get that to work first.
Here is a good tutorial
Eventually, create your own users implementing IdentityUser. All of the UserManager functions will work and you will have access to your new properties. The additional properties will automatically be built into the AspnetUser table generated by the IdentityDbContext.
public MyIdentityUser : IdentityUser
{
public int Id {get; set;}
public string CustomUserId {get; set;}
public string UserId { get; set; }
}
Or you can start building your custom MyIdentityUser with foreign key references to other objects.
public MyIdentityUser : IdentityUser
{
public virtual UserProperties Properties { get; set; }
}
Does this help any?

How to initialize on MVC module?

I am new to MVC programming. In normal OOP, where I have my class, I would just initiliaze and load data from database. In MVC, we have modules, how do I load up records from it?
Here is my current code for type UserAcount:
[Table("UserAccount")]
public class UserAccount {
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string userName { get; set; }
public string email { get; set; }
public int companyID { get; set; }
}
Say that I have an user with name "testUser", how do I initialize on this record and get it's information? How do I do this:
UserAccount user = new UserAccount("tesetUser");
How and where shoulud I use this?
user = user.SingleOrDefault(u => u.userName.ToLower() == User.Identity.Name.ToLower());
You need to read up on Entity Framework. This is the default ORM that MVC uses. Simply:
If you don't have a project context, yet, create one:
public class MyProjectContext : DbContext
{
public MyProjectContext()
: base("name=ConnectionStringNameHere")
{
}
}
Add your models to your project context:
public class MyProjectContext : DbContext
{
...
public DbSet<SomeModel> SomeModels { get; set; }
public DbSet<SomeOtherModel> SomeOtherModels { get; set; }
# etc.
}
Update your database using Package Manager Console (TOOLS > Library Package Manager > Package Manager Console):
> update-database
(hit ENTER after typing that)
Now, to use your context in your controllers:
public class MyAwesomeController : Controller
{
private MyProjectContext db = new MyProjectContext();
public ActionResult Index()
{
var someModels = db.SomeModels;
return View(someModels);
}
public ActionResult GetSomeModel(int id)
{
var someModel = db.SomeModels.Find(id);
return View(someModel);
}
# other actions
}
In the simplest case, you should do this logic in your controller, which will pass the data to the view. However, MVC is meant for UI separation of concerns, so theoretically you should be doing this in your domain layer, which is called from your controller.
Here is a decent article from Jeff Atwood, however I disagree that the controller is the brains of the application. It is more of the brains of the UI...but that depends on how complex your code is. Dont create a domain layer if it is stupidly simple
In the MVC model, Controllers are responsible for processing HTTP requests.
Typically you would load your entity (e.g. UserAccount) in a controller action.
If you want to edit / update an entity, typically you would map the relevant fields to a model that reflects the UserAccount. A separate model is suggested because the needs of the UI are often somewhat different than the needs of the entity model. Having separate classes for each concern avoids polluting the entity model to satisfy the needs of the view.

Categories