I had this fixed a few months back and it must have just left my mind entirely, and since I just updated my data model on my MVC3 site (update model from db) it is broken again. I am getting the
A potentially dangerous Request.Form value was detected from the client
error. There are plenty of questions out already on this talking about changing some settings in the web.config, but I haven't ever been able to get those to work. The last time I fixed it I am 99% certain I changed something in this generated file:
[DataContract(IsReference = true)]
[KnownType(typeof(Blog))]
[KnownType(typeof(Comment))]
public partial class Post
{
public Post()
{
this.Comments = new HashSet<Comment>();
}
[DataMember]
public int Id { get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public System.DateTime DateCreated { get; set; }
//[SOMETHING HERE??]
[DataMember]
public string Content { get; set; }
[DataMember]
public string Tags { get; set; }
[DataMember]
public int BlogId { get; set; }
[DataMember]
public virtual Blog Blog { get; set; }
[DataMember]
public virtual ICollection<Comment> Comments { get; set; }
}
But I cannot for the life of me remember what, and I am not sure what words to search for on the web.
And I know that editing generated code is a big dumb thing to do, but I haven't figured out how to get around that just yet.
You are looking for the [AllowHtml] attribute:
[AllowHtml]
[DataMember]
public string Content { get; set; }
And I know that editing generated code is a big dumb thing to do, but
I haven't figured out how to get around that just yet.
The problem is that you are passing your WCF domain entities to/from views which is a very bad design approach.
The correct way is to use view models. View models are classes that you specifically design to meet the requirements of your views and then you only pass view models to the views. You will then map between your domain models and view models. AutoMapper is a great tool to simplify this task.
Related
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.
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.
I'm very new to entity framework and web api so please excuse me if what I'm trying to do doesn't make much sense! Is it possible to send one model on a post and receive a different model on a get? My example.
I have a very simple companies model:
public class Company
{
[Required]
public string companyName { get; set; }
public virtual List<Branch> branches { get; set; }
}
public class Branch
{
public int companyID { get; set; }
public string branchName { get; set; }
public string address { get; set; }
public string postcode { get; set;}
public string phoneNumber { get; set; }
public virtual Company company { get; set; }
}
When I post to myapp/api/companies I want to be able to include a list of branches to add alongside the company, this is currently working perfectly however, my front end designer has requested that the companies come back without the branches attached. I have tried [jsonIgnore] against the branches and this works for the GET but it also stops the branches from writing on a post. Is there some way to apply the jsonIgnore on the controller perhaps?
Should I try and convince my front-end guy to just ignore the branch data or is there some way I could omit it in the response?
Thanks
Chris
The way I finally managed to do this was to use eager loading instead of lazy loading. To achieve that remove virtual from each of the relations. This stops EF from getting the relations automatically then in any code that returns the object use .Include() to include any relations you want back in that return.
Using VS2010, .NET4.0, MVC3, EF4.1 Code-First
I have this POCO entities:
public class XBLContent
{
[Key]
[StringLength(36, ErrorMessage="Must have 36 characters")]
[Required(ErrorMessage="Must have a unique GUID")]
public string GUID { get; set; }
public int Price { get; set; }
public float FileSize { get; set; }
public virtual ICollection<XBLRegionalContent> RegionalInfo { get; set; }
public string RelatedGameId { get; set; }
[ForeignKey("RelatedGameId")]
public virtual XBLContent RelatedGame { get; set; }
}
public class XBLRegionalContent
{
[Key, Column(Order = 0)]
public string ContentId { get; set; }
[ForeignKey("ContentId")]
public virtual XBLContent Content { get; set; }
[Key, Column(Order = 1)]
public string RegionId { get; set; }
[ForeignKey("RegionId")]
public virtual XBLRegion Region { get; set; }
public string Name { get; set; }
}
public class XBLRegion
{
[Key]
[StringLength(5, ErrorMessage="ID must have 5 characters")]
[Required]
[RegularExpression(#"[a-z|A-Z]{2}-[A-Z|a-z]{2}")]
public string ID { get; set; }
public string Country { get; set; }
public string Language { get; set; }
}
Relationships:
One XBLContent has many XBLRegionalContent;
One XBLContent can be related to another XBLContent(most of them are not);
One XBLRegionalContent has one XBLContent and one XBLRegion;
One XBLRegion has many XBLRegionalContent;
The Context objetc is really simple:
public class XBLContentContext : DbContext
{
public DbSet<XBLContent> XBLContents { get; set; }
public DbSet<XBLRegionalContent> XBLRegionalInfos { get; set; }
public DbSet<XBLRegion> XBLRegion { get; set; }
public XBLContentContext() : base("XBLToolsDB")
{
}
}
I'm using XBLContent as my main business object and maybe that is not the best idea. I think there is something wrong with the architecture I designed because I'm having trouble to send information to the View and filter, sort, etc.
Now, I'm using Telerik grid and when I try to sort by a navigation property field I get an error saying that "No property or field exist". Maybe I should not use XBLContent as my main business object, or create a ViewModel containing all needed fields and send it to the View. Or create one single entity that splits into two EF tables(I don't know if that is possible or how to achieve that).
I'm just padawan in .NET and need some Jedi Masters advice.
I need contents that can have multiple translations.
How to best achieve this goal?
this should fix your problem.
http://weblogs.asp.net/manavi/ A great resource for beginners and i can see you have used a lot of annotations ,so a little bit of fluent api would make your concepts stronger.
I'm assuming you're using the Telerik MVC Extensions here, but if you are using a different product please let me know and I'll re-answer accordingly :)
In regards to the Grid what kind of binding are you utilizing? If you are using regular server or ajax binding then you might run into some issues when binding to a navigational property, as by default these bindings only work with primitive (int, string etc.) types. However, there is such a thing as custom binding which allows you to take full control over paging/sorting/filtering. I believe this could account for why you are getting this error, as the automatic LINQ expressions cannot find the specific field you are looking for. Here are two demos (which have source code for both WebForms and Razor ViewEngines) that can help with setting up custom binding. It's just a little more work than the automatic binding, but should still work (note that these examples are using Razor):
Ajax Binding
Server Binding
The added benefit here is that you get to control everything on your own, which can be quite nice in somewhat more complex scenarios. If you're already using custom binding, and/or if the links there do not help let me know. It could also be helpful to have the code for the Telerik Grid.
I've resolved these kinds of issues by normalizing the results like:
from r in ctx.XBLContents
select new
{
r.Guid,
RelatedGuid = r.RelatedGame.Guid
};
Essentially creating an anonymous classes that is more denormalized has worked for me to work around these kinds of issues, where the results denormalizes those navigational properties too.
HTH.
I an developing a page where users will be able to add and modify existing content, its not a wiki per sé but sort of, like SO's editing abilities.
I am working with EF4 and the new Code First approach in the latest CTP, so what would be the best class design for this?
my current guess is something like this:
public class VersionableText
{
public int Id { get; set; }
public DateTime Date{ get; set; }
public String Text{ get; set; }
public virtual User User{ get; set; }
}
and then use it in my other entities, in a SO context it could be something like this
public class Question
{
public int Id {get; set;}
public virtual VersionableText Title {get; set;}
public virtual VersionableText Content{get; set;}
...
}
But I'm not really convinced by it.. since I am also going to have tags, ability to delete/undelete posts, rollback, etc. Do you know how to properly design classes that help me version the content properly?
Aim for simplicity
The main question that you need to ask yourself is Are you going to show all versions all the time or the latest version most of the time and all of them on request? Similar to here. Most of the time you only see the latest version.
If this is the same with our case I wouldn't care so much about these versions. But when you'd want to show them all on one page class design more or less depends on the way that you'd like to show it. Is it going to be showing changes and things like that.
I'd rather have a class like:
public class Question
{
public int Id { get; set; }
public QuestionStatus Status { get; set; }
}
public class QuestionHistory
{
public Question Question { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public User Author { get; set; }
public DateTime Created { get; set; }
public IList<Tag> Tags { get; set; }
}
And when I'd display all of them I'd just return a list of these ordered by LastChange. I've added tags list but I didn't add any of the other process-related properties related to question state. It hugely depends on the process sequence.