0

I am working on an ASP.NET Core application that grabs a model from a database via Entity Framework, and will pass a "subset" of that model to our Angular front end. For example:

I have a list of Users. On the user-list page, I would like to grab a list of User objects from the API and display them on the page. For each User, it should only show Name and maybe a few other fields.

I would also like to be able to click on the user's name to redirect to their profile page. On this page, we will get more fields from the User table - perhaps more in-depth information like Nickname or Middle Name, etc.

My question is, what is the "correct" way to structure this, on the front-end side and the server side?

On the front end, is it best to have one class with nullable values that either get filled out or left null based on which page they are on? Like this:

export class User{
    firstName: string;
    middleName?: string;
    lastName: string;
}

Or would I have "UserListUser" and "UserProfileUser" classes that are completely separate? Or, would it be a parent class called "User" with a subclass with more information like "UserFull"?

And, on the back-end, is it best to do the same thing? Would you create separate classes for each page that has access to that database model? Would you just use the ORM object that is created from Entity Framework? Or would you always map that to a smaller object with only a subset of the fields on the database table?

2

I would have multiple models server side for the different views for different user (user as in the person visiting your site) permissions/perspectives and use a utility for generating typescript classes from c# classes (you don't have to use that tool, it's just a random example) to keep my c# and typescript in sync.

This approach assumes your typescript classes are meant to be data containers to be written into templates i.e. all you need them for is those generated fields that can be populated by deserialization or some other method.

You still need to do the work to use the fields in your Angular code but at least if you try and remove a field on the c# side you won't be able to keep showing it on the frontend (the typescript compiler should complain). It is less harmful if your typescript class gets a new field you can show the user but you forget to actually show it, versus if you realize you cannot show a field and you accidentally keep showing it.

You need to find a way to trigger the generation of typescript classes as part of your workflow. How you would do this depends on your generation tool etc. You then need to have test(s) to compare your current stored definition to what would be generated from your current c#. The idea is that if you forget to "sync" your C# and typescript something is going to stop your incorrect code from going out.

I would never use the ORM class as a model. You want to have models where every single field/property will be used by its typescript buddy. You want to know that when a field is null it is because it is a bug and not because you don't need that field for what you are showing the user in that particular situation.

If ModelA is like ModelB but has User.MiddleName, you can use inheritance (assuming your c# -> typescript tool handles inheritance properly). Having the models separate from the ORM also basically documents what you are trying to show the user. I can look at UserSummary.cs and see what we show for each user on the user-list page.

There should probably be a domain layer between your models and your ORM. An sort-of-psuedocode example:

Data access layer:

public class UserORM {
    string UserName;
    string PasswordHash;
    string FirstName;
    string Surname;
    int? CountryId;
    string EmailAddress;
    //code related to saving and loading, this saving/loading code could be in another class. Either way, this is the view of the User as they will be stored in the DB
}

Domain ("business rules") code:

public class User {
    string UserName;
    string PasswordHash;
    string FirstName;
    string Surname;
    int? CountryId;
    //business rules code e.g. when it is valid to save this user to the DB (this code may go in another class). At the very least you will show the User as the "business" sees it
}

Model 1: User list item (summary of user, e.g. for list on webpage):

public class UserSummaryModel {
    string UserName;
    string EmailAddress;
    internal UserSummaryModel(Domain.User user) {...}
}

Model 2: User details (e.g. for when you click on a user):

public class UserDetailsModel {
    string UserName;
    string FirstName;
    string Surname;
    int? CountryId;
    string EmailAddress;
    internal UserDetailsModel (Domain.User user) {...}
}

Disclaimer: this code is not meant to represent an example of secure management of user details and credentials. Including the PasswordHash is just meant to illustrate that the idea that the domain model of a user has a password and the DB is going to store it. The PasswordHash is an example of something we are not going to show the user in any model

  • 1
    That being said, if your web page is an application, there is nothing wrong with that application having a domain model of User (or whatever). This model though should not be a direct lift from the API, it might be well-informed by a specific API but it should not be tied to it. This allows the Web Application to redefine what it means by User independent of what each API defines as a user, independent of what the Server defines as a User. – Kain0_0 Jan 9 at 1:12
  • @Kain0_0 Am I understanding correctly that you mean putting the domain model in the angular frontend? – Dev243 Jan 9 at 18:29
  • What do you mean by the domain layer between the models and the ORM? Are you referring to C# code on the back end that would transform the data from the ORM into the model to send back to the front end? Would you be able to give an example in Model View Controller of what you're referring to? – RegretfulWasher Jan 9 at 19:22
  • @RegretfulWasher I see any web system as being composed of several applications. The browser is the platform for one of these should the web page be a dynamic web app. The Angular code constitutes a program, thin clients have the absolute minimums, and thick clients have more. By layer, it has a display html and any objects representing that, a logic layer where domain relevant objects exist, a communications layer usually a http/websocket link to a Web API/Service, and a persistence layer via cookies, and browser supplied databases. – Kain0_0 Jan 9 at 23:05
  • So in line with the question, The server has a domain of interest, this might not cleanly map to the information each api point returns, so it must map from domain to communication model. Then because the Web App should not permit coupling on a communication layer, it should map from the communication layer to whatever constitutes its domain of interest. Now if you have a boring thin-client, pragmatically speaking you can bind the results returned by the api directly, but if you wish to isolate the display of the results from how they are retrieved, you automatically have a thick client+logic. – Kain0_0 Jan 9 at 23:13

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.