1

In my MVC5 application I have an enum class as shown below and with this approach I can pass the enum values i.e. US, UK instead of United States" from Controller to View. How can I pass and display enum description with the following approach? I tried many different solution method as C# String enums, etc. but none of them solved my problem. On the other hand, I do not want to use sealed class and it would be better for me a solution with enum class as shown below:


Enum:

public enum Country
{
    [Description("United States")]
    US = 1,
    [Description("United Kingdom")]
    UK = 2,
    [Description("New Zealand")]
    NewZealand = 3,
    [Description("France")]
    France = 4,
    [Description("Germany")]
    Germany = 5
}


Model:

public class VisitorViewModel
{
    [Key]
    public int VisitorID { get; set; }

    public Country Country { get ; set; }
    //code omitted for brevity
}


Controller:

public JsonResult Visitor_Read([DataSourceRequest] DataSourceRequest request)
{
    var result = db.Visitors.Select(m => new VisitorViewModel
    {
        VisitorID = m.VisitorID,
        Country = m.Country
        //code omitted for brevity
    })      
    var jsonResult = Json(result, JsonRequestBehavior.AllowGet);
    jsonResult.MaxJsonLength = int.MaxValue;
    return jsonResult;
}


View:

$(document).ready(function () {

    var grid = $("#visitorGrid").kendoGrid({            
        dataSource: {
            type: "json",
            transport: {
                read: {
                    url: "/Visitor/Visitor_Read",
                    dataType: "json",
                    cache: false
                }
            },
            schema: {
                model: {
                    fields: {
                        VisitorID: { type: 'number' },
                        Country : { type: 'string' }
                    }
                }
            }
        },
        columns:
        [   
            { field: "VisitorID", title: "Id" },
            { field: "Country ", title: "Country" }, 
        ]
    }).data("kendoGrid");   

});
Community
  • 1
  • 1
Jack
  • 1
  • 21
  • 118
  • 236
  • Why don't you use razor to create your grid, if you're using asp.net MVC? – ataravati Dec 15 '15 at 16:20
  • You can add additional getter `public string CountryName`, which return `Country.ToString()` – Gene R Dec 15 '15 at 16:26
  • @ataravati I use razor (the view page is cshtml). If you mean Kendo MVC, I used to it before but in this project I had to use Kendo Grid in javascript for some reason. On the other hand, does it make any sense to solve this problem? Because first of all I need to return string values composed of multiple words from Controller to View. Any idea at least about it? – Jack Dec 15 '15 at 20:06
  • @GeneR But I use EF Code First approach and I am not sure if adding new property to the related entity class will cause an extra column in the database. Should I use it as virtual? Could you post an example by changing my original code? – Jack Dec 15 '15 at 20:09
  • @Christof i am using EF reverse engineer code first, and generating `partial class` for model, and then creating same `partial class` for model custom properties – Gene R Dec 16 '15 at 07:05
  • @GeneR Why do not post an example by changing my original code? Any help pls? – Jack Dec 16 '15 at 08:03
  • @Christof sorry forgot to mention `NotMapped` attribute, posted an answer – Gene R Dec 16 '15 at 08:20

2 Answers2

4

You must set NotMapped attribute for custom property:

using System.ComponentModel.DataAnnotations.Schema;
public class VisitorViewModel
{
    [Key]
    public int VisitorID { get; set; }

    public Country Country { get; set; }

    [NotMapped]
    public string CountryName
    {
        get { return Country.GetDescription(); }
    }
}

and GetDescription() is next extension method:

public static string GetDescription(this Enum e)
{
    var field = e.ToString();
    var attribute = e.GetType().GetField(field).GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault();

    return attribute != null ? ((DescriptionAttribute)attribute).Description : field;
}
Gene R
  • 3,684
  • 2
  • 17
  • 27
  • 1
    Perfect and very simple... Thanks a lot Gene, now it works like a charm :) Voted+ – Jack Dec 16 '15 at 09:39
1

You will have to create method which will return description attribute. It can be some helper method, extension or whatever you want.

For example:

public class VisitorViewModel
{
    [Key]
    public int VisitorID { get; set; }

    public Country Country { get ; set; }
    //code omitted for brevity

    public  string GetDescription()
    {
        var type = typeof(Country);
        var memInfo = type.GetMember(this.Country.ToString());
        var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
        return ((DescriptionAttribute)attributes[0]).Description;
    }
}

so you can call it like

var result = db.Visitors.Select(m => new VisitorViewModel
{
    VisitorID = m.VisitorID,
    Country = m.GetDescription()
    //code omitted for brevity
})  

Or if it is better for you, create helper method which will be called similarly, but will be static ...

public class SomeHelperClass
{
    public static string GetDescription(VisitorViewModel model)
    {
        var type = typeof(Country);
        var memInfo = type.GetMember(model.Country.ToString());
        var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
        return ((DescriptionAttribute)attributes[0]).Description;
    }
}

so call will be looks like

SomeHelperClass.GetDescription(model);

EDIT I got one idea, maybe it is not exactly what you want, maybe it can help you. If you add property with country name you can use this approach also:

public class VisitorViewModel
{
    [Key]
    public int VisitorID { get; set; }

    public string CountryName { get; set; }

    private Country _country;
    public Country Country 
    { 
        get { return this._country; }
        set
        {
            this._country = value;
            this.CountryName = GetDescription(value);
        }
    }
    //code omitted for brevity

    private string GetDescription(Country country)
    {
        var type = typeof(Country);
        var memInfo = type.GetMember(country.ToString());
        var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
        return ((DescriptionAttribute)attributes[0]).Description;
    }
}

so if you will fill your model as you do

var result = db.Visitors.Select(m => new VisitorViewModel
{
    VisitorID = m.VisitorID,
    Country = m.Country
    //code omitted for brevity
})    

you will have automatically filled your CountryName property whcih can be use in kendo grid.

{ field: "CountryName", title: "Country" }, 
Ademar
  • 1,418
  • 1
  • 17
  • 27
  • Many thanks for your reply. I tried first and second methods but get the following error: For the 1st method I get "LINQ to Entities does not recognize the method 'System.String GetDescription()' method, and this method cannot be translated into a store expression." I have a look at workaround but did not solve problem. For the 2nd I get "The model backing the 'DbContext' context has changed since the database was created." error. I know it is not an error, but indicates that migrating and updating database will cause an extra colon (CountryName ) in the database that I do not want. – Jack Dec 16 '15 at 08:02
  • @Christof you can use NotMapped attribute for CountryName column. [link](http://www.entityframeworktutorial.net/code-first/notmapped-dataannotations-attribute-in-code-first.aspx) I have forgot on it .. – Ademar Dec 16 '15 at 08:27
  • Many thanks Ademar, but as Gene posted working code with "NotMapped" before, I selected his answer. But of course Voted+ your answer. Thanks a lot again :) – Jack Dec 16 '15 at 09:40