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.
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 have a class, which has 8 properties / 8 columns in DB. In the Edit page, I want to exclude the AddedDate and UserID fields. When a user edits a voucher, he can't overwrite the AddedDate or UserID values in the DB.
public class Voucher
{
public int ID { get; set; }
public string Title { get; set; }
public string SiteName { get; set; }
public string DealURL { get; set; }
public DateTime AddedDate { get; set; }
public DateTime? ExpirationDate { get; set; }
public string VoucherFileURL { get; set; }
public Guid UserID { get; set; }
}
Here is what I have for Edit controller:
// POST: /Voucher/Edit/5
[HttpPost]
public ActionResult Edit([Bind(Exclude = "AddedDate")]Voucher voucher)
{
if (ModelState.IsValid)
{
db.Entry(voucher).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(voucher);
}
On Edit page, when I click on submit, I got the following error:
System.Data.SqlServerCe.SqlCeException: An overflow occurred while converting to datetime.
Seems like the AddedDate didn't get excluded from the voucher object and triggered the error.
Would you please let me know how to fix it? Thanks!
(it is an updated version of asp.net mvc3 UpdateModel exclude properties is not working, I will go with another approach)
Never use your domain entities as action arguments and never pass your domain entities to your views. I would recommend you to use view models. In the view model you will include only the properties that you want to be bound from the view. The view model is a class that's specifically tailored to the requirements of a given view.
public class VoucherViewModel
{
public int ID { get; set; }
public string Title { get; set; }
public string SiteName { get; set; }
public string DealURL { get; set; }
public DateTime? ExpirationDate { get; set; }
public string VoucherFileURL { get; set; }
}
and then:
[HttpPost]
public ActionResult Edit(VoucherViewModel model)
{
// TODO: if the view model is valid map it to a model
// and pass the model to your DAL
// To ease the mapping between your models and view models
// you could use a tool such as AutoMapper: http://automapper.org/
...
}
UPDATE:
In the comments section #Rick.Anderson-at-Microsoft.com points out that while I have answered your question I haven't explained where the problem comes from.
The thing is that DateTime is a value type meaning it will always have a value. The [Bind(Exclude = "AddedDate")] works perfectly fine and it does what it is supposed to do => it doesn't bind the AddedDate property from the request. As a consequence the property will have its default value which for a DateTime field is 1/1/0001 12:00:00 AM and when he attempts to save this in SQL Server it blows because SQL Server doesn't support such format.
I am developing a blog application in ASP.NET MVC and I have doubt whether my solution of updating some related classes is fully correct.
I have a class representing texts:
public partial class Text
{
public long ID { get; set; }
public string Title { get; set; }
...
public virtual ICollection<Tag> Tags { get; set; }
}
and tags:
public partial class Tag
{
public long ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Text> Texts { get; set; }
}
When I'm editing a texts, the TextEditorViewModel is being passed:
public class TextEditorViewModel
{
public long ID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public IEnumerable<TagEditorViewModel> Tags { get; set; }
}
TagEditorViewModel is:
public class TagEditorViewModel
{
public long ID { get; set; }
public string Name { get; set; }
public bool IsInText { get; set; }
}
In the view I'm checking appropiate tags (this is reflected by IsInText property) and this works fine and correct data is being passed back to the controller.
Here is my code for the repository on which controller is working:
Text OriginalText = Mapper.Map<Text>(Text);
IEnumerable<long> tags = OriginalText.Tags.Select(tag => tag.ID);
ICollection<Tag> tagobj = context.Tags.Where(tag => tags.Contains(tag.ID)).ToList();
OriginalText.Tags = tagobj;
Text is object of TextEditorViewModel which is passed back on post. I'm using mapper to bind only primitive types and I'm rewriting all collection and reference types (as seen above), only tags marked as not in the text are filtered out. Is there any simpler way of managing the tags instead of quering the database and rewriting them?
You can attach the tags manually to the context instead of reloading them from the database because you have the ID of the tags which is sufficient to create/update a relationship:
Text OriginalText = Mapper.Map<Text>(Text);
foreach (var tag in OriginalText.Tags)
context.Tags.Attach(tag);
context.Texts.Add(OriginalText);
context.SaveChanges();
(I've taken the last two lines from your comment.)
Even though the properties in the different tags don't have the values from the database (except the ID) it will work because EF only needs the correct tag ID to create the relationship.
I have an order model (shown below)
public class Order
{
//[Key]
[ScaffoldColumn(false)]
public int OrderId { get; set; }
[DisplayName("Order Date")]
public DateTime OrderDate { get; set; }
public virtual ProductSelection ProductSelection { get; set; }
public virtual ShippingDetails ShippingDetails { get; set; }
public virtual BillingDetails BillingDetails { get; set; }
public virtual CardDetails CardDetails { get; set; }
public virtual AccountUser AccountUsers { get; set; }
}
As you can see is made up of a set of other models for example ProductSelection (shown below).
public class ProductSelection
{
public int SimulatorId { get; set; }
public string VersionNumber { get; set; }
[DisplayName("Quantity")]
public int Quantity { get; set; }
[DisplayName("Total Price")]
[ScaffoldColumn(false)]
public decimal TotalPrice { get; set; }
}
The issue I am having is when I post to the Controller which has a parameter of Order, I am unable to obtain any of the values from the sub-models (for example Order.ProductSelection.SimulatorId.)
Any ideas why this isn't working as I having to currently use FormCollection which isn't ideal and better messy.
Looking forward to replies
Steve
1) Silly question but just to make sure....Do you preserve values of your sub model on the view(In the form as hidden or any other input type,make sure name of your hidden are same as your properties name in the model) or in the query string.
Before giving you fully loaded model, model binder looks at different places to load your model like your form collection,rout data and query string
If you are not preserving them in any of these places then model binder has no way to find those values and give you loaded values on controller action.
Basics.. http://dotnetslackers.com/articles/aspnet/Understanding-ASP-NET-MVC-Model-Binding.aspx
2)Your example model seems fine but make sure all properties of your sub model have public access modifier and they must have set in their property declaration.
--->I had same issue before because I had private access modifier for set on those properties and I wasted whole day to figure that out.
3)If nothing works(hope that's not the case) then at last you can write your own model binder.
Here is the good post if you decide to head in that direction
http://buildstarted.com/2010/09/12/custom-model-binders-in-mvc-3-with-imodelbinder/
This is my first post (under my account) and it feels really good to participate..!!
You should apply ForeignAttribute on the ProductSelection property which points the primary key of the ProductSelection class:
[ForeignKey("SimulatorId")]
public virtual ProductSelection ProductSelection { get; set; }
Hope that helps.
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; }
}