jaf*_*ffa 13 javascript razor asp.net-mvc-3
我已经看到了将常量添加到javascript文件中的问题的有用答案,因此它可以与razor视图一起使用:在MVC Razor中共享C#和Javascript之间的常量
我希望能够做同样的事情,除了定义枚举,但我不知道如何将C#Enum转换为javascript中的常量.
关闭GetType(),似乎没有办法实际获得常量值.
val*_*ero 11
我从几个人的答案中得到了一个混合物并编写了这个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());
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用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>
Run Code Online (Sandbox Code Playgroud)
然后你可以在这样的javascript中使用它:
if(value == Enum.DecisionStatusEnum.Complete)
Run Code Online (Sandbox Code Playgroud)
由于top(if(!window.Enum))的属性检查,这允许您为多个枚举调用它,它不会覆盖全局 Enum变量,只是附加到它.
转换为Dictionaryfor 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 + ";");
}
Run Code Online (Sandbox Code Playgroud)
您可以更进一步并传入命名空间enum并使用反射来查找类型.这将允许更通用的操作方法.
ActionResult Enum(string enumType)
Run Code Online (Sandbox Code Playgroud)
我之前使用的另一种方法是使用t4模板来完成这种工作.类似于t4mvc的工作方式,如果你知道如何使用它,它可以是一个非常强大的工具.
这个想法是在t4模板中你爬行你的项目并寻找一个枚举,当它找到一个时,你会想要模板来转换它并根据C#代码吐出一些javascript.我第一次使用T4Templates时,它突然爆发了,并没有很多很好的资源,但它们可以是特殊的(参见t4mvc)
在您链接到的另一个问题中使用模板而不是控制器操作的优点是,t4模板引擎生成的文件是输出是常规js文件,可以像任何其他JavaScript文件一样提供/缩小,而不是要求MVC堆栈的开销以满足请求.
如果你有兴趣,我可能会挖掘一个例子.我可能没有在存储库中存放过.
编辑
所以我挖了一个例子,我从它的原始形式编辑了一下,并没有测试它,但你应该得到这个想法.它有点长,所以我把它作为一个github要点.但我会在这里强调一些重要的块.
首先,T4模板是Visual Studio内置的模板引擎,控制块是用C#编写的(如果需要,可以用VB编写).我不是想象中的专家,也不是自称是一个人,但我会分享我能做到的.因此,这些文件在Visual Studio项目中显示类似于其他"代码隐藏"类型的项目,您可以在其中展开.tt项目并查看其后面生成的模板文件.
所以让我们深入研究:
<#@ template language="C#v3.5" debug="true" hostspecific="true" #>
第一行设置控制块的语言.如你所见,我将使用C#.
<#@ output extension=".js" #>
接下来,我正在设置生成的文件的扩展名.在这种情况下,我说我想生成一个.js文件.因此,当我将此模板放入解决方案enum.tt时,当我运行模板时,它将创建一个名为的文件enum.js.您可以控制生成的文件(或多个文件).例如,t4mvc可以选择生成一堆不同的文件(每个控制器一个)或生成一个t4mvc.cs文件.
接下来,您将找到我需要使用的一堆程序集.一些更有趣的是以下内容:
<#@ assembly name="EnvDTE" #>
<#@ assembly name="EnvDTE80" #>
Run Code Online (Sandbox Code Playgroud)
同样,我不是专家,但您可以在msdn网站上找到这些文档.这些提供了一些核心功能,可以访问/操作visual studio解决方案.
然后有一些相当无趣的进口.你会注意到控制块是由<# .. #>(或者说,我真的不记得下一个字符的重要性,它已经有一段时间了).任何没有包含在控制块中的东西都将直接写入输出流.
这将我们带到将要编写的实际文件的开头:
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] };
Run Code Online (Sandbox Code Playgroud)
在这里,我只是做一个简单的JavaScript Enum实现.没有声称它是最好的.但是它就是这样啊.:)
<#
Prepare(this);
foreach(ProjectItem pi in FindProjectItemsIn(CurrentProject.ProjectItems.Item("Models"))) {
DumpEnumerationsFrom(pi);
}
#>
Run Code Online (Sandbox Code Playgroud)
然后我们得到了模板的内容.基本上它看起来在一个名为的文件夹中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");
}
}
Run Code Online (Sandbox Code Playgroud)
它会产生如下所示的东西:
window.Enum.TheNameOfTheEnum = (new Enum()).add("Value1",1).add("Value2",2);
Run Code Online (Sandbox Code Playgroud)
因此生成的JS文件直接基于c#项目中的枚举.
但是有一些限制.一个枚举必须位于项目中的文件中(不在引用的库中),至少使用此实现可能有更聪明的方法来执行它.每次更改枚举时,都必须重新运行模板(右键单击它并选择"运行自定义工具").
但是有一些优点,就像我之前提到的那样,生成的文件只是一个简单的js文件,因此可以组合并运行缩小.因为它只是一个文件,它可以托管在CDN上,就像我之前提到的那样,不需要命中MVC堆栈来提供请求.
无论如何,我并不是说它是出于各种目的的最好的想法,但在我看来它是一种未被充分利用的方法.希望这可能有助于提供一些启示,并为您提供调查方向.
| 归档时间: |
|
| 查看次数: |
10864 次 |
| 最近记录: |