Getting an Enum to display on client side
Asked Answered
P

2

9

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??

Pencil answered 12/3, 2013 at 12:11 Comment(0)
I
4

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.

Iz answered 13/3, 2013 at 18:58 Comment(3)
While investigating this issue, I found that although Enum metadata was present in the /Metadata API call, it was discarded on the client side by Breeze. Thanks for the update Jay.Pencil
Breeze v 1.2.1 was just released and enums are now queryable as strings and are materialized this way as well.Iz
Incidentally I updated a few minutes ago too... ;) This version solves the issue, Thanx...Pencil
A
7

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

Astonishing answered 12/3, 2013 at 22:48 Comment(4)
I am afraid that had no effect on the API return call. That may be because the Breeze controller handles the API calls & such...Pencil
@Van Dame, I updated the answer with solution for current Breeze.js versionAstonishing
Thanks for the fixes, but it seems this fix won't be necessary in a few days and I'd rather avoid any hacks... :)Pencil
the JsonFormatter details at the top of your answer was super helpful. Thanks!Molten
I
4

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.

Iz answered 13/3, 2013 at 18:58 Comment(3)
While investigating this issue, I found that although Enum metadata was present in the /Metadata API call, it was discarded on the client side by Breeze. Thanks for the update Jay.Pencil
Breeze v 1.2.1 was just released and enums are now queryable as strings and are materialized this way as well.Iz
Incidentally I updated a few minutes ago too... ;) This version solves the issue, Thanx...Pencil

© 2022 - 2024 — McMap. All rights reserved.