I am trying to create a ViewModel class. After I created class in "ViewModels" folder. My List type declaration are not recognized. My questions and code is below:
Are there some special way of creating ViewModel Classes?
Are ViewModels a methodology, rather than a feature in MVC3?
Can someone please tell me what I have missed thanks -P
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication8.ViewModels
{
//compiler does not recongize List class or SelectListitem
private List<SelectListItem> _products = new List<SelectListItem>();
//compiler does not recongize List class
public List<SelectListItem> products
{
get { return _products; }
}
}
Are there some special way of creating ViewModel Classes?
No, create them like creating any other class. The convention is to place them in the Models folder.
Are ViewModels a methodology, rather than a feature in MVC3?
Kind of. They're not a feature of the framework itself, but a recommendation to keep your View's simple and clean, and simplify model binding.
Can someone please tell me what I have missed thanks
Where's your class declaration?
namespace MvcApplication8.ViewModels
{
public class ThisIsTheClassNameAndMustGoFirst
create a new empty MVC 3 project, using Razor.
add a class definition under Models folder, i.e:
namespace MvcApplication1.Models
{
public class WhateverNameYouWantModel
{
public string Foo { get; set; }
public string Bar { get; set; }
}
}
right click on Controllers folder and add a new controller. the name must end with "Controller". don't bother checking option to add action methods. the controller would look like this:
using System.Web.Mvc;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers
{
public class HelloController : Controller
{
public ActionResult Index()
{
return View(new WhateverNameYouWantModel());
}
}
}
right click on the Index() signature above and choose "Add View". Make sure nothing is checked, the view name matches the action name "Index" and Razor is the engine. add the model type at the top:
#model MvcApplication1.Models.WhateverNameYouWantModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>Index</title>
</head>
<body>
<div>hello world!</div>
</body>
</html>
set the mvc project as your startup project, press F5, the browser will open to http://localhost:xxxx now you will need to point to http://localhost:xxxx/Hello/Index
In asp.net mvc names are everything between the views, actions and controllers. Its all convention, you don't need to stick to it but if you don't you are gonna have to do some extra plumbing.
Related
I am in the process of learning Entity Framework 6. I am looking for a tutorial explaining how to setup an ASP.NET Web Forms site (not ASP.NET MVC) and create basic CRUD pages. The only tutorials I can find are based on MVC and/or Console Apps rather than web application.
I am familiar with MVC but I do not want to use MVC for this project. Entity Framework 6 webforms only. All tutorials seem to be based on MVC or they step you through creating a Console App rather than a Web App.
An example of what I am running into is trying to add a simple gridview to a webform page.
It seems this should be a simple procedure but I have not found the code to make it work yet. I think I must be missing a simple step. The page has a gridview named Gridview1. In the code behind I am using:
namespace EFTestSchool.Models
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Student db = new Student();
GridView1.DataSource
}
}
}
When I add the .Models to the namespace, it says that the Gridview1 cannot be found. When I use the namespace as simply EFTestSchool, the Gridview1 is recognized but my line Student db = New Student() says Student cannot be found.
The name of my project is EFTestSchool. The name of my model is SchoolModel.
This is based on the standard School database used in some tutorials.
I must be missing something very simple that is preventing me from adding a simple grid to a webform page.
Any suggestions would be appreciated.
I can't think of why you would want to choose ASP.NET Web Forms over the more modern .Net alternatives that there are now. But assuming you have a good reason here is my answer.
Firstly here is a tutorial I found on Entity framework, crud and webforms. The entity framework code is a little out of date now. But if you understand the console app demos that you have mentioned you should be able to see from this how to apply it to webforms.
Going by your description I think what is happening is you are getting confused with how namespaces work. This code will hopefully help with that.
using AnotherNamespace; //this means the code on the page can access the public
//parts of AnotherNamespace
namespace MyNamespace
{
//code in here belongs to MyNamespace
}
Below is a simple example of what I think your code should look like.
First your dbcontext
using EFTestSchool.Models;
using System.Data.Entity;
namespace EFTestSchool.Data
{
public class MyDbContext: DbContext
{
public DbSet<Student> Students { get; set; }
public MyDbContext()
:base("{your connection string}")
{
Database.SetInitializer<MyDbContext>(null);
}
}
}
The student model
namespace EFTestSchool.Models
{
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
}
The Default.aspx file
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="EFTestSchool.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView ID="Gridview1" runat="server">
</asp:GridView>
</form>
</body>
</html>
The code behind, i.e. default.aspx.cs
using EFTestSchool.Data;
using System;
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;
using EFTestSchool.Models; //use this in your code to remove the student cannot be found compiler error
namespace EFTestSchool //needs to stay as this or it won't be able to recognise the controls in the aspx file
{
public partial class Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
using (var ctx = new MyDbContext())
{
var students = ctx.Students.ToList();
Gridview1.DataSource = students;
Gridview1.DataBind();
}
}
}
}
}
I have one project with EF and Code First approach and there using of Data Annotations was straight forward. Now I'm working with Database First and I see that using Data Annotations is more specific so I want to know the right steps to implement it.
The structure of my project that provides Data Access is this:
In ModelExtensions are all my files that I've created to add the Data Annotations to the DbContextModel.tt entities.
Here is the structure of one of my files in ModelExtensions:
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
namespace DataAccess.ModelExtensions
{
[MetadataType(typeof(MCS_ContentTypesMetaData))]
public partial class MCS_ContentTypes : BaseEntity
{
}
internal sealed class MCS_ContentTypesMetaData
{
[Required]
[StringLength(10)]
public string Name { get; set; }
}
}
I have several questions here. First - the namespace. Should it be like this namespace DataAccess.ModelExtensions or I have to remove the .ModelExtensions part. I was looking at a project using DB first and there the namespace was just DataAccess not sure why it is needed (if so). Also - Do I need to add some other references to the DbContextModel.tt entities? Now I use standard C# classes for this and then rename them to : public partial class MCS_ContentTypes : BaseEntity. Do I have to use a special approach for creating those to explicitly expose the connection between the entity and this file?
1) The namespace of your extension models must be the same as the namespace of EF auto-generated entity classes - If the namespace of DbContextModel.tt entity classes is DataAccess, you should set the namespace of your classes to DataAccess.
2) I doesn't get your question completely, however in this approach, names of entity classes and your classes must be the same.
The following example shows what it should be. Suppose that EF generates the following entity class for you:
namespace YourSolution
{
using System;
using System.Collections.Generic;
public partial class News
{
public int ID { get; set; }
public string Title { get; set; }
}
}
So, your partial classes should be like the following:
namespace YourSolution
{
[MetadataType(typeof(NewsAttribs))]
public partial class News
{
// leave it empty.
}
public class NewsAttribs
{
// Your attribs will come here.
[Display(Name = "News title")]
[Required(ErrorMessage = "Please enter the news title.")]
public string Title { get; set; }
// and other properties you want...
}
}
So, you doesn't need any : BaseEntity inheritance.
Why does T4MVC uses virtual for controller methods? Changing a
public ActionResult Details (string Id)
to:
public virtual ActionResult Details (string Id)
I have already seen other questions about T4MVC but didn't understand why.
Usually if a framework/library needs virtual methods (see also Nhibernate) it means somewhere/sometime your methods will be overridden.
So T4MVC marks your action methods as virtual because it's overrides them.
Lets take a simple controller:
public partial class HomeController : Controller
{
public virtual ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
}
If you go to the generated HomeController.generated.cs under the T4MVC.tt you will find a generated class which inherits from your controller and overrides your action method:
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class T4MVC_HomeController: MvcApplication8.Controllers.HomeController {
public T4MVC_HomeController() : base(Dummy.Instance) { }
public override System.Web.Mvc.ActionResult Index() {
var callInfo = new T4MVC_ActionResult(Area, Name, ActionNames.Index);
return callInfo;
}
}
I haven't used T4MVC so I don't know why and for what purpose T4MVC creates this generated class.
The only benefit I can see for making them virtual is to allow the developer to 'Go to Implementation/Definition' where The T4MVC helpers are used. This works because the Controller's type on the static Helper 'MVC' is the base controller type.
public static partial class MVC
{
public static HomeController Home = new T4MVC_HomeController();
}
So in the following snippet, Go to Definition on the Action Name will go to Base Implementation:
#Url.Action(MVC.Home.Index())
+1 David Ebbo for such an intuitive feature. I was mind blown when I realized this!
PS: this does not work for the parameterless actions added via the partial function, instead they navigate to the generated code, unfortunately.
I used LINQ to SQL to generate a dbml file which contains the database model for my database table. I want to use UIHint to let MVC present some fields as DropDownLists or Checkboxes in edit mode. But if I change the file, it will be lost if it's been regenerated. How should I solve that issue? I'm quite new to MVC and still learning. I've set up a controller with views for all CRUD elements, but now I'm finetuning and I'm running into this problem.
Since Linq-to-SQL auto-generates partial classes, you'll need to create a partial 'buddy class' where you will add your Data Annotations. Your buddy class mirrors portions of the auto-generated class that you need to modify. You tie them together with [MetadataType(typeof(BuddyClassName))] The partial buddy class and the auto-generated partial class will be merged together when you compile your project.
In an example given that:
Your namespace is "Project.Models"
Your Linq-To-Sql class is called "Products"
using System.ComponentModel.DataAnnotations;
namespace Project.Models
{
[MetadataType(typeof(ProductsMeta))]
public partial class Products
{
// You can extend the products class here if desired.
public class ProductsMeta
{
// This is a Linq-to-Sql Buddy Class
// In here you can add DataAnnotations to the auto-generated partial class
[Key]
public int ProductKey { get; set; }
[Display (Name = "Product Name")]
[Required(ErrorMessage = "Product Name Required")]
[StringLength(255, ErrorMessage = "Must be under 255 characters")]
public string ProductName { get; set; }
[UIHint("MultilineText")]
public string Description { get; set; }
}
}
}
These articles were very helpful:
ScottGu: ASP.NET MVC 2: Model Validation
How to: Validate Model Data Using DataAnnotations Attributes
Validating with Data Annotation Validators
If you are going to use the entities directly you should create a partial class and add your annotations there. This way when the model is regenerated you will not lose your annotations.
Howdy, I have what should be a simple question. I have a set of validations that use System.CompontentModel.DataAnnotations . I have some validations that are specific to certain view models, so I'm comfortable with having the validation code in the same file as my models (as in the default AccountModels.cs file that ships with MVC2). But I have some common validations that apply to several models as well (valid email address format for example). When I cut/paste that validation to the second model that needs it, of course I get a duplicate definition error because they're in the same namespace (projectName.Models). So I thought of removing the common validations to a separate class within the namespace, expecting that all of my view models would be able to access the validations from there. Unexpectedly, the validations are no longer accessible. I've verified that they are still in the same namespace, and they are all public. I wouldn't expect that I would have to have any specific reference to them (tried adding using statement for the same namespace, but that didn't resolve it, and via the add references dialog, a project can't reference itself (makes sense).
So any idea why public validations that have simply been moved to another file in the same namespace aren't visible to my models?
CommonValidations.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
namespace ProjectName.Models
{
public class CommonValidations
{
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public sealed class EmailFormatValidAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value != null)
{
var expression = #"^[a-zA-Z][\w\.-]*[a-zA-Z0-9]#[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$";
return Regex.IsMatch(value.ToString(), expression);
}
else
{
return false;
}
}
}
}
}
And here's the code that I want to use the validation from:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Growums.Models;
namespace ProjectName.Models
{
public class PrivacyModel
{
[Required(ErrorMessage="Required")]
[EmailFormatValid(ErrorMessage="Invalid Email")]
public string Email { get; set; }
}
}
You have declared EmailFormatValidAttribute as a subclass to CommonValidations. As such you need to reference it like CommonValidations.EmailFormatValidAttribute. Or alternatively move the EmailFormatValidAttribute class out of the CommonValidations class.
This should work:
[CommonValidations.EmailFormatValid(ErrorMessage="Invalid Email")]
public string Email { get; set; }
By the way, you can simplify your class as follows:
public class EmailFormatValidAttribute : RegularExpressionAttribute
{
public EmailFormatValidAttribute() :
base(#"^[a-zA-Z][\w\.-]*[a-zA-Z0-9]#[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$")
{}
}
Also, take a look at this: Data Annotations Extensions. It's a great DataAnnotations library which has already the most common validations included in it.