I have a scenario in which I need advice on. I have an application where there are two kinds of users Student and Teacher. Student and Teacher share some of the common properties like FirstName, LastName, Email, UserName, Password etc. For this reason I derive Student and Teacher classes from User.
Now, the problem is that there are times where I don't really know that if the user is student or teacher. Like when implementing a custom membership provider and in the GetUser function. GetUser takes userName but now I lost that what should I return.
For Student functions I have created IStudent and ITeacher for teachers. But sometimes I just want to return a User and do not care about if he is student or teacher. But then returning base class does not seems like a good idea too.
UPDATE:
I think it is good idea to return User and not even have Student and Teacher classes. Student and Teacher are simply the roles and can be managed by StudentServices and TeacherServices.
A classic scenario and a classic runaway from the problem. Yes there is always pain to work with inheritance as they constrain. But benefits occur when you inject behavior into your class(es). Now it seems like you have decided for jut using User class and not having User as a base and child classes Teacher and Student. It can be a good idea if you make Teacher and Student as roles, but handling them in separate services... well it smells i my opinion. You'll likely end up with duplicate code in these services since they both need to handle User logics.
The fact is if you start to fend off difficulties like this by compensate in service layer, that's the road to an anemic domain model where logic leaks out from domain layer to gui or service layer.
What is unique with teacher and student and what logic/behavior differs should be represented in domain layer.
You can use inheritance (maybe the best solution) or making these as a role where you actually make Role as a custom Enum - Look at (I Think) Jimmy Bogard for how to extend a custom Enum with behavior.
Related
I'm just getting started with DDD and implementing the Onion Architecture.
I'm making an invitation system, where a super user can invite another user by email to his company. However when creating the invitation, I want to ensure that the user is not already created in the system. I want to do that by checking if there's any record in the database with that email. I'm using Entity Framework to handle the database context.
And I've made a repository for both Invitation and UserAccount, that contain methods to find items based on an Id.
I need to use the DB context in order to see if the invitation is still valid, but since the method is declared in the Domain Layer, I can't really figure out how to do it, without breaking the design pattern. The Domain layer should not know anything about the persistence layer.
I thought about injecting the IUserAccountRepository and then executing the required methods in order to complete the Accept() method, but I'm afriad this is wrong.
The Domain layer should not know anything about the persistence layer.
That's right - the domain layer should not know about persistence.
But that constraint doesn't apply to the application layer.
In other words, we design our domain model interface so that it "asks for" the information that we (might) need to successfully compute the next state of the model, and the application has the problem of figuring out where that information comes from.
public UserAccount Accept(Guid userId, Boolean userExistsInDatabase)
What you will see in some designs, is that instead of passing in the answer to the question, we'll pass in the capability of asking the question, and let the model decide for itself whether the question should be asked and what to do with the answer
public UserAccount Accept(Guid userId, Roster roster)
In this case, Roster would be an interface defined by your model, that accepts some piece of information that the model already has and reports back some other piece of information that your model understands. Then your application would provide an implementation of this interface when invoking the method.
Passing values across the boundaries is a bit more "pure", in that the model code doesn't need to know anything about the failure modes of the Roster -- all of that code would instead live in the application layer.
It's OK to use Contracts in your Domain Services.
"IUserAccountRepository" is a Contract that we create in the domain and the domain service doesn't know about implementation.
So Do not worry about that it's right
I'm starting with DDD and trying to apply in my current project, but as you can suppose I have thousand of questions.
Here I present a sample domain so I can make different question and serves as an exercise on which you can explain me how things can be made.
Our hypothetical system must take control of companies and what persons works on each one.
Domain.
Company(id, name, address)
Employee(id, name, surname, age)
A person can only work on a company and a company can have many employees working on it.
Operations
The system must allow to add a new employee to a company. For this it receives the company id and the name, surname, age of the new employee. There are some restriction to satisfy:
There can not be another employee with the same name, surname and age in the company.
The employee can be working in another company.
Questions
I have a mess in my mind :)
To implement the operation I'm thinking on:
Service receives all the parameters.
Service call CompanyRepository->findCompanyById to retrieve the company instance.
Service creates a new instance of Employee using the specified parameters.
Services calls company->addEmployee to attach the employee to the company.
Within the company->AddEmployee check the new employee satisfies the conditions (specifications).
Service calls CompanyRepository->save(company) to persist the company in addition to the employee.
Because company+employee is managed as a cluster (aggregate) I'm considering the company the aggregate root.
Is this a good implementation?
If I consider company+employee an aggregate, in the same way I described to save the cluster company+employe, must I retrieve all the related employees too when I retrieve the company instance from repository ?
Respect specifications I can understand easily how to check, for example, if a employee name has more than 10 chars, but: how to check if the employee exists in the same company if the company has thousands of employees?
Can a specification call repository operations? and if yes, and the fact that considering company+employee a cluster is right, what would be the right place? CustomerRepository->findEmployeeByName(idCompany, nameEmployee) or better create a specific EmployeeRepository.
1
What is good or bad is just an opinion. DDD shouldn't be a dogma and you can take the best of it and your own additions to build good software architectures.
2
No, company can either lazily-load employees (i.e. when runtime access the Employee property the first time after the company has been retrieved) or company can implement a Load method which also supports pagination to load only required employees.
3
You should implement this at repository level (for example ICompanyRepository.ContainsEmployee(Employee)) and use the underlying data mapper to perform this heavy operation.
Also, I tend to call specifications as pre-/post-conditions in repositories, because it's the only way to be sure that they will be fulfilled in all cases.
4
I would avoid it, but if you want to ensure a lot of domain rules, you'll need to use them in specifications. BTW, I wouldn't use repositories but I would use services instead.
The right place depends on the requirement. If you want to perform checks to be sure that domain objects are being stored in the repository in a valid state, I find no issue if you want to call an specification from within ICompanyRepository.Add or ICompanyRepository.Update, or ICompanyRepository.AddOrUpdate. The point here is you shouldn't verify object states both when they're stored in the repository and when they're retrievied. If your specifications and your code is reliable, if the repository has filtered domain objects and it has stored them in the underlying data store, you can be sure than read operations will get valid domain objects.
Side note: While you shouldn't model your domain based on the underlying data store (either relational, NoSQL, file system...), again, you shouldn't apply DDD like a dogma. If the underlying data store provides a better approach to define data constraints, I would try to use them instead of implementing complex specifications which might need to access the data anyway.
Your solution should be a balance of an optimal software architecture and runtime performance.
I'm not sure if that's the best way to ask this question.
I've built a facebook clone.
Now it's coming to the point where I want people to be able to create pages/company profiles.
So I want MANY users to be able to
A) manage these pages (Easy, just authorize the user against the page)
B) Act as those pages, as if they were a normal user account (Make posts on pages, and act throughout the app, as if they were a normal user
Now to do this I could
i) Actually create a new USER which is of a different type. When a normal user wants to act as a PAGE/Company I actually authenticate/authorize them to be able to, and actually switch their signed in account to the second user. When logged in as this user, they can switch back to the other user type using the same method. I actually quite like this idea, as it means very little code change, and everything should work just fine.
Problems - Cookies? Multiple users being signed into the same account at the same time? I'm guessing this is my problem and how I structure my general app/cookie approach
ii) I could just create new types in the db, ie Pages / Companies, and on each place where I have a UserId (Posts, Messages, Photos, Images, etc...) add a PageId and CompanyId. Then when working as a page or a company, I can log which page/company was interacting.
This will result in a fair amount of code change, and also feels hacky, compared to the theorectically clean idea in option a).
However I may have missed some absolutely massive security flaw or other reason why option A) is a bad idea.
Any ideas anyone?
It seems that you are over-complicating your situation. You seem to want to do the following:
Create a User model that is your one and only model capable of logging in
Add the 'other account types' as added levels of authentication within that User model
This is akin to adding different roles to your User models.
UserA can have a role that allows them to do more things than UserB
These roles can come and go as necessary
You appear to be on the right track with your method i. KISS comes to mind.
Update - based on your comments:
I would go back to the drawing board on how you want to do this - the apparent structure is too unclean, we need to be more inventive here.
We would be able to help more if we knew a lot more information about your exact structure, but that's tedious. That being said, there is something inherently complicated about your solution that is resulting in these issues.
I'll do my best - this is what comes to mind when I think of your user needs:
It feels similar to a classroom setting. You have a bunch of users (Students, Teacher, Administration) who can access the same area (classroom), and there's several of these areas that are similar (different classrooms).
If it is anything like the classroom setting, you would have users with roles like these:
Administrators can access anything anywhere they want.
Instructors can access any classroom they explicitly teach.
Being an Instructor means they can do more things in the classroom than the students.
Students have much more limited permissions and can basically only attend class, turn in homework, and see their grades. The only thing they are in control of is weather they show up or not.
At first, the above situation may sound convoluted - how does one set up a permission scheme for this sort of structure?
Easy:
You have three roles: Admin Teacher Student
(I'm going to over-simplify) You throw [Authorize(Roles = "Admin")] over every single controller action that requires a user to log in - since they can do anything they want.
You allow Teachers to have almost all control over any action related to a class they teach: if User.IsInRole("Teacher") && User.Name == classroom.Teacher
You allow Students to have greater restrictions over what they can do and limit further by if they user is actually in the classroom or not: if User.IsInRole("Student") && User.Name.IsInList().List<Enrollments>EnrollmentListForCurrentClassroom (very pseudo-codey)
You only have three roles, but you can restrict access to separate parts of the database by more than just the role - you can restrict access by weather the user has also been added to a list of enrolled students in a class, a list of teachers that teach a class (typically only 1 teacher per class. . . ), etc.
Hopefully taking an approach similar to the one above would help simplify your situation.
I have a class named Employee.This class have 3 attributes:name,adress and supervisor.
If the supervisor of an Employee can be any other kind of Employee the supervisor should be an Employee, but if only Managers can be supervisors then supervisor should be Manager.
Just as a side note: Inheriting in this way is not always a good solution. You will run into lots of trouble if Employee can have multiple roles, like both Developer and Designer.
I recommend you to have a look at object composition instead of inheritance.
I am using the built in .net authentication in my project and am creating class entities in entity framework 4.0.
My classes are a Student, University and Company class. My question is can I inherit the System.Web.Security.MembershipUser class for these classes? The ef class already inherit the EntityObject class so I don't know how to do it?
thanks
Your question is a little lacking in detail but I have a go at answering.
To start you won't want to inherit from the MembershipUser class. You can (because its abstract) but you would only inherit from it if you were going to use your own logic and db tables to store the validation fields.
You wouldn't put Membership onto a University or Company class but on the members of those Entities e.g. a Student is a member of a University, as there are Employees to a Company.
Neither of the Student or Employee would have Membership information on them (within their db tables) but would more likely have information relating directly to them (e.g. an Employee has a Payroll number)
Student and Employee are both of type Person (e.g they both have Name, Address, etc.)
A Student or an Employee maybe a User of your Application (web site, desktop, etc.) but then they maybe not also, or they may be deactivated as a User but you want to keep their Person and Student/Employee information for your records.
A User will have the usual info like... UserId, Username and Password, etc. but you don't want to use this entity if you were going to put a DisplayName on the App. For security reasons, I also do not put Session information onto the User but use the UserId (encrypted MD5 one way encryption) and SessionId to validate my users Session, this means that if some how I did have a breach of security (SQL injection) the hacker would not be able to access Usernames and Password details. Anyway, I digress.
So, what is the MembershipUser class? It gets used mainly in your Authentication object which will have methods like... Login, ChangePassword, Logout, etc. These methods would call
if (!Membership.ValidateUser('username', 'password')) return false; etc.
If you wanted to use your own db tables and entityframework calls for the membership then you would look to implement a Custom Membership Provider, overriding all the standard methods and put you entity DAO requests (hopefully using Design Patterns e.g. Repositories etc.). This can be risky and difficult, but with experience not too big a deal.
Otherwise, just stick with the standard Membership (User) Provider, stick what it needs in the web.config file and have it deal with the security and you can get on with developing you Application...
a good book is Pro Asp.Net MVC Framework ... it goes through everything including unit-testing, design patterns, etc. Also a great way to spend some money is on the GOF (Gang of Four) design patterns source code... get the full works, best £60 spend ever.
I hope this helped.
Hugh
There is no EF provider, but you can write your own provider.
Write a mapper class for your MembershipUser derived class.
I found a nice example over here:
efmembership.codeplex.com