4

I am looking for an efficient way to automatically format data fields in an entity - ideally using attributes.

We need to generate a PDF file from the data model. We want to ensure consistency in the deliverable, so we're looking to apply some formatting rules to certain data fields (dates, phone numbers, zip codes, etc..). Of course, I could write custom attributes and formatting code, but I'd rather not re-invent the wheel. I see a lot of promise using DataAnnotations (especially the DisplayFormat attribute), but I can't seem to find any built-in classes that work with those attributes.

How do I do this in a non-UI (i.e. non-MVC) context?

Here's an example of what we're looking for:

public class MyDataModel
{
    [PhoneNumber]
    public string PhoneNumber { get; set; }

    public void FormatData()
    {
        //Invoke some .NET or other method changes the value of PhoneNumber into a desired format, i.e. (888)555-1234 based on its decorations.
    }
}

I am also open to solutions that create a "view" of the data rather than update the original object, that is:

MyDataModel formatted = original.FormatData();

Whatever requires the least amount of code is ideal.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dan McCann
  • 383
  • 3
  • 11

2 Answers2

2

You'll have to use reflection to read a type's property's attributes. This answer provides a few extension methods that should help. It's for an MVC question, but it will work outside of MVC as well:


public static T GetAttribute<T>(this MemberInfo member, bool isRequired)
    where T : Attribute
{
    var attribute = member.GetCustomAttributes(typeof(T), false).SingleOrDefault();

    if (attribute == null && isRequired)
    {
        throw new ArgumentException(
            string.Format(
                CultureInfo.InvariantCulture, 
                "The {0} attribute must be defined on member {1}", 
                typeof(T).Name, 
                member.Name));
    }

    return (T)attribute;
}

public static string GetPropertyDisplayName<T>(Expression<Func<T, object>> propertyExpression)
{
    var memberInfo = GetPropertyInformation(propertyExpression.Body);
    if (memberInfo == null)
    {
        throw new ArgumentException(
            "No property reference expression was found.",
            "propertyExpression");
    }

    var attr = memberInfo.GetAttribute<DisplayNameAttribute>(false);
    if (attr == null)
    {
        return memberInfo.Name;
    }

    return attr.DisplayName;
}

public static MemberInfo GetPropertyInformation(Expression propertyExpression)
{
    Debug.Assert(propertyExpression != null, "propertyExpression != null");
    MemberExpression memberExpr = propertyExpression as MemberExpression;
    if (memberExpr == null)
    {
        UnaryExpression unaryExpr = propertyExpression as UnaryExpression;
        if (unaryExpr != null && unaryExpr.NodeType == ExpressionType.Convert)
        {
            memberExpr = unaryExpr.Operand as MemberExpression;
        }
    }

    if (memberExpr != null && memberExpr.Member.MemberType == MemberTypes.Property)
    {
        return memberExpr.Member;
    }

    return null;
}

Usage would be:

string displayName = ReflectionExtensions.GetPropertyDisplayName<SomeClass>(i => i.SomeProperty);
Community
  • 1
  • 1
jrummell
  • 42,637
  • 17
  • 112
  • 171
  • Reflection would work, but I'm really looking for something built-in if possible. For example, there must be something built into the .NET framework to accomplish this as DynamicData seems to do it automatically, but I can't seem to locate the classes that are responsible for conversion. I would think they'd have exposed these useful classes publicly?? – Dan McCann Feb 13 '12 at 22:42
0

You can use a MaskedTextBox

MaskedTextBox mtb = new MaskedTextBox();
mtb.Mask = "(999) 000-0000";
inputString=Regex.Replace(inputString, @"\D+", "");
mtb.Text = inputString;

Then you check the text ...

string s = mtb.Text; //s = "(204) 867-5309"

You can do the same thing for zip codes, or whatever is a predictable format like that.

Maybe not super clean but it sure is quick and easy.

Edit: I added a regex to make sure only numbers are used as an input in case a a user used hyphens or parentheses on input.

Brad
  • 11,934
  • 4
  • 45
  • 73
  • 1
    What is MaskedTextBox? How does this help the OP outside of a web project? – jrummell Feb 13 '12 at 17:46
  • A MaskedTextBox is part of System.Windows.Forms. It applies whatever formatting style, i.e. mask, you set to it to the input text, which seems to be what the OP wants. It shouldn't have anything to do with a web project or not. – Brad Feb 13 '12 at 18:01