Custom Validation Attribute for three levels deep model - c#

Hi I have a situation in witch I have to create some custom validation attributes because the way my model is created.The model looks something like this:
public class EvaluationFormDataContract
{
public int StudentAssignmentInstanceId { get; set; }
public int EvaluationType { get; set; }
public List<CategoriesOnEvaluationDataContract> Categories { get; set; }
}
public class CategoriesOnEvaluationDataContract
{
public string Memo { get; set; }
public int CategoryId { get; set; }
public List<QuestionsOnEvalCategoryDataContract> Questions { get; set; }
// Fields needed for validation
public bool? HasMemo { get; set; }
public bool MemoIsMandatory { get; set; }
}
public class QuestionsOnEvalCategoryDataContract
{
public string Memo { get; set; }
public string Grade { get; set; }
public int QuestionId { get; set; }
// Fields needed for validation
public bool HasGrade { get; set; }
public bool HasMemo { get; set; }
public bool ShowOnlyMemo { get; set; }
}
As it can be seem the model is composed two levels deep.
And I will have to validate starting from the second level , where I will check if the model HasMemo and if MemoIsMandatory.
The third validation should be done at the 3rd level where I have to check if it HasGrade and HasMemo.
Normaly if it were up to me I would split this in three separate calls to the server but we are depending on an legacy project and for the moment I have to make this work.
The post action will be called via an ajax call and will have all this data into it.
Now my question is where should I add the validation attribute?
Should it be added at the top on Categories , making it directly responsible for all the levels of the model?
Or I should place it on each model and find a way to make the data binder aware of it? If so how can I do this?

You can do both. If you implement System.ComponentModel.DataAnnotations.IValidatableObject interface at the top-most level, you can do whatever you want with the properties in the entire graph and return the errors.
public class EvaluationFormDataContract : IValidatableObject
{
// All properties go here
public IEnumerable<ValidationResult> Validate(
ValidationContext validationContext)
{
if (// do what you want)
yield return new ValidationResult("message");
}
}
Or, you can apply attributes at the lower levels and automatically binding takes care of validating the properties in the graph. You don't need to do anything special.

Related

How to pass different ViewModels to a generic method?

I have a project written in C# MVC 5. There are several Controllers/Views that perform a similar set of functions based on <input ... fields in the Razor View.
There's currently logic in each controller to save input field values to a database table and later allow these saved input values to be retrieved and the View's input fields are populated by them.
These Views have many similarities and so several of their fields are duplicated across these Models.
It's become difficult to maintain code in each controller that saves its own fields and I want to use generics to create a single, common routine that saves the values for any of these controllers.
For example, 2 simple ViewModels:
public class ViewModel1
{
public string Name { get; set; }
public int Unique1 { get; set; }
...
}
public class ViewModel2
{
public string Name { get; set; }
public int Unique2 { get; set; }
...
}
Database model used:
public class SavedInputs
{
[Key] public int Id { get; set; }
public string Name { get; set; }
public int? Unique1 { get; set; }
public int? Unique2 { get; set; }
}
Now I want to create a function that can save either ViewModel's fields. Something like:
public bool SaveToDb(T model)
{
var inputs = new SavedInputs()
{
Name = model.Name,
Unique1 = model.Unique1,
Unique2 = model.Unique2
}
_db.SavedInputs.Add(inputs);
...
}
Then from each controller's Save action:
public ActionResult SaveInputs(ViewModel1 model)
{
var success = SaveToDb(model);
}
Of course ... SaveToDb() above isn't going to work but hopefully it shows what I'm wanting to accomplish.
There's many ways to do this.
Either you could have a common interface or abstract class that all your view models share which have the properties you want to save. Then SaveToDb just takes the interface instead of the generic type. Then in SaveToDb you can access all the properties of the interface properties from the model passed in and do whatever you want with them. I guess if you want to just have some properties null then abstract class makes sense, since you can override whatever you want to use
e.g.
public abstract class SavedInputsBase
{
public virtual string Name { get; set; }
public virtual int Unique1 { get; set; }
public virtual int Unique2 { get; set; }
}
public class ViewModel1 : SavedInputsBase
{
public override string Name { get; set; }
public override int Unique1 { get; set; }
...
}
public class ViewModel2 : SavedInputsBase
{
public override string Name { get; set; }
public override int Unique2 { get; set; }
...
}
public bool SaveToDb(SavedInputsBase model)
{
var inputs = new SavedInputs()
{
Name = model.Name,
Unique1 = model.Unique1,
Unique2 = model.Unique2
}
_db.SavedInputs.Add(inputs);
}
Alternatively you could use something like Automapper nuget package and have SaveToDb take SavedInputs and then just map your viewmodel to SavedInputs. Or just manually map it everywhere you want to call SaveToDb.

Implementing Generic Interfaces for collections of widgets?

We're attempting to build a somewhat basic reporting system for our analytics team to use. It's our third or fourth iteration of the same system, but we're doing a consolidation and rewrite of a large portion of the backend logic to make generating reports easier going forward.
One issue we're having is forming the interfaces that will be implemented by our reporting widgets in order to push them through to our ViewComponents.
An example of a couple widgets may look something like the following:
public interface IWidget<T>
{
WidgetType WidgetType { get; set; }
string WidgetName { get; set; }
T ViewModel { get; set; }
}
public class ChartWidget : IWidget<Chart>
{
public WidgetType WidgetType { get; private set; }
public string WidgetName { get; set; }
public Chart ViewModel { get; set; }
public ChartWidget() {
WidgetType = WidgetType.Chart;
}
}
public class HeadlineBarWidget : IWidget<HeadlineBarData>
{
public WidgetType WidgetType { get; private set; }
public string WidgetName { get; set; }
public HeadlineBarData ViewModel { get; set; }
public ChartWidget() {
WidgetType = WidgetType.HeadlineBar;
}
}
But the report will contain a collection of widgets, and that collection will need to be iterated over in the View in order to fetch the proper ViewComponents and supply them with the matching model that they expect. Unfortunately, it appears most collection types need to ensure type safety, and I need a way to make this a bit better. As it stands now, our IWidget object defines ViewModel as an object, and I don't think this is a good practice.

Custom model & client validation in MVC without data annotations

I have the below view models, which are used to represent a survey of questions, but they are structured into a more flattened grid to accommodate the default model binder.
// Main ViewModel for the Question View
public class SurveyRowList
{
...
public IList<SurveyRow> SurveyRowList { get; set; }
}
public class SurveyRow
{
public int QuestionId { get; set; }
public int? ParentQuestionId { get; set; }
public int SurveyId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string HelpInformation { get; set; }
public int RenderOrder { get; set; }
public SurveyRowType RowType { get; set; }
// Collection of the same answer control, 1 or more times
// for each line number
public IList<AnswerControl> AnswerControls { get; set; }
}
public enum SurveyRowType
{
QuestionGroup = 1,
Question = 2,
AnswerRow = 3
}
public class AnswerControl
{
public int Id { get; set; }
public int QuestionId { get; set; }
// a reference to the database record answer id
public int SurveyAnswerId { get; set; }
// control type of checkbox, dropdown, input, dropdown-additional-textbox, checkbox-group
public ControlType ControlType { get; set; }
// used to specify getting particular backing data for dropdown and checkbox-group
public ControlSpecificType ControlSpecificType { get; set; }
public string Description { get; set; }
public string HelpInformation { get; set; }
public int RenderOrder { get; set; }
public bool InLine { get; set; }
public int LineNumber { get; set; }
public AnswerControlValueType Value { get; set; }
}
public class AnswerControlValueType
{
// Default string backing value when possible
public string Value { get; set; }
// AnswerCheckBox
public bool CheckValue { get; set; }
// AnswerCheckBoxListModal
public string ModalName { get; set; }
// AnswerMultiSelectListValue
public int[] ListValues { get; set; }
// making the options list setter public so that this data can be re-attached after model binding
public IEnumerable<SelectListItem> ListOptions { get; set; }
// AnswerImageValue
public HttpPostedFileBase Image { get; set; }
// AnswerSelectListAdditionalValue
public string AdditionalInformation { get; set; }
}
Each SurveyRow is like a row of a table. Only the SurveyRowType.AnswerRow actually makes use of the AnswerControls list.
Example of their ordering when rendered by their type and order number can be seen in this image:
The image only shows a few simple examples, and there can be 1-10 lines per page to a max of 100, but I have also added a bit of explanation of some of the validation rules I would want to apply. There are more but these are just a few examples.
My problem is that I want to support this more complex validation but all the rules and error text are stored in a database, 1. because of user configuration, 2. because of existing localisation of the error text to support several languages.
I am looking for any suggestions that people might have to be able to support this.
I have seen things like Fluent Validation and I haven't delved too deep yet but so far I can't see any examples that would specifically not use Data Annotations on a model.. and also RequiredIf or DisabledIf or EnabledIf style validation rules that apply across a slightly more complex collection of objects.
I worked with MVC patterns in 2001 with servlets, and again in 2006, with a custom MVC framework implemented on top of ASP.NET, and looking at what people are doing nowadays makes me believe that most did not even care about looking at what MVC stands for, only that explain the models nonsense. A lot of developers working with ASP.net MVC, tend to bind the data that is coming from the client to models, but that is such a poor design. Models contain the data that should be forwarded to the template manager which is in most cases the Razor engine.
http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
So my advice is: don't link the data that you get from the client into the models.
Get the data from the client, do a search on the Request object if it needs to
Validate the data (fluentvalidation)
apply the business rules
create the models
forward the models to the template engine
Also stopping using those crazy useless annotations.
My question was related to how I can support validating this complex model. I have since looked more at Fluent Validation and that has everything I need to do custom rules for a complex model, i.e. checking values across collections of objects within my model.

Working with derived classes as JSON

I'm using Entity Framework 4.3 to generate my database from some classes. I have an Item class which has a collection of Deals that can be either free or discounted. My classes are modeled like so:
public class Item
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
//Other properties
public virtual ICollection<Deal> Deals { get; set; }
}
public abstract class Deal
{
//These properties are shared between various Deals
public int Id { get; set; }
public bool Monday { get; set; }
public bool Tuesday { get; set; }
public bool Wednesday { get; set; }
public bool Thursday { get; set; }
public bool Friday { get; set; }
public bool Saturday { get; set; }
public bool Sunday { get; set; }
public TimeSpan TimeFrom { get; set; }
public TimeSpan TimeTo { get; set; }
public int AgesFrom { get; set; }
public int AgesTo { get; set; }
public string Comments { get; set; }
public virtual ICollection<Vote> Votes { get; set; }
}
public class DiscountedDeal : Deal
{
public double PriceAfterDiscount { get; set; }
}
public class FreeDeal : Deal
{
//No properties needed here
}
Then in my onModelCreating
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<FreeDeal>().ToTable("FreeDeals");
modelBuilder.Entity<DiscountedDeal>().ToTable("DiscountedDeals");
}
I originally had a single Deal class with a boolean field to denote if it was free or not. The way I have it now seems a bit more normalized but naturally makes things more complicated.
At the front end I'm using ajax calls to send and retrieve this data but I'm not sure how treat the separate deals. If I retrieve an Item and it has 3 Deals, say 2 Free and 1 Discounted how can I deal with that? Should I have 2 Collections (1 for Free and 1 for Discounted) in my item class? Should I so go back to having one Deal class with a flag?
Without knowing the requirements, I would suggest changing the your model so that deals and and items live at the same level and you can simply apply deals to different items. As it is now you would have to create a seperate deal for every item if say you wanted to give a fifteen percent discount to items on wednesdays.
Also, I think that having a price set on the deal is a bad idea if you're letting an item have multiple deals... That forces you to have logic that determines the order of deal precedence etc. If keeping the database normailized is what you're after you I would go back to the single deal class and just give it a DealType which would be another class so that a DealTypes table is created. You could then keep the child classes and instead of having them hold the price you could give them and ApplyDeal method that would apply the deal to the item price.

Nested ViewModel Classes in asp.net MVC

I have four MVC model layer domain classes.
namespace MvcMobile.Models.BusinessObject
{
public class Speaker
{
public int SpeakerID { get; set; }
public string SpeakerName { get; set; }
}
public class Tag
{
public int TagID { get; set; }
public string TagName { get; set; }
}
public class Seminar
{
public string Seminar_Code { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Room { get; set; }
}
public class Seminar_Detail
{
public string Seminar_Code { get; set; }
public int SpeakerID { get; set; }
public int TagID { get; set; }
public string DateAndTime { get; set; }
}
}
I would like to make CRUD operation by using these classes. So I create two VeiwModel Classes.
namespace MvcMobile.ViewModel
{
public class Seminar_Root_ViewModel
{
public Seminar_Subsidiary_ViewModel Seminars { get; set; }
public List<Speaker> Speakers { get; set; }
public List<Tag> Tags { get; set; }
}
public class Seminar_Subsidiary_ViewModel
{
public Seminar Seminar { get; set; }
public List<Seminar_Detail> Seminar_Detail { get; set; }
}
}
For Controller layer, I consider that I will use Seminar_Root_ViewModel to make the whole CRUD operation processes.
What I would like to ask is that Is this proper way or correct way?
If you have more elegant way to make model layer and ViewModel layer, Please let me get suggestion.
Every suggestion will be appreciated.
[updated]
Let's assume that I make master-Detail form design.
Speaker and Tag are just look-up tables for dropdownlist or some controls like that.
Seminar is Master Data and Seminar_Detail will be Item Grid Data.
So As for this scenario, all of this classes are needed for this program.
Please let me know if my thinking is wrong.
The only thing I can see is if you are not going to re-use your Seminar_Subsidiary_ViewModel view model you could skip it.
If you are going to need those two properties Seminar and Seminar_Detail on another view or ajax call, it's perfectly fine to have that kind of separation.
Personally I'm not a huge fan of _ on class name, but that have nothing to do with the question.

Categories

Resources