Подтвердить что ты не робот

Доля перечислений между С# и Javascript в MVC Razor

Я нашел этот полезный ответ на вопрос о добавлении констант в файл javascript, чтобы его можно было использовать с видами бритвы: Поделиться константами между С# и Javascript в MVC Razor

Я хотел бы иметь возможность делать то же самое, кроме определения перечислений, но я не уверен, как преобразовать С# Enum в константу в javascript.

Выключить GetType(), похоже, нет способа получить постоянное значение.

4b9b3361

Ответ 1

Другим методом, который я использовал ранее, является использование шаблонов t4 для выполнения такой работы. Подобно тому, как работает t4mvc, что может быть очень мощным инструментом, если вы знаете, как его использовать.

Идея заключается в том, что в t4template вы просматриваете свой проект и просматриваете перечисления, когда он находит его, вы захотите создать шаблон для его преобразования и выплюнуть некоторый javascript на основе кода С#. В первый раз, когда я работал с T4Templates, я взорвал свой разум, и для них не так много больших ресурсов, но они могут быть исключительными (см. T4mvc)

Преимущество использования шаблонов над действием контроллера, используемое в другом вопросе, с которым вы связаны, заключается в том, что файл, сгенерированный механизмом templating t4, является выходным файлом обычного js и может быть подан/уменьшен как любой другой файл JavaScript, вместо того, чтобы требовать накладных расходов на стек MVC для выполнения запроса.

Возможно, я мог бы выкопать пример, если вам интересно. У меня, вероятно, нет места в хранилище где-то.

Изменить

Итак, я откопался и нашел пример, немного отредактировал его в оригинальной форме и не тестировал, но вы должны получить эту идею. Его немного длиннее, поэтому я поставил его как github gist. Но я остановлюсь на некоторых важных кусках.

Во-первых, T4 templates - это шаблонный движок, встроенный в Visual Studio, блоки управления записываются на С# (или VB, если хотите). Я не являюсь экспертом и не претендую на то, чтобы быть одним, но я поделюсь тем, что могу. Таким образом, эти файлы, однажды в проекте с визуальной студией, похожи на другие элементы типа "code-behind", где вы можете развернуть элемент .tt и увидеть за ним сгенерированный файл шаблона.

Итак, давайте заглянем в:

<#@ template language="C#v3.5" debug="true" hostspecific="true" #>

Первая строка задает язык для блоков управления. Как вы можете видеть, я собираюсь использовать С#.

<#@ output extension=".js" #>

Далее, я устанавливаю расширение сгенерированного файла. В этом случае я говорю, что хочу сгенерировать файл .js. Поэтому, когда я помещаю этот шаблон в решение, давайте в качестве enum.tt, когда я запустил шаблон, он создаст файл с именем enum.js. У вас есть контроль над созданным файлом (или файлами). Например, t4mvc имеет возможность генерировать кучу разных файлов (по одному для каждого контроллера) или генерировать один файл t4mvc.cs.

Затем вы найдете кучу сборок, которые мне нужно использовать. Вот некоторые из наиболее интересных из них:

<#@ assembly name="EnvDTE" #>
<#@ assembly name="EnvDTE80" #> 

Опять же, я не эксперт, но вы можете найти документацию для них на сайте msdn. Они обеспечивают некоторые основные функциональные возможности, позволяющие получать доступ к визуальному студийному решению/манипулировать ими.

Тогда есть довольно неинтересный импорт. Вы заметите, что блоки управления разделены на <# .. #> (честно говоря, я действительно не помню значения следующего символа, это было время.) Все, что не было завершено в блоке управления, будет записано непосредственно в выходной поток.

Что приводит нас к началу фактического файла, который будет записан:

window.Enum = function() {
    this.__descriptions = [];
    this.__ids = []
    this.__last_value = 0;
}

window.Enum.prototype.add = function(name, val) {
    if(val == undefined) val = ++this.__last_value;
    this[name] = val;
    this[val] = name;
    this.__ids[val] = name;
    this.__descriptions[val] = name.replace(/ShowWithEllipses$/,"...").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^\s+/,"");
    return this;
}

window.Enum.prototype.describe = function(val) { return this.__descriptions[val] };

Здесь я просто делаю тривиальную реализацию enum javascript Enum. Не претендовать на то, чтобы быть лучшим. Но что есть, то есть.:)

<#
Prepare(this);
foreach(ProjectItem pi in FindProjectItemsIn(CurrentProject.ProjectItems.Item("Models"))) {
    DumpEnumerationsFrom(pi);
}
#>

Затем мы переходим к мясу шаблона. В основном он выглядит в папке с именем Models. И копается и пытается найти любые перечисления, которые он может найти. Когда это произойдет, он вызывает следующий метод:

void DumpEnumerationsFrom(ProjectItem file) {
    var enumerations = new List<CodeEnum>();
    FindEnum(file.FileCodeModel.CodeElements, enumerations);

    if(enumerations.Count > 0) TT.WriteLine("// {0}",file.Name);

    foreach(CodeEnum enumeration in enumerations) {
        TT.Write("window.Enum.{0}=(new Enum())", enumeration.Name);
        foreach(CodeElement ce in enumeration.Children) {
            var cv = ce as CodeVariable;
            if(cv == null) continue;
            TT.Write("\r\n\t.add(\"{0}\", {1})", cv.Name, cv.InitExpression ?? "undefined");
        }
        TT.WriteLine(";\r\n");
    }
}

где он будет генерировать что-то похожее:

window.Enum.TheNameOfTheEnum = (new Enum()).add("Value1",1).add("Value2",2);

Таким образом, полученный JS файл основывается непосредственно на перечислениях в вашем проекте С#.

Однако есть некоторые ограничения. Одно перечисление должно быть в файле, который находится в вашем проекте (не в справочной библиотеке), по крайней мере, используя эту реализацию, может быть более умный способ сделать это. Каждый раз, когда вы меняете свои перечисления, вам нужно повторно запустить шаблон (щелкните его правой кнопкой мыши и выберите "Запустить пользовательский инструмент" ).

Но есть некоторые преимущества, как я уже упоминал ранее, результирующий файл - это просто простой js файл, поэтому его можно комбинировать и запускать с помощью мини-программирования. Поскольку его просто файл, он может быть размещен на CDN, и, как я уже упоминал ранее, не требует удара в стек MVC для обслуживания запроса.

Во всяком случае, я не говорю, что это лучшая идея для всех целей, но это, по моему мнению, под используемым подходом. Надеюсь, это могло помочь пролить свет и дать вам направление расследования.

Ответ 2

Я взял смесь из нескольких ответов и написал этот метод расширения HtmlHelper:

    public static HtmlString GetEnums<T>(this HtmlHelper helper) where T : struct
    {
        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        sb.AppendLine("<script type=\"text/javascript\">");
        sb.AppendLine("if(!window.Enum) Enum = {};");
        var enumeration = Activator.CreateInstance(typeof(T));
        var enums = typeof(T).GetFields().ToDictionary(x => x.Name, x => x.GetValue(enumeration));
        sb.AppendLine("Enum." + typeof(T).Name + " = " + System.Web.Helpers.Json.Encode(enums) + " ;");
        sb.AppendLine("</script>");
        return new HtmlString(sb.ToString());
    }

Затем вы можете вызвать метод с использованием синтаксиса Razor следующим образом: @(Html.GetEnums<Common.Enums.DecisionStatusEnum>())

Затем он выплюнет javascript следующим образом:

<script type="text/javascript">
    if(!window.Enum) Enum = {};
    Enum.WorkflowStatus = {"value__":0,"DataEntry":1,"SystemDecisionMade":2,"FinalDecisionMade":3,"ContractCreated":4,"Complete":5} ;
</script>


Затем вы можете использовать это в javascript, например:

if(value == Enum.DecisionStatusEnum.Complete)

Из-за проверки свойства наверху (if(!window.Enum)) это позволяет вам вызывать его для нескольких перечислений и не будет перезаписывать переменную global Enum, просто добавляется к он.

Ответ 3

Преобразование в Dictionary для enum немного отличается.

public ActionResult DayOfWeekEnum()
{
    var enumType = typeof(DayOfWeek);
    var enumDictionary = enumType
        .GetFields()
        .Where(x => x.IsLiteral)
        .ToDictionary(x => x.Name, x => (int)Enum.Parse(enumType, x.Name));
    var json = new JavaScriptSerializer().Serialize(enumDictionary);
    return JavaScript("var DayOfWeek = " + json + ";");
}

Вы можете сделать шаг дальше и пройти в пространстве имен enum и использовать отражение, чтобы найти тип. Это позволит использовать более общий метод действий.

ActionResult Enum(string enumType)