Is there a way to white list a subclass via the attribute?
public class VoteQuestionViewModel
{
[Display(Name = "Vote Question")]
public string Name { get; set; }
public VoteTypeViewModel VoteType { get; set; }
}
public class VoteTypeViewModel
{
public int Id { get; set; }
[Display(Name = "Type of Question")]
public string Type { get; set; }
[Display(Name = "Description")]
public string Description { get; set; }
}
The below will will only work to white list class property, but it will not work to whitelist child class property:
public async Task<IActionResult> Create([Bind("Name, VoteType.Description")] VoteQuestionViewModel voteQuestion)
The method you included in your question is the only way. Bind works on posted values. In other words, it's looking at the key names in the form data. In that respect, there is no VoteType key and never will be: only the properties on that class that were posted, i.e. VoteType.Description.
That said, not only is it extremely bad practice to use Bind at all, but using it in conjunction with view models makes absolutely no sense. The whole point of Bind is to allow you to include/exclude a subset of properties on an entity class. Likewise, the whole purpose of a view model is to deal with only the data that the view needs to work with. Therefore, if you don't want a property to be included in the post, don't put it on the view model. Even then, view models come with the extra caveat that data has to be mapped to/from the entity class onto to them. That gives you the ability to explicitly decide what will and will not get mapped. For example, if you need Id for some reason in your view, but you don't want the user to be able to change it, simply don't map it from your view model back onto your entity.
Related
I made an MVC project which includes CRUD operations to all my classes, using default controllers and view pages which support those operations.
My new task was to make few API controllers to specific classes, which I have done correctly so far.
The problem is when a get request is requested, an entire object is returned with all its connections to other classes (which is correct!), but say I have this class:
public class VM{
public int Id { get; set; }
public string MacAddress { get; set; }
public string IpAddress { get; set; }
public DateTime? CreateDate { get; set; }
public string PrivateKey { get; set; }
public int AppId { get; set; }
public int CompanyId { get; set; }
}
I don't want the user to get the privateKey for instance, or ID. I would like the user to get all the rest, but certain information should NOT be sent.
What is the best practice to achieve that? Will making a new class which does not have those specific class members be the right answer?
Say tomorrow I would like to add another data member which will not be sent, will I have to make ANOTHER class?
I assume changing those specific data members' data to null just before sending the object back to the client is not the right answer, is it?
Just setting them to null is not the right answer indeed.
But generally you want your application to be as consistent as possible, and thus, for similar request you should return about the same types of fields/objects.
Thus a few (2 or 3) DTO (data transfer objects) should be sufficient.
If the project is of a small scale, or you just feel like being crazy you can always convert them to anonymous objects as follows:
List<VM> VMs = VMRepo.GetAll();
vms.ConvertAll(vm => new {vm.MacAddress, vm.IpAddress});
Or even give then custom names:
vms.ConvertAll(vm=> new {MAC= vm.MacAddress, IP= vm.IpAddress});
I have a view that contains conditional logic to render partial views within the main view based on conditions in the model. Originally I included the properties required for the partial view in the main page's view model and everything was hunky dory. I simply created the partial view and had it inherit the same view model as the main page like so:
public class SomeViewModel
{
public int SomeProperty {get; set;}
public string SomeOtherProperty { get; set; }
etc ...
public string PartialViewProperty { get; set; }
}
Then in the partial view:
Inherits="System.Web.Mvc.ViewUserControl<SomeViewModel>"
But now I want to reuse the partial views on pages with different view models, so the partial view can no longer inherit the same view model as it's parent since the parent view models will be different. I thought of creating a separate model for the partial view and include that in the parent view, but in many cases there is only one property required in the partial view. I could just pass the property through ViewBag or something, but I prefer that all my views are strongly typed. If I go with creating a separate model for partial views my models will now look like this:
public class SomeViewModel
{
public int SomeProperty {get; set;}
public string SomeOtherProperty { get; set; }
public SomePartialViewModel SomeModelObject { get; set; }
}
public class SomePartialViewModel
{
public string PartialViewProperty { get; set; }
}
I'm sure this would work, but it doesn't feel right. It looks strange to me to see a class with only one property in it. I searched Google & SO for things like "class with only one property" etc and could not find examples of classes with just one property. So my questions are:
Are single property classes OK and I just didn't happen to find any examples?
Is there a better way of doing what I want to do that I am overlooking?
Are single property classes OK and I just didn't happen to find any examples?
I don't see anything wrong with this, and I know I've used this myself for certain things. The partial itself is still a different view to your main view, so essentially, that single-property class does represent everything the partial would need in order to be rendered.
Having said that, you could just strongly-type the partial to the type of the property in question. For example, taking your code above:
public class SomeViewModel
{
public int SomeProperty {get; set;}
public string SomeOtherProperty { get; set; }
public SomePartialViewModel SomeModelObject { get; set; }
}
public class SomePartialViewModel
{
public string PartialViewProperty { get; set; }
}
Rather than making the view strongly-typed against SomePartialViewModel, make it strongly-typed against string instead. That way, your parent view model can be simplified to this:
public class SomeViewModel
{
public int SomeProperty {get; set;}
public string SomeOtherProperty { get; set; }
etc ...
public string PartialViewProperty { get; set; }
}
And now you can pass the string to the partial:
#Html.Partial("SomeView", Model.PartialViewProperty)
My personal preference is not to do this. The simple reason being that you could pass any string to that view by mistake and the view would compile. Having a dedicated view model for each partial reduces the likelihood of that happening.
Is there a better way of doing what I want to do that I am overlooking?
You could possibly argue that what you're doing is overkill for smaller projects but, like you, I prefer my views to be strongly-typed. Partials are there to be reused and, to me, that means they should be self-sufficient.
Edit
Actually, we should be talking about validation here too. There are two ways you could look at it:
A partial is completely encapsulated for reuse, meaning its validation requirements should not change.
A partial encapsulates the data passed to it but may have different validation requirements based on which view it's called from.
In my mind, the first one is ideally how everything should be. That would mean validation rules would be applied to a dedicated view model for a particular partial.
However, we've all come across situations where validation requirements change. It may not be desirable but it may also not be unreasonable to expect validation requirements to change for a partial. In that case, having a dedicated view model for the partial would be a problem because the validation rules would apply for all invocations of that partial view.
By applying validation to the parent view model instead, you'd be able to change the validation requirements for the partial. For example:
public class ViewModelForViewA
{
public int Id { get; set; }
// other properties
[Required]
public string PartialProperty { get; set; }
}
public class ViewModelForViewB
{
public int Id { get; set; }
// other properties
// No longer required
public string PartialProperty { get; set; }
}
However, I still believe the first way is the right way. If a partial had different validation requirements in view A and view B, you could argue that it doesn't represent the same view.
They aren't real classes. They are just lowly view models. Don't let their abnormal appearance startle you.
In all seriousness, what you've described, with the partials having their own models is exactly how I have done it. Yes, some folks (and FXCop) will probably harp on you for it, but it's much cleaner and more extensible, as you've described in your post.
My User entity has numerous differing properties which define the User record. After the default scaffolded edit and create pages are created we are now trying to implement some regions to the pages so similar areas of the users profile can be edited and updated without posting back and refreshing the entire list of properties.
I was thinking of splitting the regions into separate partial views like below and then using #Ajax.BeginForm(
public partial class UserContact : UserBase
{
[DataType(DataType.EmailAddress)]
[StringLength(255)]
public string EmailAddress { get; set; }
[DataType(DataType.PhoneNumber)]
[StringLength(50)]
public string PhoneHome { get; set; }
...
}
public partial class UserAddress : UserBase
{
[StringLength(60)]
public string AddressLine1 { get; set; }
[StringLength(60)]
public string AddressLine2 { get; set; }
...
}
public partial class UserBase
{
[Key]
[Required(ErrorMessage = "User is required")]
public System.Guid UserId { get; set; }
}
just spotted the binding keyword and i was wondering which methods people use. I would imagine its not very efficient over the wire and both in terms of the necessary validation to post back an entire Usermodel each time so do people split the main model into seperate models, or is it possible (or even adviseable) with the bind parameter to specify only a subset of the properties?
In my opinion it is indeed advisable to split the model into multiple sub models, however you also need to split your actions into sub actions. Each action will be 'bound' to that sub class and not the entire UserBase class.
If you use only one action, I don't think it is possible to [dynamically] specify what properties to bind and which not.
I'm just getting started with MVC and have my first project under development. I've been trying to wrap my head around an issue with my viewmodel and a domain object.
My view model consists of a customer object and an address object. The problem is, even though all the properties of the customer and address display on the view, I can only save changes if I explicitly define each property in the view model. In other words, I need to duplicate the properties of the customer and address objects in the view model. This solves all my problems.
My question is, do I need to explicitly define each property in the view model or is there a way I can just define the view model with a Customer property of type Customer and an Address property of type Address (which would be much simpler)?
Based on I what I'm finding online, I think the answer is I must define each property in the view model. If that is correct, are there any ways to automatically do this mapping for me?
ASP.NET MVC 4
AutoMapper is quite popular for mapping.
Regarding your ViewModel definitions, you want your ViewModel to correspond directly to the your View. There shouldn't be a property in your ViewModel that isn't used on the View. If you've got logic-less Views (which you should!), then often the properties on your ViewModel will be directly related to the fields you have on your View.
Of course, there are times when two ViewModels will use exactly the same properties and there's nothing stopping you from doing something like this:
public class CustomerViewModel {
public string Name { get; set; }
public AddressViewModel Address { get; set; }
}
public class AddressViewModel {
public string AddressLine1 { get; set; }
}
The problem is as soon as you start doing this, it's oh so much easier to let yourself slip in a property that isn't used somewhere once or twice, maybe throw in some ViewModel inheritance and you end up with very messy ViewModels.
Generally I've found that the recommendation is to have flat ViewModels. For instance, if you have two Views that need Customer and Address information, just take the hit, create a separate ViewModel for both Views and duplicate the properties in both of them.
Define only the necessary properties your View requires in the ViewModel. Your ViewModel may look similar to your Domain model. But youur view model needs only properties required by the view. Not all the properties.
Ex :You may have a customer domain model with properties CustomerID, FirstName,LastName,CreatedDate,CreatedBy,LastModifiedDate.
public class CustomerDomainModel
{
public int CustomerID { set;get;}
public string FirstName { set;get;}
public string LastName { set;get;}
public DateTime CreatedDate { set;get;}
public DateTime LastModifiedDate { set;get;}
public int CreatedBy { set;get;}
}
But in your view (UI - form) , you may need to show the fields for only FirstName and LastName. So your viewModel may have only those 3 properties ( FirstName & LastName + another property to have the CustomerID also)
public class CustomerViewModel
{
//My view is going to use only these 3 fields.
// Hence no other properties i am defining here
public int CustomerID { set;get;}
public string FirstName { set;get;}
public string LastName { set;get;}
}
To map between these 2 (Domain object to ViewModel) , you may consider using Automapper
This is somewhat a two-part question (please let me know if they should be split up).
1) I have a model class with an array of objects contained inside it. I would like to be able to bind this automatically so I can accept a single pollModel argument in my controllers.
public class pollResponseModel
{
public long id { get; set; }
public long pollID { get; set; }
public string text { get; set; }
public long count { get; set; }
}
public class pollModel
{
public long id;
public long entID { get; set; }
public string question { get; set; }
public DateTime posted { get; set; }
public DateTime expiration { get; set; }
public pollResponseModel[] responses { get; set; }
}
The problem is that I'm not sure how to bind the responses field, seeing as it can be any arbitrary size. Well, I can bind it properly when displaying the edit view, but that's about it. That leads me to the second part of my question:
2) What's an acceptable way of dynamically creating and removing data in a list on the client, so that it can be bound to a model and accessed in its modified form on the server? I envision the creation/removal process working like the iPhone list GUI: a single + button will add a new element, and a - button on each row of data will remove it from the list. I would imagine jQuery is an appropriate starting point but my JS skills are very limited.
Check out this article by Phil Haack : Model Binding To a List. It explains exactly what you need to do to bind to list properties, or properties that are complex objects.
Essentially you just have to construct your POST data in the correct way for the model binder to parse it. The article explains how to add hidden index fields and represent your complex properties in your form.