我们目前正在开发一个ASP.NET MVC应用程序,该应用程序大量使用基于属性的元数据来驱动JavaScript的生成。
以下是我们正在撰写的方法类型的示例:
function string GetJavascript<T>(string javascriptPresentationFunctionName,
string inputId,
T model)
{
return @"function updateFormInputs(value){
$('#" + inputId + @"_SelectedItemState').val(value);
$('#" + inputId + @"_Presentation').val(value);
}
function clearInputs(){
" + helper.ClearHiddenInputs<T>(model) + @"
updateFormInputs('');
}
function handleJson(json){
clearInputs();
" + helper.UpdateHiddenInputsWithJson<T>("json", model) + @"
updateFormInputs(" + javascriptPresentationFunctionName + @"());
" + model.GetCallBackFunctionForJavascript("json") + @"
}";
}
此方法生成一些样机,并将其移交给返回字符串的各种其他方法。然后将整个批次作为字符串返回并写入输出。
我的问题是:
1)除了使用大字符串块之外,还有更好的方法吗?
我们考虑过使用StringBuilder或Response Stream,但它看起来非常“吵”。使用string.format开始变得难以理解。
2)你会如何对这段代码进行单元测试?看起来有点业余,只是在字符串比较中查找字符串中的特定输出。
3)实际测试最终的JavaScript输出怎么样?
感谢您的投入!
答案 0 :(得分:2)
我们专门创建了一个库,用于将JavaScript以类似流畅的语法嵌入到我们的C#代码中,然后将其作为开源。
答案 1 :(得分:1)
我们在项目中也做了很多JS生成,我们正在使用StringBuilder来完成它。
StringBuilder sb = new StringBuilder();
sb.Append("some javascript stuff")
.Append("some more")
.AppendFormat("formatted stuff {0}", "here");
return sb.ToString();
它不漂亮,但没有解决方案。
关于测试,我们实际上并没有对生成的代码进行任何单元测试。在发布之前,人们会去测试所有功能,以确保它们按预期工作。
答案 2 :(得分:1)
如果您不关心超级演奏者表现,可以使用模板语言来生成javascript。
然后,对于单元测试,你只需用适当的绑定/变量填充模板,然后通过像Rhino这样的Javascript评估器或任何.NET等价物运行它,至少测试语法,如果不是实际的JS代码。< / p>
除此之外,我会认真质疑生成这样的Javascript的软件的设计。它看起来像你正在使用JQuery但直接引用$可能会导致一些问题。
如果生成Javascript的编译器是一回事(ala GWT),但我会尽可能地将您的客户端JS代码与.NET代码分开(更不用说您的.NET代码看起来像服务器端JS谈论混乱)。
这种将客户端垃圾与服务器分离的流行设计被称为SOFEA。我让你谷歌了。
答案 3 :(得分:1)
我通常会尝试为大部分/全部javascript代码创建单独的.js文件。通常我需要将常见的bahvior应用于由ASP控件或服务器端代码动态创建的许多元素,因此我可能无法将所有内容编码为.js文件。
我发现你想在服务器上生成javascript的主要原因是因为在页面呈现之前你不会知道元素的ID。因此,我尝试尽可能地压缩该依赖关系,以便尽可能少地生成javascript。例如,在传统的ASP.Net(不是MVC)中,如果我渲染一组表单,例如在示例中,每个表单都有多个字段,那么我可能会在后面的代码中有一些东西,例如:
protected void FormRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
Control form = e.Item.FindControl("MyForm");
ClientScript.RegisterStartupScript(this.GetType(), "prepareForm_" + form.ClientID, @"prepareForm('" + form.ClientID + "');", true);
}
单独的.js文件将包含prepareForm函数的定义,如下所示:
// define a formPresenter "class" that encapsulates the behavior for a given form
function formPresenter(formId) {
this.setFirstName = function(value) {
$("#" + formId + "_FirstName").val(value);
}
this.setLastName = function(value) {
$("#" + formId + "_LastName").val(value);
}
// create other functions to handle more complicated logic
// clear fields
this.clearInputs = function() {
this.setFirstName("");
this.setLastName("");
//...
}
// receive Json object
this.handleJson = function(json) {
this.clearInputs();
// populate fields with json object
this.setFirstName(json.FirstName);
this.setLastName(json.LastName);
//...
}
// "constructor" logic
}
function prepareForm(formId) {
// create a new formPresenter object and shove it onto the specified element as the "presenter"
document.getElementById(formId).presenter = new formPresenter(formId);
}
现在几乎所有的实际逻辑都在自己的.js文件中,这应该更容易维护。如果需要访问给定表单的formPresenter对象,则只需要获取formId参数引用的任何元素的引用并访问presenter变量:
"document.getElementById(" + form.ClientID + ").presenter.handleJson(json);"
注意:由于我一直在使用JQuery,我发现甚至不需要包含服务器生成的任何javascript。通常我可以通过查找特定的CSS类名称(或者那种效果)找到我需要的元素,并执行我需要的任何设置/初始化。