在 MVC Razor 中在 C# 和 Javascript 之间共享枚举
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8345355/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Share enums between C# and Javascript in MVC Razor
提问by jaffa
I have seen this useful answer to a question for adding constants into a javascript file so it can be used with razor views: Share constants between C# and Javascript in MVC Razor
我已经看到了这个关于将常量添加到 javascript 文件以便它可以与剃刀视图一起使用的问题的有用答案:Share constants between C# and Javascript in MVC Razor
I'd like to be able to do the same except define enums, but I'm not sure how to convert the C# Enum into a constant in javascript.
除了定义枚举之外,我希望能够做同样的事情,但我不确定如何将 C# 枚举转换为 javascript 中的常量。
Off GetType(), there doesn't seem to be a way of actually getting at the constant value.
在 GetType() 之外,似乎没有办法实际获得常量值。
采纳答案by J. Holmes
Another method I've used before is to use t4 templates to do this kind of work. Similar to the way that t4mvcworks, which can be a very powerful tool if you know how to wield it.
我之前使用的另一种方法是使用 t4 模板来完成此类工作。类似于t4mvc 的工作方式,如果您知道如何使用它,它可能是一个非常强大的工具。
The idea is the in the t4template you crawl through your project and look for an enumerations, when it finds one, you'll want to template to transform it and spit out some javascript based on the C# code. The first time I worked with T4Templates through, it exploded my mind, and there aren't a lot of great resources for them, but they can be exceptional (see t4mvc)
这个想法是在 t4template 中你在你的项目中爬行并寻找一个枚举,当它找到一个时,你会想要模板来转换它并基于 C# 代码吐出一些 javascript。我第一次使用 T4Templates 时,它让我大吃一惊,没有很多很好的资源可供他们使用,但它们可能非常出色(请参阅 t4mvc)
The advantage of using templates over controller action used in the other question you linked to, is that the file generated by the t4 templating engine is the output is a regular js file and can be served/minified like any other JavaScript file, rather than requiring the overhead of the MVC stack to fulfill the request.
使用模板而不是您链接到的另一个问题中使用的控制器操作的优势在于,t4 模板引擎生成的文件是一个常规的 js 文件,可以像任何其他 JavaScript 文件一样提供/缩小,而不是要求MVC 堆栈完成请求的开销。
I could probably dig up an example if you are interested. I probably have no laying around in a repository somwhere.
如果您有兴趣,我可能会挖掘一个示例。我可能没有在某个存储库中闲逛。
Edit
编辑
So I dug around and found an example, I edited it a bit from its original form and didn't test it but you should get the idea. Its a little long, so I put it up as a github gist. But I'll highlight some important chunks here.
所以我四处挖掘并找到了一个例子,我从它的原始形式对其进行了一些编辑,并没有测试它,但你应该明白这个想法。它有点长,所以我把它作为github gist。但我会在这里强调一些重要的部分。
First, T4 templatesare a templating engine built into Visual Studio, the control blocks are written in C# (or VB if you want). I am by no stretch of the imagination an expert, and am not claiming to be one, but I'll share what I can. So these files, once in a visual studio project appear similar to other "code-behind" types of items, where you can expand the .tt item and see the generated template file behind it.
首先,T4 模板是一个内置于 Visual Studio 的模板引擎,控制块是用 C#(或 VB,如果需要)编写的。我绝对不是专家,也不自称是专家,但我会尽我所能分享。因此,这些文件一旦出现在 Visual Studio 项目中,就会类似于其他“代码隐藏”类型的项目,您可以在其中展开 .tt 项目并查看其背后生成的模板文件。
So lets dig in:
所以让我们深入研究:
<#@ template language="C#v3.5" debug="true" hostspecific="true" #>
<#@ template language="C#v3.5" debug="true" hostspecific="true" #>
The first line sets the language for the control blocks. As you can see I'm going to be using C#.
第一行设置控制块的语言。如您所见,我将使用 C#。
<#@ output extension=".js" #>
<#@ output extension=".js" #>
Next, i'm setting the extension of the generated file. In this case I'm saying that I want to generate a .js
file. So when I place this template into a solution, lets as enum.tt
, when I run the template it will create a file called enum.js
. You do have control over the file (or files) that are generated. For example, t4mvc has the option to be able to generate a bunch of different files (one for each controller) or generate a single t4mvc.cs
file.
接下来,我正在设置生成文件的扩展名。在这种情况下,我是说我想生成一个.js
文件。因此,当我将此模板放入解决方案时,让 as enum.tt
,当我运行该模板时,它将创建一个名为enum.js
. 您确实可以控制生成的文件(或多个文件)。例如,t4mvc 可以选择生成一堆不同的文件(每个控制器一个)或生成单个t4mvc.cs
文件。
Next you'll find a bunch of assemblies that I need to use. Some of the more interesting ones are the following:
接下来你会发现一堆我需要使用的程序集。一些更有趣的如下:
<#@ assembly name="EnvDTE" #>
<#@ assembly name="EnvDTE80" #>
Again, I'm not an expert, but you can find the documentation for these on the msdn site. These provide some core functionality to be able to access/manipulate the visual studio solution.
同样,我不是专家,但您可以在 msdn 站点上找到这些文档。这些提供了一些能够访问/操作 Visual Studio 解决方案的核心功能。
Then there are some fairly uninteresting imports. You'll notice that the control blocks are delimited by <# .. #>
(to be honest, I dont really remember the significance of the next character, its been a while.) Anything thats not wrapped in a control block will be written directly to the output stream.
然后是一些相当无趣的进口。您会注意到控制块由<# .. #>
(老实说,我真的不记得下一个字符的重要性,已经有一段时间了。)任何未包含在控制块中的内容都将直接写入输出流。
Which brings us to the start of actual file that will be written:
这将我们带到将要写入的实际文件的开始:
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, " ").replace(/^\s+/,"");
return this;
}
window.Enum.prototype.describe = function(val) { return this.__descriptions[val] };
Here i'm just making a trivial javascript Enum implementation. Not claiming it to be the best. But it is what it is. :)
在这里,我只是在做一个简单的 javascript Enum 实现。不声称它是最好的。但是它就是这样啊。:)
<#
Prepare(this);
foreach(ProjectItem pi in FindProjectItemsIn(CurrentProject.ProjectItems.Item("Models"))) {
DumpEnumerationsFrom(pi);
}
#>
Then we get to the meat of the template. Basically it looks in a folder called Models
. And digs around and tries to find any enums it can find. When it does, it calls the following method:
然后我们进入模板的核心部分。基本上它在一个名为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");
}
}
where it will generate something that looks like:
它将生成如下所示的内容:
window.Enum.TheNameOfTheEnum = (new Enum()).add("Value1",1).add("Value2",2);
So the resulting JS file is based directly on the enumerations in your c# project.
因此生成的 JS 文件直接基于您的 c# 项目中的枚举。
There are some limitations though. One the enumeration has to be in a file that is in your project (not in a referenced library), at least using this implementation there might be a more clever way to do it. Every time you change your enums, you have to re-run the template (right click on it and select "Run Custom Tool").
不过也有一些限制。枚举必须位于项目中的文件中(不在引用的库中),至少使用此实现可能有更聪明的方法来做到这一点。每次更改枚举时,都必须重新运行模板(右键单击它并选择“运行自定义工具”)。
But there are some advantages, like I mentioned before, the resulting file is just a plain js file, so can be combined and run through minification. Because its just a file, it can be hosted on a CDN, and like I mentioned before doesn't require a hit to the MVC stack to serve the request.
但是有一些优点,就像我之前提到的,生成的文件只是一个普通的 js 文件,因此可以组合并通过缩小运行。因为它只是一个文件,所以它可以托管在 CDN 上,而且就像我之前提到的那样,不需要点击 MVC 堆栈来为请求提供服务。
Anyway, I'm not saying its the best idea for all purposes, but it an under used approach in my opinion. Hopefully this may have helped shed some light and give you a direction of investigation.
无论如何,我并不是说它是所有目的的最佳主意,但在我看来这是一种未充分利用的方法。希望这可能有助于阐明一些问题并为您提供调查方向。
回答by valdetero
I took a mixture from several people's answers and wrote this HtmlHelper extension method:
我综合了几个人的回答,写了这个 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());
}
You can then call the method using Razor syntax like this:
@(Html.GetEnums<Common.Enums.DecisionStatusEnum>())
然后,您可以使用 Razor 语法调用该方法,如下所示:
@(Html.GetEnums<Common.Enums.DecisionStatusEnum>())
It will then spit out javascript like this:
然后它会像这样吐出javascript:
<script type="text/javascript">
if(!window.Enum) Enum = {};
Enum.WorkflowStatus = {"value__":0,"DataEntry":1,"SystemDecisionMade":2,"FinalDecisionMade":3,"ContractCreated":4,"Complete":5} ;
</script>
You can then use this in javascript like such:
然后你可以像这样在javascript中使用它:
if(value == Enum.DecisionStatusEnum.Complete)
Because of the check for property at the top (if(!window.Enum)
), this allows you to call it for multiple enums and it won't overwrite the globalEnum
variable, just appends to it.
由于检查顶部 ( if(!window.Enum)
) 的属性,这允许您为多个枚举调用它,并且它不会覆盖全局Enum
变量,只是附加到它。
回答by Josiah Ruddell
The conversion to Dictionary
for enum
is just slightly different.
转换为Dictionary
forenum
只是略有不同。
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 + ";");
}
You could take it a step farther and pass in the namespace of the enum
and use reflection to find the type. This would allow for a more generic action method.
您可以更进一步,传入 的命名空间enum
并使用反射来查找类型。这将允许更通用的操作方法。
ActionResult Enum(string enumType)