在 MVC Razor 中在 C# 和 Javascript 之间共享枚举 [英] Share enums between C# and Javascript in MVC Razor

查看:22
本文介绍了在 MVC Razor 中在 C# 和 Javascript 之间共享枚举的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经看到了关于将常量添加到 javascript 文件以便它可以与剃刀视图一起使用的问题的有用答案:MVC Razor 中 C# 和 Javascript 之间共享常量

除了定义枚举之外,我希望能够做同样的事情,但我不确定如何将 C# 枚举转换为 javascript 中的常量.

关闭 GetType(),似乎没有办法实际获取常量值.

解决方案

我之前使用的另一种方法是使用 t4 模板来完成此类工作.类似于 t4mvc 的工作方式,如果您知道如何使用它,它可能是一个非常强大的工具.

这个想法是在 t4template 中你爬过你的项目并寻找一个枚举,当它找到一个时,你会想要模板来转换它并基于 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" #><#@程序集名称=EnvDTE80"#>

再说一次,我不是专家,但您可以在 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;这个[名称] = val;这个[val] = 名字;this.__ids[val] = 名称;this.__descriptions[val] = name.replace(/ShowWithEllipses$/,"...").replace(/([az])([AZ])/g, "$1 $2").replace(/^s+/,"");返回这个;}window.Enum.prototype.describe = function(val) { return this.__descriptions[val] };

这里我只是在做一个简单的 javascript Enum 实现.不声称它是最好的.但是它就是这样啊.:)

<预><代码><#准备(这个);foreach(FindProjectItemsIn(CurrentProject.ProjectItems.Item("Models"))中的ProjectItem pi){DumpEnumerationsFrom(pi);}#>

然后我们进入模板的核心部分.基本上它在一个名为 Models 的文件夹中查找.并四处挖掘并试图找到它可以找到的任何枚举.当它这样做时,它会调用以下方法:

void DumpEnumerationsFrom(ProjectItem file) {var enumerations = new List();FindEnum(file.FileCodeModel.CodeElements, enumerations);if(enumerations.Count > 0) TT.WriteLine("//{0}",file.Name);foreach(CodeEnum enumerations in enumerations) {TT.Write("window.Enum.{0}=(new Enum())", enumeration.Name);foreach(枚举中的CodeElement ce.Children){var cv = ce 作为 CodeVariable;if(cv == null) 继续;TT.Write("
	.add("{0}", {1})", cv.Name, cv.InitExpression ?? "undefined");}TT.WriteLine(";
");}}

它将生成如下所示的内容:

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

因此生成的 JS 文件直接基于您的 c# 项目中的枚举.

虽然有一些限制.枚举必须位于项目中的文件中(不在引用的库中),至少使用此实现可能有更聪明的方法来做到这一点.每次更改枚举时,都必须重新运行模板(右键单击它并选择运行自定义工具").

但是有一些优点,就像我之前提到的,生成的文件只是一个普通的 js 文件,因此可以组合并通过缩小运行.因为它只是一个文件,所以它可以托管在 CDN 上,而且就像我之前提到的那样,不需要点击 MVC 堆栈来处理请求.

无论如何,我并不是说它对所有目的来说都是最好的主意,但在我看来它是一种未被充分利用的方法.希望这可能有助于说明问题并为您指明调查方向.

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

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.

Off GetType(), there doesn't seem to be a way of actually getting at the constant value.

解决方案

Another method I've used before is to use t4 templates to do this kind of work. Similar to the way that t4mvc works, which can be a very powerful tool if you know how to wield it.

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)

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.

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.

First, T4 templates are 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.

So lets dig in:

<#@ 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#.

<#@ 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.

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.

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, "$1 $2").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. :)

<#
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:

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("
	.add("{0}", {1})", cv.Name, cv.InitExpression ?? "undefined");
        }
        TT.WriteLine(";
");
    }
}

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.

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.

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.

这篇关于在 MVC Razor 中在 C# 和 Javascript 之间共享枚举的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆