Exposing EF6 model subsets via WebAPI - c#

For example, I have a EF6 model like this:
class User
{
public int Id { get; set; }
public string Email { get; set; }
public string Name { get; set; }
public virtual ICollection<ProfileProperty> Properties { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
class Book
{
public int Id { get; set }
public int Name { get; set }
public DateTime CreationDate { get; set }
public long Size { get; set }
public string ContentPath { get; set }
}
And now I want to create a WebAPI that allows to:
Create a new user
Update user's name
Modify the list of user's books
However, here are a few tricks to it which don't let me use tutorials right off:
Some fields are either irrelevant or confidential and must not be exposed via WebAPI, for example: User.Id, User.Properties, and nested User.Books[x].ContentPath.
Only a small subset of fields is editable (in the example, User.Name).
Only a small subset of operations (CRUD) is available, therefore it's not a REST service.
The first thing that comes to mind is create extra classes for each exposed model. However, maintaining them and writing code that converts data from database models to those WebAPI-friendly classes and back is too bothersome. Is there a more simple and automated way?
The ideal approach would be one which requires writing as little redundant code as possible. Maybe there is a set of attributes to mark fields with?

You're right in thinking you should create more classes. For each exposed action (change name, create user, etc...) you should create a ViewModel that exposes only the fields you need.
public class ChangeUserNameViewModel
{
public int UserId { get; set; }
public string NewName { get; set; }
}
It's easy to convert your view model to your domain model and back again using something like AutoMapper.

Related

Deriving a database model for view model in ASP.MVC

I am creating some view models for my ASP MVC web app.
I created "code first" models for database. Is it a good way to derive view models from database models?
Example database model:
public class Project
{
[Key]
public int Id { get; set; }
public int? CustomerId { get; set; }
public int TypeId { get; set; }
public string Number { get; set; }
public string Name { get; set; }
}
View model:
public class ViewModelProject : Project
{
[NotMapped]
public DateTime? Start { get; set; }
[NotMapped]
public DateTime? End { get; set; }
[NotMapped]
public string Manager { get; set; }
}
Is this the right way or is it completely false?
EDIT (subquestion):
I have some very simple database models like ProjectType, which only contains i.e. two properties. Should I also fragment those models in model view or can I make it that way:
Simple database model:
public class ProjectType
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int? Code { get; set; }
}
Can I use it like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public ProjectType Type { get; set; }
}
Or does it have to be fragmented like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public string Type { get; set; }
public int TypeCode { get; set; }
}
I would not recommend doing it this way. I (and many others) have tried it and it doesn't work well. You will inadvertedly run into troubles, since an MVC model has to be tailored to the view and what you get from the DB rarely fits. Sure, you can hammer it into place, but the code quickly gets messy and store-related and UI code starts to mangle together. This even shows in your example, since you have to put the NotMappedAttribute (which is related to data storage), to ViewModelProject (a class at UI level).
There are many other examples to show this problem, but an especially good one I find when you want to serialize a model object to JSON and send it to a JavaScript client. The JSON serializer takes the values of all public properties and adds them to the JSON. If you want to exclude a property, you have to mark it with a ScriptIgnoreAttribute, which you would also have to apply to the base class, which breaks separation between UI and store-related code.
The better way to go is to keep the staorage model and the MVC model separated and to map the data from one to the other (there are already pre-existing frameworks that help you with that, such as Automapper). This comes with additional advantages, for example better testability, since you are now not dependent on a specific data store to create model instances.

Dynamic Create View with Multiple Nested IEnumerable Objects

Ok, I have 3 models. WorkoutViewModel has a one to many relationship with WorkoutExerciseViewModel. WorkoutExerciseViewModel has a one to many relationship with ExerciseSetViewModel. I need a dynamic “Create View”, that will allow me dynamically add Exercises to Workouts, and Sets to Exercises. I then want to save a Workout including all exercise and set records back to the database. I just need to validate that there is at least 1 exercise for the workout created and at least 1 set for the exercise created. Ultimately I just need to push a Workout View Model back to the controller with all of the populated nested IEnumberable objects present. Can anyone point me in the right direction?
public class WorkoutViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtal IEnumerable<WorkoutExerciseViewModel> WorkoutExercises { get; set;}
}
public class WorkoutExerciseViewModel
{
public int Id { get; set; }
public int WorkoutId { get; set; }
public int ExerciseId { get; set; }
public virtual ExerciseViewModel Exercise { get; set; }
public virtual IEnumerable<ExerciseSetViewModel> ExerciseSets { get; set; }
public string ExerciseFullname
{
get
{
return Exercise.Equipment.Name + " " + Exercise.Name;
}
}
}
public class ExerciseSetViewModel
{
public int Id { get; set; }
public int WorkoutExerciseId { get; set; }
public int Set { get; set; }
public int Reps { get; set; }
public int Weight { get; set; }
public string WeightValueType { get; set; }
}
There's really more to this than can reasonably be discussed in a StackOverflow answer, but I'll give you enough to start with.
As far as adding new exercises and sets within those exercises go, that's just JavaScript. You'll need to have some button that the user can click to add a new one, and tie the click event on that button to a handler that will add the appropriate HTML (form fields and such) to the page. There's many different ways to go about doing that, some more difficult than others. Most likely you want to look into some JavaScript templating library or a more full stack JS library like Knockout to make things easier. The only other thing to keep in mind is the conventions the modelbinder uses to wire everything from the post body to an instance of your model. For collections, it expects fields to have name attributes in the form of CollectionPropertyName[N].PropertyBeingEdited, where N is the position within the collection. So, the name attribute for ExerciseFullName for the first exercise would be WorkoutExercises[0].ExerciseFullName.
Your post action would simply take your same main view model:
[HttpPost]
public ActionResult Create(WorkoutViewModel model)
{
...
}
As long as you follow the property naming conventions for all the fields in your form, the modelbinder will happily wire everything from the post body onto your WorkoutViewModel instance.

How does one design his various architecture/business models?

I'm currently learning about various application design approaches and there's one thing I can't really get my head around.
Let's say I have a physical device in my network, an IP surveillance camera. I need a model that represents 'IP surveillance cameras' to work with them in my application, which might look like this:
public class IPCamera {
public string Token { get; set; }
public IPAddress IPAddress { get; set; }
public string RtspUri { get; set; }
}
Now, if I want to store the IPCamera into a database (e.g. with Entity Framework), I need maybe other/additional properties and thus, another model with:
public int Id { get; set; }
Oh.. I want to access my application with via a WCF service. I can't use the object "IPAddress" here because it's not very serialization friendly, hence I need another model with a custom IP class that stores the IP address as string.
And last, an Android clients wants to access my data. I design a RESTful API using WebApi2. The client isn't interested in the cameras RTSPUri, but wants to know about the current state (is online, is offline).
I'm wondering: How to name all these models that they don't come in conflict? Should I design a model per each purpose/layer/service? And how to link/map them? With the adapter pattern?
I would include everything in your entity and then create view models that only expose the properties that matter to the domain you're accessing your entities through.
Your entity:
public class IpCamera
{
public int Id { get; set; }
public string Token { get; set; }
public IPAddress IPAddress { get; set; }
public string RtspUri { get; set; }
public bool IsOnline { get; set; }
}
In your WCF service:
public class IpCameraViewModel
{
public int Id { get; set; }
public string IpAddress { get; set; }
public string Token { get; set; }
public string RtspUri { get; set; }
}
In your api project:
public class IpCameraViewModel
{
public int Id { get; set; }
public string IpAddress { get; set; }
public string Token { get; set; }
public bool IsOnline { get; set; }
}
And you can just set the IpAddress as a string to send to a receiving client. You can shed away any properties you don't want to expose. Or you can add properties that don't belong to the IpCamera entity and just add them to your view model from another entity.
As #Smith.h.Neil suggested, you should create one base normalized model (entity if you will) to store and several view models (projections).
You can easily map to/from view models using tools like AutoMapper.
As for the naming, I wouldn't use technical suffixes (like *ViewModel) in API layer. Think hard and figure out correct domain (business oriented) name of each projection. Like IpCameraStatus or perhaps just IpCamera (but in another namespace).

How to represent dynamic enum-like fields / properties in an Entity Framework 4.1 model?

I'm trying to whip up a POC of a system which allows you to create and modify enumerations that are eventually used in an application using the front-end. Something like dynamic enums.
For example, in a hypothetical bug tracker application, we can have a status enum that could have values of open,accepted and closed. All these enums (and their corresponding values) can be changed in real-time via the UI, so it is possible for an admin to come up with a new reassigned value for example (through an Admin page, most probably) somewhere down the application's lifetime. It would also be possible to create new enums as well, which in turn have their own values (for example, a complexity enum).
The way I'm currently envisioning it is that I'll have an Enumeration class, which has a 1:* referential with an EnumerationValue class.
public class Enumeration {
public string Name { get; set; }
public ICollection<EnumerationValue> Values { get; set; }
}
public class EnumerationValue {
public string Name { get; set; }
public string Description { get; set; }
}
That's the easy part. When I get to creating the entity that actually uses these dynamic enums, I hit a snag.
Let's say I'm creating the BugRecord entity, which consequently has a Status property. Following the logic above, I'd have to write it along the lines of:
public class BugRecord {
public EnumerationValue Status { get; set; }
}
But given that I could have lots of different Enumerations (and EnumerationValues), is there a way for me to restrict BugRecord.Status values to only EnumerationValues in the status Enumeration? If not how would you recommend I tackle a problem of this kind?
Create a third Entity/JoinTable EnumerationChoice and use it to map the BugRecord to the EnumerationValue
public class EnumerationChoice {
public Enumeration EnumerationCategory { get; set; }
public EnumerationValue Value { get; set; }
}
BugRecord now becomes:
public class BugRecord {
public EnumerationChoice BugType { get; set; }
public EnumerationChoice Status { get; set; }
}
The data would now look like:
BugRecord:
EnumerationChoice:
-BugType
-BugTypeValue1
EnumerationChoice:
-Status
-Open
This way, when you try to populate the EnumerationChoice, you can reference the EnumerationCategory to get the valid EnumerationValues assigned to it.

which is better multiple properties or behavior property

I have a set of contact infos that I will be displaying in an ASP.NET MVC page
They will either have an email address or information to contact
should I have this setup
public class Contact
{
public int ID { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Explanation { get; set; }
}
where email address is shown when explanation is null
or
public class Contact
{
public int ID { get; set; }
public string Name { get; set; }
public string DisplayInfo { get; set; }
public int DisplayInfoType { get; set; }
}
where the display info type determines how I will display the info.
First approach: it's more expressive!
The domain model is more expressive in the first example; it speaks for itself what the data means.
That you need to have one of the two filled is a business rule which you don't need to express in the properties of your entities.
DisplayInfo or for that matter any similar display logic should be incorporated in the Views. The business logic is not responsible for what part of the domain has to be shown to the user on the view. This should be taken care at the view-level.
The first setup is better. It expresses what the fields do more effectively. It delays the execution of UI logic until the appropriate layer.
Also note that your Email may be empty as well as null. Additionally, you may get more use out of a field name such as ContactInstructions instead of Explanation (explanation of what?).

Categories