I have an object like this
public class ParentEntityInfo
{
public long? ParentId { get; set; }
public string EntityName { get; set; }
public string ParentProperty { get; set; }
}
and view for this object is:
<%=Html.Hidden("parentInfo.ParentId", parentInfo.ParentId)%>
<%=Html.Hidden("parentInfo.ParentProperty", parentInfo.ParentProperty)%>
<%=Html.Hidden("parentInfo.EntityName", parentInfo.EntityName)%>
I have the case where parentInfo is null and I post this form to controller. On the controller action
public ActionResult SomeAction(..., ParentEntityInfo parentInfo)
I receive constructed object parentInfo but all properties are null. In this case I would rather prefer to have whole parentInfo to be null. I there any possibility to tell default model binder do not pass such object? Or probably I can modify something in this code to make it work this way. I think in mvc 2.0 it worked this way.
Use the HiddenFor(...) helper instead.
I think the default model binder will always use Activator.CreateInstance to bind complex action parameters. What you can do is use ModelState.IsValid to assess whether the parameter was bound successfully. I think in your case this will be false by default, but if not you could add the necessary attribute to ensure this behaviour e.g.
public class ParentEntityInfo
{
[Required(ErrorMessage = "Parent required")]
public long? ParentId { get; set; }
public string EntityName { get; set; }
public string ParentProperty { get; set; }
}
Related
I have a model like the followings:
public class MyModel {
[Required]
public string Name { get; set; }
public string Family { get; set; }
[Required]
public int Number { get; set; }
}
So for example in Edit View I have 3 Editorfor() objects and I am interesting to filter the post data of this page, actually I want to ignore Number field and just want to post Name and Family Also I need the validations of Number be active, One way is I remove Number property from MyModel and define in view by hand and write all validation script by own, but I am interesting to know is there any simpler way in MVC. Does anyone have any idea?
Controlling all that validation and model binding manually is way too complicated and error-prone. You should be using ViewModels
public class SomeSpecificViewModel
{
[Required]
public string Name { get; set; }
public string Family { get; set; }
}
public ActionResult SomeSpecificAction(SomeSpecificViewModel model)
{
//...
}
Now MVC wil validate only Name and Family
Any value not filled in the view will not be posted to the controller. However, if a field which is [Required] is not filled, then ViewModel.isValid will be false.
I want to input html in the database and also display it back as html. I wrote my view model like this:
public class TemplateVM
{
[HiddenInput(DisplayValue = false)]
public int TemplateId { get; set; }
public string Name { get; set; }
public string Content { get; set; }
}
the property Content should be able to accept html. How can I do this? Right now, it throws the error of:
A potentially dangerous Request.Form value was detected from the client (Content="<p>test</p>").
I'm aware of using this on the action, but I dont want it to apply to every property.:
[ValidateInput(false)]
Instead of using ValidateInput attribute on entire model, I suggest you use AllowHtml attribute on Content property:
public class TemplateVM
{
[HiddenInput(DisplayValue = false)]
public int TemplateId { get; set; }
public string Name { get; set; }
[AllowHtml]
public string Content { get; set; }
}
This attribute is only applied for Content property, while other properties are still validated.
Put [ValidateInput(false)] on top of TemplateVM. It will apply to all properties.
I have the following ViewModel and i would like to create a custom binder to bind subclasses (LogOnModel, ChangePasswordModel).
public class LogOnViewModel
{
public string NextStep { get; set; }
public string PreviousStep { get; set; }
public string ReturnUrl { get; set; }
public bool MustChangePassword { get; set; }
public bool MustAgreeNewPrivacyStatement { get; set; }
public LogOnModel logOnModel { get; set; }
public ChangePasswordModel changePasswordModel { get; set; }
}
I was able to create my custom binder (inherit from DefaultModelBinder) but never was able to get a full VALIDATED model (ModelState populated) back into my controller. It's working fine for simple type (string, bool, ....) but a bit more complicated with complex type (subclass).
Is MVC 3 Futures the answer to my question or someone was able to override DefaultModelbinder to bind subclasses?
Thanks,
Michel
You will have to create custom model binders for LogOnModel and ChangePasswordModel as well; your custom model binder doesn't know automatically how to bind your complex types.
In my MVC application I have a problem with passing data from view to controller. I have fairly complex domain classes:
public class TaskBase : PersistableObject
{
public virtual TaskCategory Category { get; set; }
public virtual IList<TaskNote> Notes { get; set; }
public virtual string TaskTitle { get; set; }
public virtual string TaskBody { get; set; }
public virtual DateTime? CreationTime { get; set; }
public virtual User CreatedBy { get; set; }
public virtual int CompletionRatio { get; set; }
}
public class MainTask : TaskBase
{
public virtual IList<TaskBase> ChildTasks { get; set; }
public virtual User AssignedTo { get; set; }
public virtual IList<TaskHistory> History { get; set; }
}
public class TaskFormModel : ViewDomainBase
{
public MainTask Task { get; set; }
public LoginForm LoginInfo { get; set; }
}
And in my view I want to pass an instance of TaskFormModel to the controller.
<%= Html.ActionLink<TaskController>("Edit Task", (x) => x.Edit(new TaskFormModel() { Task = item, LoginInfo = Model.LoginInfo }))%>
And here is the controller action:
public ActionResult Edit (TaskFormModel taskInfo)
{
return View(ViewPageName.TaskDetailsForm, task.Task);
}
In this action method taskInfo comes null even if I pass non-null instance from view. I think I have a binding problem here. I think, writing custom model binder requires every property to be converted and also when new fields added then binder class should also be changed, so I don't want custom model binder to do this. Is there any other way to pass data to controller in this scenario? Or could custom model binder can be coded so that less code written and also when new properies are added binder class will not need to be changed?
Edit After Comments: What I am trying to achieve is basically to pass an instance from one view to another view, without querying repository/db in my controller's action.
First version of answer:
Your GET edit method should be like:
public ActionResult Edit (int id)
{
var model = taskRepository.GetTaskEditModel(id);
return View(ViewPageName.TaskDetailsForm, model);
}
and ActionLink:
<%= Html.ActionLink("Edit Task", "Edit", "Task", new { model.Task.id })%>
If you want to pass complex objects to controller, you should wrap them up in html form and pass to POST action.
In my opinion you are doing something wrong.
As I understand: you are trying to instantiate a new object, pass it to browser and get it back.
well you cant.
If object you want to edit exists already in your storage, then you should alter your ActionLink to reference it by id, and instantiate it inside your Edit action.
Take a look at default strongly typed index views created by tooling.
I am using EFExtensions with a typed view in mvc and am getting
The model item passed into the dictionary is of type 'Microsoft.Data.Extensions.Materializer`1+d__0[MvcCms.Web.Models.User]' but this dictionary requires a model item of type 'MvcCms.Web.Models.ViewData.SiteAdminModel'.
'MvcCms.Web.Models.ViewData.SiteAdminModel' contains a definition of User, here is the code in SiteAdminModel
public class SiteAdminModel
{
public StateProvince SelectedState { get; set; }
public IEnumerable<StateProvince> States { get; set; }
public IEnumerable<Organization> Organizations { get; set; }
public IEnumerable<User> Users { get; set; }
}
What would be the best way to fix this. Possibly using a codebehind to cast the Materialized version or doing that in the controller?
The problem was occuring because I was passing the model through in the renderpartial and it didn't need to be passed there because the control had access without it.