Going mad now. I have a MVC solution that i've upgraded from MVC 1 to 2. It all works fine.... except the Validation!
Here's some code:
In the controller:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Web.UI;
using MF.Services.Authentication;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace MF.Controllers
{
//basic viewmodel
public class LogOnViewData
{
[Required]
public string UserName { get; set; }
[Required]
public string Password { get; set; }
}
[HandleError]
public class AccountController : Controller
{
[HttpPost]
public ActionResult LogOn(LogOnViewData lvd, string returnUrl)
{
if (ModelState.IsValid)
{
//do stuff - IsValid is always true
}
}
}
}
The ModelState is always valid. The model is being populated correctly however. Therefore, if I leave both username and password blank, and post the form the model state is still valid. Argh!
Extra info: using structure map for IoD. Previously, before upgrading to MVC 2 was using the MS data annotation library so had this in my global.asax.cs:
ModelBinders.Binders.DefaultBinder = new Microsoft.Web.Mvc.DataAnnotations.DataAnnotationsModelBinder();
Have removed that now.
I'm sure i'm doing something really basic and wrong. If someone could point it out that would be marvellous.
Cheers
Half way through the development of MVC2, they went from input validation to model validation, which should in all cases validate your object completely. Make sure you're using the latest version (RTM).
However, [Required] merely indicates the attribute must not be null. Unfortunately, String.Empty -which is the default for strings- is not null, so model validation will pass for empty strings.
See this post by Brad Wilson for important details.
As a solution, you could use the [RegularExpression("....")] to impose restrictions on the minimum string length and allowed characters.
Related
Trying to convert a partialview to to a List as well as pass in a variable, but I can't seem to get it to pass the variable. Included a snippet below, thanks for the help.
Here's what I want to do (but with a partial view, not an iframe.
<iframe src="/Episodes/Grid?seriesId=#Html.DisplayFor(model => model.SeriesID)"></iframe>
And here's how I'm trying to do it, but I can't get it to do both the conversion to a List and passing in the SeriesID variable at once.
#{
Html.RenderPartial("~/Views/Episodes/Grid.cshtml", new List<myA.Models.Episodes> { new myA.Models.Episodes() }; new { SeriesID = Model.SeriesID }););
}
As per adiga's suggestion, I created another model but I'm getting Internal server errors, see below.
Model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace myA.Models
{
public class Combined
{
public IEnumerable<myA.Models.Episodes> Episodes { get; set; }
public string SeriesID { get; set; }
}
}
but I get
'IEnumerable<Episodes>' does not contain a definition for 'Number' and no extension method 'Number' accepting a first argument of type 'IEnumerable<Episodes>' could be found (are you missing a using directive or an assembly reference?)
Solved my issue by inserting the required partial view using JQuery. So I didn't have to convert to a IEnum List and pass in the parameter as I passed it in using JQuery .load, similar idea to the iframe I originally posted but kinda cleaner.
<script>$('#episode-list').load('/Episodes/Grid?SeriesID=' + #Html.DisplayFor(model => model.SeriesID));</script>
I am currently building an MVC site using Entity Framework. I have created following class:
using System; using System.Collections.Generic;
using System.Linq; using System.Web;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
namespace .Models {
public class VehicleTableData
{
[NotMapped]
public Dictionary<string,string> StandardVehicleData { get; set; }
[NotMapped]
public Dictionary<string,string> AdditionalData { get; set; }
} }
However, I would like it to be ignored by Entity Framework as when I try to create a view with it I get the error that there is no valid key.
If you have the class defined in your DbContext with the following line of code:
public DbSet<VehicleTableData> VehicleTableDatas { get; set; }
This will cause Entity Framework to include the class. Once the above line is removed it will not be included.
You could also remove the [NotMapped] attributes as this would only apply to properties that you would not want saved to the database in a model included in your DbContext.
I've already read several SO questions about this topic, but honestly most of them have been way too complex for me. I'm very new to ASP.NET mvc.
I have a sample ASP.NET mvc 4 app that I created by following along with (and deviating just a bit from) the Movie database tutorial. It has the built-in account bits, the Entity Framework (which has turned out to be a pain any time I change anything) plus 2 models that I built myself based on the models from the tutorial:
1) Bug
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
namespace MasterDetailPractice.Models
{
public class Bug
{
public int BugID { get; set; }
public string BugTitle { get; set; }
public DateTime BugDate { get; set; }
public string BugStatus { get; set; }
[Column(TypeName = "ntext")]
[MaxLength]
public string BugDescription { get; set; }
}
public class BugDBContext : DbContext
{
public DbSet<Bug> Bugs { get; set; }
public DbSet<Comment> Comments { get; set; }
}
}
2) Comment
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
namespace MasterDetailPractice.Models
{
public class Comment
{
public int CommentID { get; set; }
public int BugID { get; set; }
public int UserID { get; set; }
public DateTime CommentDate { get; set; }
[Column(TypeName = "ntext")]
[MaxLength]
public string CommentText { get; set; }
}
}
When I run my app I'm able to go to /Project and get the standard Index view with the Add link, where I can add a Bug. Once added, I see the usual Edit/Details/Delete links.
When I run my app I'm also able to go to /Comment and get the standard Index view with the Add link, where I can add a Comment. Once added, I see the usual Edit/Details/Delete links.
Up to this point, I'm OK. The CRUD forms work, they just don't work together.
THE PROBLEM:
Currently, in order to make a Comment apply to a Bug, I have to actually input a BugID into the /Comment/Create form. And then the Comments are all only available at the /Comment/ route.
Instead, I need the following to happen:
The "Add Comment" form should automatically know what BugID to
save without a user having to input it.
A master-detail presentation of the data: The /Comment/Index view should appear at the bottom of the /Bug/Edit and/or Bug/Details page and show only the Comments related to the current Bug.
The "Add Comment" link should only appear from the /Bug/Edit or
/Bug/Details page, so Comments are never added without relating to a Bug.
It's kind of amazing that I haven't been able to figure this out myself, after spending 3 days poring over every Google result and SO post I can find on the topic. That said, here I am, hoping to learn the simplest possible implementation of this.
Do I need to post more code (the Controllers, for example, or the Views) in order for this question to be properly answerable?
Looking forward to getting the slow-learning train to start pulling out of the station...
Okay you need to do a few things.
First, create a new action method in your CommentController that looks like this.
public ActionResult Index(int bugId)
{
// Your logic to fetch all comments by BugID through EntityFramework or whatever
return View(data);
}
Now, in your Bug/Edit.cshtml or Bug/Details.cshtml pages add the following line to render those actions inline.
#Html.RenderAction("Index", "Comment", new { #bugId = Model.BugID }
In this case, you should be returning a BugModel back to your Bug/Edit.cshtml or Bug/Details.cshtml anyway as your model.
This should show you the form you need, with the BugID from the model being passed through.
For your last question, just put the "Add Comment" link within your Comment/Index.cshtml view since it will only appear anyway within the context of a bug. You will probably need to wrap this around a form that posts to your CommentController.
Here's a helpful link on working with forms in ASP.NET 4.
http://www.asp.net/mvc/tutorials/hands-on-labs/aspnet-mvc-4-helpers,-forms-and-validation
I'm learning asp.net mvc3 from w3schools and following that tutorial.http://w3schools.com/aspnet/mvc_models.asp In the section "ASP.NET MVC Models" I have created the model like this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
namespace MvcDemo.Models
{
public class MovieDB
{
public int ID { get; set; }
public string Title { get; set; }
public string Director { get; set; }
public DateTime Date { get; set; }
}
public class MovieDBContext : DbContext
{
public DbSet<MovieDB> Movies { get; set; }
}
}
Then I was going to add a controller according to the instructions.
In the Solution Explorer, right-click the Controllers folder, and select Add and Controller
Set controller name to MoviesController
Select template: Controller with read/write actions and views, using Entity Framework
Select model class: MovieDB (McvDemo.Models)
Select data context class: MovieDBContext (McvDemo.Models)*
Select views Razor (CSHTML)
Click Add
But the problem I have is that the drop down list doesn't show MovieDB (McvDemo.Models) in Model Class and Data Context Class to be selected. Can anyone please help me? Thanks.
You should just be able to recompile (Shift-Ctrl-B) and then try it again - it will be there. Otherwise you can always just declare it yourself at the top of a blank view, but that will not provide the scaffolding that the generator does:
#model MvcDemo.Models.MovieDB;
I recompiled but that did not fix the issue for me and yes I am doing the same thing and ran into the same exact issue. The problem for me was caused by visual web developer not being able to connect to my Movies database. I had to change the definition of my connectionString within web.config like this:
<add name="MovieDBContext"connectionString="Data Source=c:\sites\w3schools_demo\MvcDemo2\MvcDemo2\App_Data\Movies.sdf" providerName="System.Data.SqlServerCe.4.0"/>
If you are having this issue you will need to change the "Data Source" path to point to your Movies.sdf database file.
Hullo,
I am trying to update a website from ASP.NET MVC1 to ASP.NET MVC3 and from VS2008 to VS2010. So far everything seems to be going OK except the class FormCollection seems to be completely different across the two visual studios.
I've noticed that in VS2008 there is a FormCollection for version 1 and version 2 (presumably MVC1 and MVC2) and I can't see any big changes with them, but in VS2010 the only FormCollection class there is is a sealed class which is causing me grief as I have a class from before that inherits from FormCollection.
Anyone know if the FormCollection I used to know and love has moved or if I should just rewrite everything using the class that inherits it (a lot of stuff)?
Regards,
Harry
Worked my way around it now. Instead of inheriting FormCollection now it has it's own field 'form' which is a FormCollection instead and it's commands just act on that.
Edit:
People were asking for the codes, so here's the old class:
using System;
using System.Linq.Expressions;
using System.Web.Mvc;
using OpenProjects.Core;
namespace ProjectSupport.Web.Test
{
public class FormFor<TEntity> : FormCollection where TEntity : class
{
public FormFor<TEntity> Set<TReturn>(Expression<Func<TEntity, TReturn>> property, string value)
{
this[property.PropertyName()] = value;
return this;
}
}
}
And here's how it is now:
using System;
using System.Linq.Expressions;
using System.Web.Mvc;
using OpenProjects.Core;
namespace ProjectSupport.Web.Test
{
public class FormFor<TEntity> where TEntity : class
{
private FormCollection form;
public FormFor()
{
form = new FormCollection();
}
public FormFor<TEntity> Set<TResult>(Expression<Func<TEntity, TResult>> property, string value)
{
form.Add(property.PropertyName(), value);
return this;
}
public FormCollection ToForm()
{
return form;
}
}
}
For clarification on why this was being used rather than model binders, this was being used only for testing to easily mock up forms quickly and easily.