A viewmodel has a behavior/methods compared to a DTO but - c#

People on SO often say:"A ViewModel holds methods that can be executed by the view, properties to indicate how toggle view elements, etc. ..."
When my ViewModel is sent as a WebApi response to the client serialized to JSON, how can this ViewModel execute a method on the client?
This is not clear at all to me.

You can understand viewmodel in at least two ways
instead of passing your business objects to the view (for example MVC Razor view) you pass stripped down objects that contain properties that are needed for this view and nothing else. View creation is easier and you avoid problems when view designer uses fields that are lazy loaded from database (avoid Select N+1 problem and others)
you can create viewmodel that will be used client side (in Javascript). You create it in Javascript as object and thus it can contain methods that view can call. What you are describing (sending JSON objects using WebAPI) is just data that will feed that viewmodel.
For example of this you can look on main page here knockoutjs. You can see TicketsViewModel that contains tickets array. In this example you can see three kinds of tickets hardcoded in viewmodel. But you could get them as JSON from WebAPI like you described. After downloading them just put them in this array.

A DTO (data transfer object) contains data in a consumable format. A ViewModel/ActionModel contains data formatted for the View to consume.
A DTO might look like:
public class OrderDTO
{
public decimal Price { get; set; }
public int Amount { get; set; }
}
While a ViewModel might look like:
public class OrderViewModel
{
public decimal Price { get; set; }
public int Amount { get; set; }
public string PriceBackgroundColor { get; set;}
public Uri ImageUri { get; set; }
}

Related

ASP.net MVC Is it possible to modify a class object in a view?

I am a newbie and creating a website where you can create your own custom quizes. Ive made a database that stores a class object mytests that consists of a name, and a list of questions parameter.
public class MyTests
{
public int ID { get; set; }
public string name { get; set; }
public string description { get; set; }
public List<MyQuestions> AllTestQuestions;
}
//using this object for questions
public class MyQuestions
{
public string QuestionDescription { get; set; }
public string MultipleChoiceCorrect { get; set; }
public string MultipleChoiceB { get; set; }
public string MultipleChoiceC { get; set; }
public string MultipleChoiceD { get; set; }
public string Answerexplanation { get; set; }
}
I'm using the default database code generated by visual studio. I have no problem adding this test object(mytest) to the database, but what I want to do is that on the edit.cshtml view I want to be able to add elements to the question list before returning the object to the database saved.
The problem is I don't know how to edit the model object from the view, or if this is even possible. I could maybe get it to work through a redirect? but I thought that adding the elements directly from the view would be easier. Is it possible to modify the model.object inside a view from the view (putting security concerns aside)?
For example model.title = something;
or
model.list.add()
Is anything like this possible?
If this question is not clear please let me know and I will try to clarify in the comments.
Yes, it is possible to edit the model from within the view.
From within your .cshtml file specify the view model using the #model declaration, then edit the model like so:
#model Namespace.For.MyTests
#Model.name = "Hello World";
<p>#Model.name</p>
Whilst this would work, it's not really what the view is for so I wouldn't recommend it.
The view is about presenting your data, not mutating it - that should be done in the controller, or domain layer. As soon as the user leaves the page then your changes will be lost due to the stateless nature of the web (.NET MVC passes data to the view from the controller, then ends the request).
This should be done at the controller level. You could do it on a view but it's not what the view is for.
Your issue is that if the page is refreshed you will lose you content, so if you do anticipate on the page refreshing you will need a way in which to temporarily hold the information before it being saved.
On a side note, I'd also consider renaming your classes "MyTests" to "MyTest" (singular) and "MyQuestions" to "MyQuestion"... it's just good practice because then you'd have a List of singleton "MyQuestion" in a "MyTest". EntityFramework Codefirst will pluralise the names when the database is created/update.

Most efficient way to convert a object to another (Model to ViewModel)

Suppose I have a model with 20 fields, and in my index page, I want to list all models that are stored in my database.
In index page, instead of listing all fields of the model, I only to list 3 fields.
So, I make two class:
class CompleteModel {
public int Id { get; set; }
public string Field01 { get; set; }
public string Field02 { get; set; }
public string Field03 { get; set; }
public string Field04 { get; set; }
public string Field05 { get; set; }
...
public string Field20 { get; set; }
}
now, in my Controller, I can use:
await _context.CompleteModel.ToListAsync();
but I feel that it does not seem to be the right way to do it, because I'm getting all fields and using only 3 fields.
So, I made this code:
class ViewModel {
public string Field02 { get; set; }
public string Field04 { get; set; }
public string Field08 { get; set; }
}
var result = _context.CompleteModel.Select(
x => new {
x.Field02,
x.Field04,
x.Field08
}).ToListAsync();
var listResults = new List<IndexViewModel>();
if (result != null)
{
listResults.AddRange(results.Select(x => new IndexViewModel
{
Field02 = x.Field02,
Field04 = x.Field04,
Field08 = x.Field08
}));
}
I think this is a lot of code to do this.
First, I selected all the fields that I want, then, copied everything to another object.
There's a "more directly" way to do the same thing?
Like:
_context.CompleteModel.Select(x => new IndexViewModel { Field02, Field04, Field08 });
You could use AutoMapper to reduce the boiler plate so you're not manually copying field values over.
If you include the AutoMapper NuGet package then you'd need to have the following in your startup somewhere to configure it for your classes:
Mapper.Initialize(cfg => cfg.CreateMap<CompleteModel, ViewModel>());
You could then do something like the following:
var results = await _context.CompleteModel.ToListAsync();
var viewModelResults = results.Select(Mapper.Map<ViewModel>).ToList();
There are a lot of configuration options for the package so do take a look at the documentation to see if it suits your needs and determine the best way to use it if it does.
In my view this is one of the weaknesses of over abstraction and layering. The VM contains the data that is valuable to your application within the context of use (screen, process etc). The data model contains all the data that could be stored that might be relevant. At some point you need to match the two.
Use EF Projection to fetch only the data you need from the database into projected data model classes (using the EF POCO layer to define the query, but not to store the resultant data).
Map the projected classes onto your VM, if there is a naieve mapping, using Automapper or similar. However unless you are just writing CRUD screens a simple field by field mapping is of little value; the data you fetch from your data store via EF is in its raw, probably relational form. The data required by your VM is probably not going to fit that form very neatly (again, unless you are doing a simple CRUD form), so you are going to need to add some value by coding the relationship between the data store and the View Model.
I think concentrating on the count of lines of code would lead to the wrong approach. I think you can look at that code and ask "is it adding any value". If you can delegate the task to Automapper, then great; but your VM isn't really pulling its weight other than adding some validation annotation if you can consistently delegate the task of data model to VM data copying.

Domain Model with partially loaded objects

Let's say I have an application which consists of both client and server. Client is using MVVM pattern (with WPF) and server is simply a WCF service which fetches some data from database and returns data as DTO-objects to client. In client, DataAccess layer converts these DTOs to domain objects and passes them to Model. ViewModel uses Model to fetch data (Domain Object) and populates itself with it.
To optimize database performance, each ViewModel is given only the data it really needs and nothing more (as recommended by many sources). For example, let's say there is an entity called DbCustomer which has 30 properties, and there are also 3 different Views related to customers: CustomerProfileView, CustomersListView and CustomerThirdView. Every view needs different portion of data: CustomerProfileView uses 20 properties, CustomersListViewuses 10 properties and CustomerThirdView uses only 4 properties. For each View, only required properties are fetched from database and delivered to ViewModel.
Now the problem arises: how should I design my Domain Objects to support this?
Solution 1, one partially loaded Domain Object (no-go)
If I have only one Customer Domain Object which is used by all ViewModels, it would have different data depending on the ViewModel that requested it. Obviously this is a no-go way because if I have to use this Customer object somewhere else I cannot be sure does it have enough properties loaded.
For example, I might have method GetDataStoragePath which is supposed to return string describing path to customer's private files. The method requires properties FirstName, LastName, SSN and IsExternalCustomer. Now, let's say CustomerThirdView doesn't need IsExternalCustomer, so it is not loaded when CustomerThirdViewModel requests Model to load Customer. Now if I use this Customer somewhere else (it is not a ViewModel specific object), the method GetDataStoragePath will fail.
Solution 2, three different Domain Objects
In another solution there would be 3 different Domain Objects (used as data containers) with suitable interfaces, and thenGetDataStoragePath would depend only from this interface. Example:
public interface ICanGetDataStoragePath {
string FirstName { get; }
string LastName { get; }
string SSN { get; }
bool IsExternalCustomer { get; }
}
public CustomerProfileData : ICanGetDataStoragePath { ... } // Implements interface
public CustomerListViewData : ICanGetDataStoragPath { ... } // Implements interface
public CustomerThirdViewData { ... } // Does NOT implement interface
public class CustomerLogic : ICustomerLogic {
public string GetDataStoragePath(ICanGetDataStoragePath customer) {...}
}
This would lead to Anemic Domain Model but it is not a problem in my opinion. However, it seems messy since I can easily imagine that there would be 20 different methods with different needs which would result in 20 interfaces (and only for Customer, there are LOTS of other domain objects also). Of course in this simple case I could pass all four parameters separately to GetDataStoragePath but in real life there are many more required properties.
Are there any other options? What would be the best way to solve the problem?
Your model obviously has to much Data. Why not make 3 models and one composite model?
i.e.
public class CustomerProfile
{
public string Phone { get; set; }
// other profile fields
}
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string SSN { get; set; }
public bool IsExternalCustomer { get; set; }
public CustomerProfile Profile { get; set; }
}
Then you'd put all of your always required fields into the Customer class and group the rest together, i.e. in a CustomerProfile class. If it's null, then that data wasn't fetched and isn't available

request-response pattern mvc

Is the request-response pattern in Asp.net (Webforms) the same as (or similar to) the 'model' being passed and returned in the MVC world. Basically, should there still be a need to use the request / response (i.e. creating seperate request and response classes) pattern if all the request/response classes are doing is containing some properties related to request or response and can actually be placed in the model, e.g.
LoginRequest.cs contains
string Username { get; set; }
LoginResponse.cs contains
string AuthenticationTicket { get; set; }
whereas LoginModel.cs would have
string Username { get; set; }
string AuthenticationTicket { get; set; }
Which is better in to use in the MVC world ?
Thanks.
One could argue that depending on the level you look at it, they are both the same since you have a request (postback with context parameters/model binded through model binder) and a response (changing the response object/rendering the view based on viewmodel) in every request, but on another level they are fundamentally different since webforms was conceived to be natural to windows forms developers and MVC is, IMO, a more mature and with better SoC architecture for web frameworks.
When dealing with MVC apps I usually go for one class that represents the view model and another one that make sense for the request so in a user details scenario I would have something like this:
public class LoginModel
{
public string Username {get;set;}
public string Password {get;set;}
}
public class LoginViewModel
{
public string Username {get;set;}
public string Fullname {get;set;}
public string LastLogin {get;set;}
}
public ActionResult Login(LoginModel model)
{
/* do whatever you need */
return new LoginViewModel { ... };
}
You still need the Request/Response DTOs when dealing with WCF Scenarios. The Request entity should be serializable and contains information that shd be discrete to the MVC View. On the other hand, the view model contains information bound to the relevant view. hope this help!

Passing and returing data to a simple grid form using ASP.NET MVC

I have page with a simple table and advanced search form. I pass List<Customers> to the model:
View(List<Customers>);
So what is best way to pass and return data to the search form? I want to use validation or something but I think passing data through ViewData is not good idea. Any suggestions?
You should wrap all your data that is required by you view in a model specific to that view. The advantage to this is you could also include your search criteria in the model which would be empty at first but when your search posted, the model would automatically contain your search criteria so you could reload it when passing back the results. This will help maintain your state between post's as well.
This also allows all your view's data to be type safe where ViewData would not be.
Eg:
public class CustomerSearchViewModel
{
public List<Customer> Customers { get; set; }
// your search criteria if you want to include it
public string SearchFirstName { get; set; }
public string SearchLastName { get; set; }
public int SearchCustomerID { get; set; }
// etc...
}
When you return back the List<Customer> the search criteria would already be filled in your model from the post so your view can default the search criteria back to the corresponding controls (assuming your search results and search inputs controls are on the same view).
For example, in your post you would accept a CustomerSearchViewModel. Then all you need to do is get your list of customers and add it back to the model and return the same model.
// assuming you have accepted a CustomerSearchViewModel named model
model.Customers = GetCustomersForSearchCriteria(model.SearchFirstName,
model.SearchLastName, model.SearchCustomerID);
return View(model);
You could also add the validation attributes to your model properties to leverage the built in validation in MVC. This would not be possible if you were using ViewData to pass this data around.
You have to also consider the 'next guy'. It's cleaner when all the data that the view requires is located in a single class. This way they don't have to hunt through the code to discover if ViewData is being used and what data is actually being passed around in it.
ViewData is still an option for passing data but I try to minimize the use of it if at all possible.
Rather than passing just a list of items to your View, create a class which contains your list of items and any other data you might need, i.e. a ViewModel.
public class CustomerSearchViewModel {
public IEnumerable<Customer> Customers { get; set; }
public string SearchTerm { get; set; }
}
.....
var viewModel = new CustomerSearchViewModel {
Customers = customerList,
SearchTerm = searchTerm
};
return View(viewModel);

Categories