Applying Required Attribute Validation on a Collection, IEnumerable - asp.net-mvc

How can I apply Required Attribute like validation to the following without knowing how many elements will be in each collection:
public class MyViewPageViewModel
{
[Required]
public List<int> IntCollection { get; set; }
[Required]
public Dictionary<int, string> IntAndStringAllValueCollection { get; set; }
[Required("Value")]
public Dictionary<int, string> IntAndStringValueValidationCollection { get; set; }
[Required("Name","HairColor")]
public List<Person> PersonNameValidationCollection { get; set; }
}
For IntCollection I want every element to be required. For IntAndStringAllValueCollection I want every Key and every Value to be required. For IntAndStringValueValidationCollection I do not want the Key to be required but I want the Value to be required.

Although I'd like to be able to do it as expressed above, one way to get around the problem is like so:
public class PageViewModel
{
public List<RequiredStartAndEndDateTuple> OnlineDates { get; set; }
}
public class RequiredStartAndEndDateTuple
{
public RequiredStartAndEndDateTuple() { }
public RequiredStartAndEndDateTuple(DateTime? startDate, DateTime? endDate)
{
OnlineStartDate = startDate;
OnlineEndDate = endDate;
}
[Required(ErrorMessage = "Start Date Required")]
public DateTime? OnlineStartDate { get; set; }
//-- Note, no attribute means end date not required
public DateTime? OnlineEndDate { get; set; }
}
And if you're interested in the Controller & View Bits, check out:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Specifically grab the project source code and check out the 'Sequential' page using the strongly typed helpers

Related

Sorting and pagination with many search fields

I followed this tutorial and tried to implement sorting, filtering and pagination in my MVC application. Generally it's OK - it works, but I don't like code which is the result of this - it's terrible, problematic and complicating.
Here is my model:
public class ProductOccurence
{
[Key]
public int ProductOccurenceId { get; set; }
public int ProductId { get; set; }
public int ShopId { get; set; }
public decimal ProductPrice { get; set; }
public DateTime ProductBuyDate { get; set; }
public bool IsPromotional { get; set; }
public virtual Product Product { get; set; }
public virtual Shop Shop { get; set; }
}
and ProductSearchModel class (ViewModel only for fields to search):
public class ProductOccurenceSearchModel
{
public string Description { get; set; }
public string ShopName { get; set; }
public decimal? PriceFrom { get; set; }
public decimal? PriceTo { get; set; }
public DateTime? BuyDateFrom { get; set; }
public DateTime? BuyDateTo { get; set; }
public bool? IsPromotional { get; set; }
}
also declaration of controller function:
public ViewResult Index(string sortOrder, ProductOccurenceSearchModel searchModel, string currentFilterDescription, string currentFilterShopName, decimal? currentFilterPriceFrom, decimal? currentFilterPriceTo, DateTime? currentFilterBuyDateFrom, DateTime? currentFilterBuyDateTo, bool? currentFilterIsPromotional, int? page)
as you can see, there is a lot of variables - also I need separate ViewBag for each field. In every place I need to refer to each variable, what is inelegant, illegible - and makes unnecessary redundant code.
In my view it looks like this:
Link for sorting column:
#Html.ActionLink("ID", "Index", new
{
sortOrder = ViewBag.IDSortParm,
currentFilterDescription = ViewBag.CurrentFilterDescription,
currentFilterShopName = ViewBag.CurrentFilterShopName,
currentFilterPriceFrom = ViewBag.CurrentFilterPriceFrom,
currentFilterPriceTo = ViewBag.CurrentFilterPriceTo,
currentFilterBuyDateFrom = ViewBag.CurrentFilterBuyDateFrom,
currentFilterBuyDateTo = ViewBag.CurrentFilterBuyDateTo,
currentFilterIsPromotional = ViewBag.CurrentFilterIsPromotional
})
and PagedList helper:
#Html.PagedListPager(Model.ProductOccurences, page => Url.Action("Index", new
{
page,
sortOrder = ViewBag.CurrentSort,
currentFilterDescription = ViewBag.CurrentFilterDescription,
currentFilterShopName = ViewBag.CurrentFilterShopName,
currentFilterPriceFrom = ViewBag.CurrentFilterPriceFrom,
currentFilterPriceTo = ViewBag.CurrentFilterPriceTo,
currentFilterBuyDateFrom = ViewBag.CurrentFilterBuyDateFrom,
currentFilterBuyDateTo = ViewBag.CurrentFilterBuyDateTo,
currentFilterIsPromotional = ViewBag.CurrentFilterIsPromotional
}))
This is needed to store the results while paging and sorting (parameters are transfered by URL).
I was looking for solutions, I read the tutorials, but never found a good solution for many search fields (only for one or two).
How can I make it simple and clean? For example through the transfer of all the values in one object or something like this. Thanks in advance!

Viewmodel set up Aspt.net MVC 6

I'm having trouble understanding how to implement a ViewModel in Asp.net MVC, I have the following tables:
Form
ID, Data
Report
ID, FormID, Owner, Category, Status, SubmissionDate
ReportValues
ID, ReportID, Title, Value
I'm looking for a way to display and edit Report and ReportValues in the one ViewModel where ReportValues.ReportID = Report.ID
ReportValues will have multiple entries that relate to a Report.
I have had a look at similiar questions on here and tried following a tutorial ( http://techfunda.com/howto/262/list-data-using-viewmodel ) and coming up empty handed.
If you need any more information let me know and thanks in advance for any replies!
Your View Model is nothing more than a class. You can solve this many ways, but here's an example.
Create your 3 classes like you normally would.
public class Form
{
public int Id { get; set; }
public string Data { get; set; }
}
public class ReportValues
{
public int Id { get; set; }
public int ReportId { get; set; }
public string Title { get; set; }
public string Value { get; set; }
}
public class Report
{
public int Id { get; set; }
public int FormId { get; set; }
public string Owner { get; set; }
public string Category { get; set; }
public string Status { get; set; }
public DateTime SubmissionDate { get; set; }
}
Then, create your ViewModel class to include the three above classes like this.
public class ReportViewModel
{
public Form Form { get; set; }
public ReportValues ReportValues { get; set; }
public Report Report { get; set; }
}
In your view you can access your three classes and their properties as you would in your controller. Model.Form.Id
Depending on your data types, ReportValues will likely be a property of Report, but that's entirely up to your data structure. You will need to populate the classes using whatever method you want (Entity Framework, ADO, etc.) before you can pass them to your view and use them.

How do I save several set of information on my model class in MVC?

I'm making a simple website where I'm storing some information that I get from an excel file into my models class and retrieving them from the html page. The following class is a class in my models:
public class ToxinInformation
{
public string cas_rn { get; set; }
public string critical_effect { get; set; }
public string point_of_departure { get; set; }
public string adi_tdi { get; set; }
public string intake { get; set; }
public string hazard_quotient { get; set; }
public string comment { get; set; }
public string tox_link { get; set; }
public string tox_link_decription { get; set; }
public string intake_link { get; set; }
public string intake_link_description { get; set; }
public IList<string> Links { get; set; }
}
And I use this code to set the information in my controller class and return the view:
(of course I would set information all the variables, not only the first one)
var model = new ToxinInformation
{
cas_rn = "lol"
};
return View(model);
So far I can easily set all my strings and my list and retrieve them on my html page, but what do I do if in some cases I need several instances of the class "ToxinInformation"? In some cases I have 2 or more set of data I'd like to save and show in HTML except for just one.
Any suggestions would be very helpful.
You should make a list and add instances of model to the list. Then you can use a DisplayFor or EditorFor template to show them all.
var models = new List<ToxinInformation>();
foreach(var dataBlob in YourDataStore)
{
var model = new ToxinInformation()
{
cas_rn = dataBlob.cas_rn // Not sure where your raw data is coming from.
}
models.add(model)
}
return View(models);

Appropriate way to set default values for ViewModel in MVC4?

I have a viewModel that contains the following:
public class CreateCardViewModel
{
[HiddenInput(DisplayValue = false)]
public int SetId { get; set; }
[Required]
public IList<Side> Sides { get; set; }
[Required]
public int Stage { get; set; }
[Required]
[DataType(DataType.Date)]
[HiddenInput(DisplayValue = false)]
public DateTime DateCreated { get; set; }
[Required]
public bool IsReady { get; set; }
}
The model is as follows:
public class Card
{
public virtual int CardId { get; set; }
// belongs to a Set
public virtual int SetId { get; set; }
public virtual Set Set { get; set; }
// has Sides
public virtual IList<Side> Sides { get; set; }
// is in a certain Stage
public virtual int Stage { get; set; }
// is ready to study
public virtual bool IsReady { get; set; }
public virtual DateTime DateCreated { get; set; }
}
How can I set a default value for DateCreated?
Would the method change if I want to insert a blank Side into Sides upon Card creation?
You could set defaults in the constructor:
public CreateCardViewModel()
{
DateCreated = DateTime.Now;
Sides = new List<Side> { new Side() };
}
Caveat: There is an issue with using DateTime.Now from a unit testing perspective. If you're unit testing your ViewModel creation and need to be able to verify that the created date is set to a known value, you can look at creating a separate concept for time, as detailed in Ayende's blog. You basically create a static func, SystemTime, that you can set to a known value in your tests. If you don't set it, it defaults to DateTime.Now:
public static class SystemTime
{
public static Func<DateTime> Now = () => DateTime.Now;
}
Your constructor code then becomes:
public CreateCardViewModel()
{
DateCreated = SystemTime.Now();
Sides = new List<Side> { new Side() };
}
If you need to actually set the time to a known value, you do this:
SystemTime.Now = () => new DateTime(2013, 2, 11, 17, 41, 12);
I agree on The SystemTime approach.
Although, I personally don't like setting the CreatedDate on the constructor, since there can be a short time lapse since you instantiate the object and when you persist it to the database. (And here I am assuming you definitely are)
You could make all your domain objects inherit from an interface like this one:
public interface ITimeStamped
{
DateTime DateCreated { get; set; }
}
And then on the Commit method int the Context class I would do something like this to set the date for all entities that implement the interface:
foreach (var entry in ChangeTracker.Entries<ITimeStamped>()
.Where(entry => entry.State == EntityState.Added))
{
entry.Entity.DateCreated = SystemTime.Now();
}
This way you're totally certain that the entity is stored with the correct DateTime when it was persisted on the database.

asp.net mvc3 Bind Exclude on properties does not work

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.

Resources