我正在开发一个使用ASP.NET渲染HTML5的开源项目。你可以看一下:http://asphtml5.codeplex.com/
现在我有一个问题,更新面板张贴回来的输入值,有类型以外的"文本"。您可能知道,HTML 5引入了几种输入类型,例如"number"、"tel"、"search"等。现在,如果我渲染这样的控件,在正常情况下一切都很好,但如果我把它们放在一个UpdatePanel中,没有值将被返回,值将被重置。
下面是一小段产生相同错误的代码: <asp:UpdatePanel runat="server" ID="UP">
<ContentTemplate>
<p>
Enter A Number:
<asp:TextBox runat="server" ID="Number2" type="number" />
</p>
<asp:Button Text="Submit" runat="server" ID="BtnSubmit" OnClick="BtnSubmit_Click" />
<p>
You entered :
<asp:Label Text="" ID="LblValue" runat="server" />
</p>
</ContentTemplate>
</asp:UpdatePanel>
如果你在一个支持html 5的浏览器上测试这段代码,让我们说Chrome作为一个例子,将显示一个数值上下字段。但是如果你点击提交按钮,它会丢失你输入的值。
下面是事件处理程序的代码:
protected void BtnSubmit_Click(object sender, EventArgs e)
{
LblValue.Text = Number2.Text;
}
我已经尝试过阅读UpdatePanel, ScriptManager和ScriptManagerProxy类代码,没有发现任何东西。
我想我可能需要创建我自己的UpdatePanel和/或ScriptManager类使用。
谁能帮我,告诉我在哪里检查?
有趣的是,ASP。. NET 4.0 AJAX框架似乎意识到HTML 5的输入类型(见代码),但正如@TimSchmelter指出的,这被微软确认为一个bug。
这可以为调试行为和/或覆盖默认行为并找到解决方案提供一个起点。
这也可能是服务器端处理这些输入类型代码的错误,尽管我不确定为什么他们应该/会关心异步回发与正常回发。
this._textTypes = /^(text|password|hidden|search|tel|url|email|number|range|color|datetime|date|month|week|time|datetime-local)$/i;
function Sys$WebForms$PageRequestManager$_onFormSubmit(evt) {
var i, l, continueSubmit = true,
isCrossPost = this._isCrossPost;
this._isCrossPost = false;
if (this._onsubmit) {
continueSubmit = this._onsubmit();
}
if (continueSubmit) {
for (i = 0, l = this._onSubmitStatements.length; i < l; i++) {
if (!this._onSubmitStatements[i]()) {
continueSubmit = false;
break;
}
}
}
if (!continueSubmit) {
if (evt) {
evt.preventDefault();
}
return;
}
var form = this._form;
if (isCrossPost) {
return;
}
if (this._activeDefaultButton && !this._activeDefaultButtonClicked) {
this._onFormElementActive(this._activeDefaultButton, 0, 0);
}
if (!this._postBackSettings || !this._postBackSettings.async) {
return;
}
var formBody = new Sys.StringBuilder(),
count = form.elements.length,
panelID = this._createPanelID(null, this._postBackSettings);
formBody.append(panelID);
for (i = 0; i < count; i++) {
var element = form.elements[i];
var name = element.name;
if (typeof(name) === "undefined" || (name === null) || (name.length === 0) || (name === this._scriptManagerID)) {
continue;
}
var tagName = element.tagName.toUpperCase();
if (tagName === 'INPUT') {
var type = element.type;
if (this._textTypes.test(type)
|| ((type === 'checkbox' || type === 'radio') && element.checked)) {
formBody.append(encodeURIComponent(name));
formBody.append('=');
formBody.append(encodeURIComponent(element.value));
formBody.append('&');
}
}
else if (tagName === 'SELECT') {
var optionCount = element.options.length;
for (var j = 0; j < optionCount; j++) {
var option = element.options[j];
if (option.selected) {
formBody.append(encodeURIComponent(name));
formBody.append('=');
formBody.append(encodeURIComponent(option.value));
formBody.append('&');
}
}
}
else if (tagName === 'TEXTAREA') {
formBody.append(encodeURIComponent(name));
formBody.append('=');
formBody.append(encodeURIComponent(element.value));
formBody.append('&');
}
}
formBody.append("__ASYNCPOST=true&");
if (this._additionalInput) {
formBody.append(this._additionalInput);
this._additionalInput = null;
}
// truncated for length
好吧,我有办法解决这个问题了。首先,我发现了Tim Medora提供的代码的问题。这都是this.
修饰者的错。所以这个JavaScript解决了这个问题:
var _textTypes = /^(text|password|hidden|search|tel|url|email|number|range|color|datetime|date|month|week|time|datetime-local)$/i;
function Sys$WebForms$PageRequestManager$_onFormSubmit(evt) {
...
if (_textTypes.test(type) ||
(((type === 'checkbox') || (type === 'radio')) && element.checked)) {
formBody.append(encodeURIComponent(name));
formBody.append('=');
formBody.append(encodeURIComponent(element.value));
formBody.append('&');
...
}
现在我必须将函数注入ScriptResource.axd
。现在我找到了一种似乎有效的方法:
我创建了一个类ScriptResouceHandler
,扩展了命名空间DotM.Html5.Handlers中的System.Web.Handlers.ScriptResourceHandler
。
在ProcessRequest
中,我调用base.ProcessRequest(context)
来完成它的工作。但是我想把我的函数添加到渲染原始函数的函数中。我发现是在加密的ZSystem.Web.Extensions,4.0.0.0,,31bf3856ad364e35|MicrosoftAjaxWebForms.debug.js|
被通过的时候。
另一个问题是在System.Web.Handlers.ScriptResourceHandler
中,'Page。调用内部的DecryptString方法来解密查询字符串参数。所以我没有办法通过反射来调用那个方法。
protected sealed override void ProcessRequest(HttpContext context)
{
base.ProcessRequest(context);
if (CypherContainsAjax(context.Request.QueryString["d"]))
context.Response.Write(OnFormSubmit);
}
private bool CypherContainsAjax(string cypher)
{
var text = DecryptString(cypher);
if (text == null)
return true; //Then Add it everywhere. What else could I do? :D
return text.Contains("MicrosoftAjaxWebForms");
}
private string DecryptString(string cypher)
{
if (PageDecryptString == null)
return null;
return (string)PageDecryptString.Invoke(null, new object[] { cypher });
}
private static MethodInfo PageDecryptString;
static ScriptResourceHandler()
{
PageDecryptString = typeof(Page).GetMethod("DecryptString", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
}
你可以说这是某种丑陋的黑客行为…
这已经在。net 4可靠性更新1中修复了(也有一个版本2,但它不包含第一个版本):http://support.microsoft.com/kb/2533523
但是如果你正在使用AjaxControlToolkit,它使用自己的内部MicrosoftAjaxWebForms.js,这是一个较旧的分支,仍然没有官方的修复-你可以使用我的解决方案从这里:http://ajaxcontroltoolkit.codeplex.com/workitem/27041
所以-你可以包括固定的ToolkitScriptManager与你的项目(一个膨胀,我知道),或者你可以尝试包括新版本的MicrosoftAjaxWebForms.js通过尝试与vanilla ScriptManager属性AjaxFrameworkMode="Explicit", Scripts或CompositeScript。
使用AjaxFrameworkMode属性来启用所有Microsoft Ajax脚本文件,禁用所有Microsoft Ajax脚本文件,或者显式地包含单个脚本文件。
Scripts集合不包含核心Microsoft Ajax Library脚本。核心库中的脚本是自动呈现的;它们不需要在ScriptManager控件中注册。但是,如果您想要覆盖一个核心脚本或任何控制脚本,并替换脚本的不同版本,您可以将您的版本添加到Scripts集合中。
<asp:ScriptManager runat="server">
<Scripts>
<asp:ScriptReference Path="~/MicrosoftAjaxWebForms.js" />
</Scripts>
</asp:ScriptManager>
您可以在安装了可靠性更新1的机器上从System.Web.Extensions程序集资源(带有。net Reflector)中获得新版本的MicrosoftAjaxWebForms.js。