@Html.SomethingCool("containerName","jsCallbackFunction") <script type="javascript"> function jsCallbackFunction(e,i) { alert(e.target.name + ' / ' + i); } </script>
如您所见,JavaScript回调函数名称被传递给HtmlHelper扩展方法.这导致开发人员必须参考文档来找出jsCallbackFunction函数需要的参数.
我宁愿喜欢这样的东西:
@Html.SomethingCool("containerName",New SomethingCoolCallbackDelegate(Address Of jsCallbackFunction)) <OutputAsJavascript> Private Sub jsCallbackFunction(e,i) ' SOMETHING goes here. some kind of html dom calls or ??? End Sub
SomethingCoolCallbackDelegate将为目标函数提供代码合同.
那么编译器将在MVC页面上编译jsCallbackFunction作为javascript.
有没有像这样内置的.NET 4 / ASP.NET MVC 4 / Razor 2?还是可以实现类似的任何其他技术?
示例在VB中,但C#中的解决方案也是可以接受的.
澄清:
@gideon:注意jsCallbackFunction有两个参数e,而i.但是,HtmlHelper扩展方法只需要一个字符串(javascript回调函数的名称),并且不指示此函数可能需要哪些参数.我想解决的问题是双重问题.
>首先,缺少参数提示.传递代替“javascript回调名称”字符串的.NET代理类型将完成此操作.我可以接受其他解决方案来实现这一点.我知道XML的意见.他们不是一个真正的解决方案.
>第二,试图让页面程序员以单一语言工作.在javascript和VB(或js和C#)之间切换需要(至少对我来说)昂贵的上下文切换.我的大脑不能很快地过渡.让我在VB或C#中工作更有成效,更具成本效益.所以能够在.NET语言中编写一个函数,并将其编译成javascript,在ASP.NET MVC / razor视图的上下文中,这是我之后的内容.
@TyreeJackson:SomethingCool是一个HtmlHelper扩展方法,我会写,输出html和javascript. JavaScript输出的一部分需要调用一个用户(程序员)来进行一些决定.想想它类似于您为ajax调用提供的成功或失败功能.
解决方法
这是基础设施代码.您需要完成getArgumentLiteral和getConstantFromArgument函数来处理您提出的其他情况,但这是一个体面的起点.
public abstract class JavascriptFunction<TFunction,TDelegate> where TFunction : JavascriptFunction<TFunction,TDelegate>,new() { private static TFunction instance = new TFunction(); private static string name = typeof(TFunction).Name; private string functionBody; protected JavascriptFunction(string functionBody) { this.functionBody = functionBody; } public static string Call(Expression<Action<TDelegate>> func) { return instance.EmitFunctionCall(func); } public static string EmitFunction() { return "function " + name + "(" + extractParameterNames() + ")\r\n{\r\n " + instance.functionBody.Replace("\n","\n ") + "\r\n}\r\n"; } private string EmitFunctionCall(Expression<Action<TDelegate>> func) { return name + "(" + this.extractArgumentValues(((InvocationExpression) func.Body).Arguments) + ");"; } private string extractArgumentValues(System.Collections.ObjectModel.ReadOnlyCollection<Expression> arguments) { System.Text.StringBuilder returnString = new System.Text.StringBuilder(); string commaOrBlank = ""; foreach(var argument in arguments) { returnString.Append(commaOrBlank + this.getArgumentLiteral(argument)); commaOrBlank = ","; } return returnString.ToString(); } private string getArgumentLiteral(Expression argument) { if (argument.NodeType == ExpressionType.Constant) return this.getConstantFromArgument((ConstantExpression) argument); else return argument.ToString(); } private string getConstantFromArgument(ConstantExpression constantExpression) { if (constantExpression.Type == typeof(String)) return "'" + constantExpression.Value.ToString().Replace("'","\\'") + "'"; if (constantExpression.Type == typeof(Boolean)) return constantExpression.Value.ToString().ToLower(); return constantExpression.Value.ToString(); } private static string extractParameterNames() { System.Text.StringBuilder returnString = new System.Text.StringBuilder(); string commaOrBlank = ""; MethodInfo method = typeof(TDelegate).GetMethod("Invoke"); foreach (ParameterInfo param in method.GetParameters()) { returnString.Append(commaOrBlank + param.Name); commaOrBlank = ","; } return returnString.ToString(); } } public abstract class CoreJSFunction<TFunction,TDelegate> : JavascriptFunction<TFunction,TDelegate> where TFunction : CoreJSFunction<TFunction,new() { protected CoreJSFunction() : base(null) {} }
public class alert : CoreJSFunction<alert,alert.signature> { public delegate void signature(string message); }
public class hello : JavascriptFunction<hello,hello.signature> { public delegate void signature(string world,bool goodByeToo); public hello() : base(@"return 'Hello ' + world + (goodByeToo ? '. And good bye too!' : ''") {} } public class bye : JavascriptFunction<bye,bye.signature> { public delegate void signature(string friends,bool bestOfLuck); public bye() : base(@"return 'Bye ' + friends + (bestOfLuck ? '. And best of luck!' : ''") {} }
这是一个演示其使用的控制台应用程序:
public class TestJavascriptFunctions { static void Main() { // TODO: Get javascript functions to emit to the client side somehow instead of writing them to the console Console.WriteLine(hello.EmitFunction() + bye.EmitFunction()); // TODO: output calls to javascript function to the client side somehow instead of writing them to the console Console.WriteLine(hello.Call(func=>func("Earth",false))); Console.WriteLine(bye.Call(func=>func("Jane and John",true))); Console.WriteLine(alert.Call(func=>func("Hello World!"))); Console.ReadKey(); } }
这里是控制台应用程序的输出:
function hello(world,goodByeToo) { return 'Hello ' + world + (goodByeToo ? '. And good bye too!' : '' } function bye(friends,bestOfLuck) { return 'Bye ' + friends + (bestOfLuck ? '. And best of luck!' : '' } hello('Earth',false); bye('Jane and John',true); alert('Hello World!');
更新:
您可能还想查看JSIL.我不隶属于该项目,不能说它的稳定性,准确性和效力,但它听起来很有趣,可能可以帮助您.