pondělí 11. října 2010

AttributeProviderAttribute rendered useless ... or maybe not?

OK, so I'm writing some ASP.Net MVC application, I've got some data model classes generated by Entity Framework (with a custom template and loads of attributes added to the properties) and of course for the views I've got some viewmodels. Nothing unusual right? Most of the properties of the viewmodels are of course based on the properties of the datamodel so I'd like to copy the attributes from the datamodel classes to the viewmodel classes so that instead of repeating the loads of attributes I could just point to the other property in the other class and have them copied.
Enter System.ComponentModel.AttributeProviderAttribute. The docs are rather bad, babbling something unrelated about some silly DataGridView.DataSource property, but nevertheless it looks like it might be the thing I'm looking for. Let's see ... so you can specify the type to get the attribute from as [AttributeProvider(typeof(Project.Models.Whatever)], you can also specify the type name as a string ("The name of the type to specify." per docs, with no example whatsoever) or you can specify the type name as string and the property name as string (again, no examples).

OK, I need to specify the property name, so I have to use the AttributeProviderAttribute(String, String) constructor.

public class Sumfin {
 [AttributeProvider("Project.Models.Whatever", "FullName"]
 public string Name {get;set;}

Nope, no chance. No error, but the attributes are not there. OK, let's see if I can get it to take the attributes from the type itself.
Nope. OK, let's try the other syntax ...
[AttributeProvider( typeof(Project.Models.Whatever)]
Hey, that works. But how the heck do I specify the property?? And why doesn't the string version of the type name work?

A few Google searches later ... I need what?!? An assembly qualified name of the type? What the fsck is that?

OK, typeof(Project.Models.Whatever).AssemblyQualifiedName returns the thing. Something like  "Project.Models.Whatever, DataModel, Version=, Culture=neutral, PublicKeyToken=null". Lovely. And
[AttributeProvider( typeof(Project.Models.Whatever).AssemblyQualifiedName, "FullName"] of course doesn't work: "An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type".

Thank you very much Microsoft! It would be too much work to provide a fourth constructor AttributeProviderAttribute(Type, String), right?

OK. The docs say that AttributeProviderAttribute class cannot be inherited, but what if I try??

public class BasedOnAttribute : AttributeProviderAttribute {
public BasedOnAttribute(Type type, string property)
: base(type.AssemblyQualifiedName, property) {

[BasedOn( typeof(Project.Models.Whatever), "FullName"]
public string Name {get;set;}

Build, run ... hey, it works and does what I wanted all along! What does the "This class cannot be inherited." in the AttributeProviderAttribute class mean then? Never mind. I got my cookie.

Žádné komentáře: