在 ASP.NET 中使用 JavaScript 模板
在我的职业生涯中,我多次遇到这个问题,但从未找到一个优雅的解决方案。想象一下您有一个简单的页面,其中有一个转发器。您可以通过数据绑定在服务器端填充该中继器。这太棒了,工作速度快并且能完成它应该做的事情。但现在您想要将分页器添加到该转发器,或者以其他方式更改输出。通过 Ajax 执行此操作是实现富客户端交互的首选方式。
因此,您创建了一个 Web 服务,以 JSON 形式为您提供数据,但现在您陷入困境......要么您必须编写复杂的客户端代码来查找每个中继器项目中需要修改的每个字段,要么您必须清除中继器的整个服务器端输出并从头开始构建新的 HTML,或者,我最近使用的方法是,获取第一个重复项目,清除其他所有内容并克隆第一个项目尽可能多根据需要调整其字段。
所有描述的方法都不是最佳的,因为无论如何,它们都需要在服务器端(即转发器中的模板)和客户端(用于显示 JSON 数据的 JavaScript)进行大量重复逻辑。必须有一种更好、更简单的方法来做到这一点。首先想到的是,不是从 Web 服务器返回 JSON,而是返回预填充中继器的 HTML。但对于类似的事情,我不妨使用 ASP.NET AJAX 更新面板。使用独立的网络服务,输出不会变小。
接下来我想到的是 JavaScript 模板。如果有某种方法可以在服务器端获取未处理的中继器模板,并将其转换为 JavaScript 模板,该模板可以在加载时嵌入到页面上,或者作为 Web 服务响应的一部分。但是,我找不到此类问题的任何现有解决方案。我自己也想不出一个简单的方法来做到这一点。有什么想法吗?
PS 在页面加载时将 JavaScript 模板渲染到客户端,并使用 JavaScript 填充它而不在服务器上渲染初始视图(没有中继器和数据绑定)是不可能的。我太在意表现了。
I ran into this problem multiple times in my career, and never was able to find a elegant solution for it. Imagine you have a simple page, that has a repeater. You populate that repeater on the server-side through the databinding. That's great, works fast and does what it's supposed to. But now you want to add paginator to that repeater, or otherwise change the output. Doing it through Ajax is a preferred way to enable rich client interaction.
So you create a web-service that serves you the data as JSON, but now you are stuck... Either you have to write complicated client-side code to find each field that you need to modify in each repeater-item, or you have to blow away the whole server-side output of the repeater and construct new HTML from the scratch, or, the method that I've been using lately, take the first repeated item, blow away everything else and clone the first item as many time as you need to and modify it's fields.
All of the described methods are not optimal, because no matter what, they require quite a bit of repeated logic on the server-side (i.e. template in repeater) and on the client-side (javascript to display JSON data). There's got to be a better, easier way to do this. First thing that comes to mind, is instead of returning JSON from the web-server, return HTML of the pre-populated repeater. But for something like that, I might as well use ASP.NET AJAX Update panel. The output isn't going to be any smaller with a stand-alone web-service.
Next thing that I thought of, is JavaScript templates. What if there would be some way to take unprocessed repeater template on the server-side, and convert it to JavaScript template that could be either embedded on the page at load, or served as part of the web-service response. However, I couldn't find any existing solutions for something like this. And I can't think of a simple way to do that myself. Any ideas?
P.S. Rendering JavaScript template to the client-side on page load, and using JavaScript to populate it without the initial view being rendered on the server (no repeater and databinding) is out of the question. I care too much about performance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,我不认为即使在第一次加载时使用带有 JSON 数据的客户端模板也会对性能产生不利影响,除非我们讨论的是具有不同外形尺寸的设备,例如手机等。
但是,如果您必须使用服务器端模板/渲染,那么为什么不让服务器返回中继器的 html。这可以通过将中继器逻辑放入不同的用户控件/页面并仅在 ajax 请求上处理该页面来完成。这根本不等于使用 UpdatePanel (如您所述) - UpdatePanel 发布具有更多请求大小的整个页面数据(包括视图状态)。响应大小也很大,因为它必须包含视图状态。同样在服务器端,使用 UpdatePanel 会导致加载带有状态数据和回发事件处理的完整控制树。仅发送必需的 html 是更好的方法,并且完全满足您的需求 - 唯一的问题是 html 的大小与 JSON 相比会更大。
最后,还有一些有趣的项目,例如 Script# - Script# 将 C# 代码转换为 java 脚本。您可以构建类似的东西(使用 script# 本身)将服务器端模板代码转换为等效的 JS 代码。类似的更可行的方法可以使用 T4 模板将技术无关的模板转换为服务器端代码(标记+代码或纯代码)和等效的 JS 代码。
Firstly, I don't believe that using client template with JSON data even on first load will adversely affect the performance unless we are talking about devices with different form factors such as phones etc.
However, if you must use server side templating/rendering then why not make server return the html for the repeater. This can be done by putting repeater logic into a different user control/page and processing only that page on ajax request. And this is not at all equivalent to using UpdatePanel (as stated by you) - UpdatePanel posts entire page data (including view-state) having more request size. The response size is also larges because it must contain the view-state. On server side also, use of UpdatePanel results in loading complete control tree with state data and post-back event processing. Sending only the requisite html is much better approach and will fit your needs perfectly - only issue is the html would be larger in size as compared to JSON.
Lastly, there are some interesting projects such as Script# - Script# converts C# code into java-script. You may build something similar (using script# itself) to convert the server side templating code into eqivalent JS code. More viable approach on similar lines could be use T4 templating to convert a technology-agnostic template into both server side code (markup + code or pure code) and equivalent JS-code.
在考虑了不同方法的所有优点和缺点之后,我停止了以下方法。我创建了一个自定义 ASP.NET 数据绑定控件,它可以呈现 HTML,但是,当使用查询字符串参数请求页面时,它将使用 Response.Clear() 和 Response.End() ,而不是仅仅进行标准呈现这两个命令之间根据查询字符串参数输出 JSON 版本的数据。此外,在页面的第一次呈现时,它还将使用反射输出 JavaScript 模板,以从控件的模板区域读取变量的名称。
这个方法效果很好,我所要做的就是将控件放在页面上,对其进行数据绑定,它就像一个真正的 AJAX 网格一样工作,支持分页、排序和过滤。但它确实有局限性。在控件的模板中,您只能指定变量,而不能指定表达式。否则反射无法将其转换为 JavaScript 变量。但我可以忍受这一点。
我考虑的其他可能性是一个单独的 Web 服务,它采用页面类型作为参数,并使用反射来获取数据绑定对象以及为网格创建模板。我还想编写我自己的更新面板版本,它不会使用视图状态并且仅发送页面的一部分。
After thinking about all pros and cons of different approaches, I stopped on the following method. I created a custom ASP.NET databound control, that can render HTML, however, when the page is requested with query string parameters, instead of just doing standard rendering, it will use Response.Clear() and Response.End() and in between of those two commands output JSON version of data based on the query string parameters. Also on the first rendering of the page, it will also output JavaScript template using reflections to read names of the variables from the control's template area.
This method works great, all I have to do, is drop my control on the page, data bind it, and it works as a true AJAX grid that supports pagination, sorting and filtering. However it does have limitation. In the control's template you can only specify variables, not expressions. Otherwise reflections can't convert it to a JavaScript variable. But I can live with that.
Other possibilities that I considered is a separate web-service that takes a type of the page as parameter and uses reflection to get data bound object as well as create template for the grid. I also though about writting my own version of update panel, that would not use view state and only send in part of the page.