About your host

Photo of your host - Charles Vallance Charles Vallance is a web developer with a slight case of OCD when it comes to nice clean standards compliant html and code.

Badges

twitter / cvallance
My articles have been featured in The Morning Brew - Daily .NET News and Views

Tag Cloud

more tags...
posted @ Thursday, August 06, 2009 8:16 PM

With the new release of ASP.NET MVC 2 CTP 1 there are a lot of cool new features that are driven by html attributes on your models. Read both The Gu’s and Phil Haack’s blog posts about the release to get the full low down.

I’m guessing that (like myself) a lot of people out there are using ORM’s to generate their models. Yeah? Thought so. Anyway, looking at that previous sentence, the key word is *generate*. You see, if you put property attributes in these generated files, they’re just going to be wiped each time you make a db schema change – far from ideal! ;-)

So where do you put these attributes?

Nope, you can’t put them in a partial class because C# and VB.NET don’t allow you to add attributes to properties defined in another partial class.

Enter the Buddy Class!

The Gu touched on buddy classes in his aforelinked1 post, but didn’t go into them in any detail – so I’m going to try and fill that void with this post.

Say we have a 'Customer' table (similar to The Gu's example) in our database and our orm generates a class like so:

public partial class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
    public string Country { get; set; }
}

Before we go any further (if you haven’t already) you should add a reference to System.ComponentModel.DataAnnotations.dll to your project – you’re gonna need it.

Next we create a partial class for the generated class and also create it’s buddy class.

The best way to explain this is with code, so here you go:

[MetadataType(typeof(Customer_Metadata))]
public partial class Customer
{
    //Custom model stuff here
}

public class Customer_Metadata
{
    [DisplayName("First name")]
    [Required(ErrorMessage = "First name is required")]
    public string FirstName { get; set; }

    [DisplayName("Last name")]
    [Required(ErrorMessage = "Last name is required")]
    public string LastName { get; set; }

    [Range(1, 120, ErrorMessage = "Invalid Age")]
    public int Age { get; set; }

    [Required(ErrorMessage = "Email is required")]
    [RegularExpression(@"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$")]
    public string Email { get; set; }

    [Required(ErrorMessage = "Country is required")]
    [UIHint("CountryDropDown")]
    public string Country { get; set; }
}

Savvy? Good, because that's really all there is to it! ;-)

1aforelinked - new word? © Charles Vallance 2009

EDIT: Making the buddy class a private inner class

As outlined below by Tyrone and Steve, it's probably best practice to have the buddy class as a private inner class.

E.g.

[MetadataType(typeof(Customer.Metadata))]
public partial class Customer
{
    //Custom model stuff here

    private sealed class Metadata
    {
        [DisplayName("First name")]
        [Required(ErrorMessage = "First name is required")]
        public string FirstName { get; set; }

        [DisplayName("Last name")]
        [Required(ErrorMessage = "Last name is required")]
        public string LastName { get; set; }

        [Range(1, 120, ErrorMessage = "Invalid Age")]
        public int Age { get; set; }

        [Required(ErrorMessage = "Email is required")]
        [RegularExpression(@"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$")]
        public string Email { get; set; }

        [Required(ErrorMessage = "Country is required")]
        [UIHint("CountryDropDown")]
        public string Country { get; set; }
    }
}

And then he said...

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by Tyrone
on 8/7/2009 5:17 AM
Probably should make the Customer_Metadata class a private inner class of your Customer class. I think that would work..but haven't tried it as yet.

# ASP.NET MVC 2 – Buddy Classes for your models - Charles Vallance

Gravatar
Posted by DotNetShoutout
on 8/7/2009 6:12 AM
Thank you for submitting this cool story - Trackback from DotNetShoutout

# ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by progg.ru
on 8/7/2009 7:35 PM
Thank you for submitting this cool story - Trackback from progg.ru

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by Steve
on 8/7/2009 10:00 PM
Inner class do work.

[MetadataType(typeof(Customer.Metadata))]
partial class Customer
{
private sealed class Metadata
{
// etc.
}
}

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by Juliën
on 8/8/2009 2:21 AM
Great article, Charles. Was wondering if DataAnnotations would work with Entity Framework generated models. Definitely will try your sample in a sandbox project.

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by Neil
on 8/8/2009 2:46 AM
This is nothing really new, or good for that matter. Ayende touched on this a while back ayende.com/.../...dy-classes-are-drowning-dry.aspx

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by Kieron
on 8/8/2009 3:25 AM
Excellent, was trying to crack that this-morning. Thanks!

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by Martin
on 8/8/2009 4:55 AM
I don't think Buddy Classes are new to MVC 2 ... I saw Elijah Manor do this in MVC1 at a presentation at CodeStock.

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by yemek tarifleri
on 8/8/2009 9:46 AM
Buddy class are works around of very nasty Attribute problem of .Net.
I don't understand why they do not fix .Net framework

# Daily tech links for .net and related technologies - August 7-10, 2009

Gravatar
Posted by Sanjeev Agarwal
on 8/9/2009 7:35 PM
Daily tech links for .net and related technologies - August 7-10, 2009 Web Development Best Free Website

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by charles
on 8/9/2009 8:30 PM
@Tyrone & @Steve - Cool, will have to give that a whirl. Will update the posting with your suggestions.

@Juliën - Yep, they will work with the Entity Framework

@Neil - No nothing new, pretty sure they were released with .NET 3.5 SP1. I wouldn't say that 'they aren't good', I would say that the need for them isn't good. IMHO, they are good because they are a great workaround to a problem.

@Martin - No buddy classes aren't new to MVC 2. But what is new to MVC 2 is the frameworks use of DataAnnotation attributes... which will require the use of buddy classes for generated models.

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by Kyle Bailey
on 8/16/2009 2:29 PM
why can I not get this to work? can you make your code dowloadedable?

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by Anthony Gatlin
on 8/25/2009 3:58 PM
On my current project, I originally generated the model through the Linq-to-Sql designer. After reading Scott Gu's post on the release of MVC V2 preview 1, I just went back and used SQLMetal to generate my map and class files and decorated the classes with the data annotation attributes. It seemed like less trouble to me than the buddy classes. I wonder if someone could lay out the pros and cons of using designer+partial classes+buddy classes+data annotation attributes versus sqlmetal+data annotation attributes.

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by John
on 9/15/2009 9:13 AM
For some reason I don't get the "DisplayName" attribute - VS gives me a compiler error.

Can you zip up an example project with the "DisplayName" attribute working?

# The Case for Partial Properties

Gravatar
on 9/15/2009 10:19 AM

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by EvanG
on 9/16/2009 11:24 PM
How would body classes be used in N-tier scenarios? Would they? Idealy I want to make these validations at the service layer or web layer, but I should not have reference to the Entities there...thanks.

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by Josh Einstein
on 11/3/2009 3:10 AM
Another thing that might be worth mentioning is the property types don't need to match the actual declarations at all. I usually declare all properties of the metadata class as "object" so I have one less thing to worry about keeping in sync.

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
Posted by Sosh
on 12/9/2009 11:49 PM
I don't really understand the point of buddy classes here - is 'so your orm wont wipe them when it generates the model' the only reason to use them? I didn't realise there were so many people generating their models automatically. Don't you have anything else in there you're worried about losing?!

# re: ASP.NET MVC 2 – Buddy Classes for your models

Gravatar
on 1/28/2010 6:49 AM
@@ EvanG

http://www.asp.net/(S(pdfrohu0ajmwt445fanvj2r3))/learn/mvc/tutorial-38-cs.aspx

Hope this will helps.

Ashraf.

And then I said...

Title *
Name *
Email
Url
Comment *  
Please add 8 and 5 and type the answer here: