Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting an Enum to display on client side

I'm having hard time understanding how to convert an Enum value to it's corresponding name. My model is as follows:

public class CatalogRule
{
  public int ID { get; set; }
  [Display(Name = "Catalog"), Required]
  public int CatalogID { get; set; }
  [Display(Name = "Item Rule"), Required]
  public ItemType ItemRule { get; set; }
  public string Items { get; set; }
  [Display(Name = "Price Rule"), Required]
  public PriceType PriceRule { get; set; }
  [Display(Name = "Value"), Column(TypeName = "MONEY")]
  public decimal PriceValue { get; set; }
  [Display(Name = "Exclusive?")]
  public bool Exclude { get; set; }
}

public enum ItemType
{
  Catalog,
  Category,
  Group,
  Item
}

public enum PriceType
{
  Catalog,
  Price_A,
  Price_B,
  Price_C
}

A sample result from .net API:

[
  {
    $id: "1",
    $type: "XYZ.CMgr.Models.CatalogRule, XYZ.CMgr",
    ID: 1,
    CatalogID: 501981,
    ItemRule: 0,
    Items: "198",
    PriceRule: 1,
    PriceValue: 0.5,
    Exclude: false
  },
  {
    $id: "2",
    $type: "XYZ.CMgr.Models.CatalogRule, XYZ.CMgr",
    ID: 2,
    CatalogID: 501981,
    ItemRule: 2,
    Items: "9899",
    PriceRule: 2,
    PriceValue: 10.45,
    Exclude: false
  }
]

So in this example, I need to get Catalog for results[0].ItemRule & Price A for results[0].PriceRule. How can I accomplish this in BreezeJS??

like image 804
Van Dame Avatar asked Mar 12 '13 12:03

Van Dame


2 Answers

This is easy to do in ASP.NET Web API, because it is an out-of-box feature in the default JSON serializer (Json.NET).

To see strings instead of enum numbers in JSON, just add an instance of StringEnumConverter to JSON serializer settings during app init:

var jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
jsonFormatter.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());

UPDATE: Yep, you right, this is not help with Breeze.js. Ok, you can anyway do a little magic to make enums work like strings (while new version with fix is not released).

Create a custom ContextProvider which updates all integer enum values in metadata to strings. Here it is:

public class StringEnumEFContextProvider<T> : EFContextProvider<T>
    where T : class, new()
{
    protected override string BuildJsonMetadata()
    {
        XDocument xDoc;
        if (Context is DbContext)
        {
            xDoc = GetCsdlFromDbContext(Context);
        }
        else
        {
            xDoc = GetCsdlFromObjectContext(Context);
        }

        var schemaNs = "http://schemas.microsoft.com/ado/2009/11/edm";

        foreach (var enumType in xDoc.Descendants(XName.Get("EnumType", schemaNs)))
        {
            foreach (var member in enumType.Elements(XName.Get("Member", schemaNs)))
            {
                member.Attribute("Value").Value = member.Attribute("Name").Value;
            }
        }

        return CsdlToJson(xDoc);
    }
}

And use it instead of EFContextProvider in your Web API controllers:

private EFContextProvider<BreezeSampleContext> _contextProvider =
        new StringEnumEFContextProvider<BreezeSampleContext>();

This works well for me with current Breeze.js version (1.1.3), although I haven't checked other scenarios, like validation...

UPDATE: To fix validation, change data type for enums in breeze.[min|debug].js, manually (DataType.fromEdmDataType function, dt = DataType.String; for enum) or replace default function during app init:

breeze.DataType.fromEdmDataType = function (typeName) {
    var dt = null;
    var parts = typeName.split(".");
    if (parts.length > 1) {
        var simpleName = parts[1];
        if (simpleName === "image") {
            // hack
            dt = DataType.Byte;
        } else if (parts.length == 2) {
            dt = DataType.fromName(simpleName);
            if (!dt) {
                if (simpleName === "DateTimeOffset") {
                    dt = DataType.DateTime;
                } else {
                    dt = DataType.Undefined;
                }
            }
        } else {
            // enum
            dt = DataType.String; // THIS IS A FIX!
        }
    }

    return dt;
};

Dirty, dirty hacks, I know... But that's the solution I found

like image 104
whyleee Avatar answered Oct 14 '22 04:10

whyleee


There will be a new release out in the next few days where we "change" breeze's enum behavior ( i.e. break existing code with regards to enums). In the new release enums are serialized and queried by their .NET names instead of as integers. I will post back here when the new release is out.

like image 24
Jay Traband Avatar answered Oct 14 '22 04:10

Jay Traband