这个旧标题描述了可见的问题,但新标题更好地描述了根本原因问题。我仍然不确定为什么 ASHX 没有被调用,所以我仍在寻找答案。我现在有一个解决方法,方法是硬编码 API 描述符(Ext.app.REMOTING_API 变量)。我从运行 .NET 3.5 的原始代码中的 DirectProxy“提供程序”返回的变量中获得了 JSON 对象(Ext.app.REMOTING_API 变量)。我只是使用了一个在线 JavaScript 美化器让它看起来很漂亮(这样你就可以阅读它,而不是在一行上)。
旧标题:ExtJS 3 Ext.Direct proxy error: Uncaught TypeError: Cannot read property 'events' of undefined
我刚刚将 extdirect4dotnet 项目从 .NET 3.5 升级到 .NET 4.0。该项目和示例项目可以在这里找到https://code.google.com/p/extdirect4dotnet/。当我这样做时,我不得不在更改项目版本时临时复制 Web.Config 文件。我修复了两个覆盖方法的参数列表,这是由于在http://json.codeplex.com/SourceControl/latest#readme.txt中的 JSON.NET 中继承了一个类。我还修复了两个项目中 DLL 引用的方式。然后,我将 Web.Config 中所有出现的“3.5”替换为“4.0”。
不幸的是,这个项目使用 ExtJs 3.0.0,而不是 ExtJs 4.2.*,这是我使用这个 .NET 服务器端堆栈 (extdirect4dotnet) 实现 Ext.Direct 代理的框架版本。所以它仍然使用一些旧的语法。下面我试图弄清楚如何在 .NET 升级后修复特定错误。它仍在使用 ExtJs 3.0.0。请参阅“addProvider”函数中的“查看此行”以查看它失败的行。当我从 JavaScript 调试它时,“提供者”是未定义的。Ext.app.REMOTING_API
我想在我将它升级到 .NET 4.0 后它不知道如何获取提供程序。
JavaScript 错误:
Uncaught TypeError: Cannot read property 'events' of undefined
ExtJs 代码:
/*!
* Ext JS Library 3.0.0
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
...
* </code></pre>
* @param {Object/Array} provider Accepts either an Array of Provider descriptions (an instance
* or config object for a Provider) or any number of Provider descriptions as arguments. Each
* Provider description instructs Ext.Direct how to create client-side stub methods.
*/
addProvider : function(provider){
var a = arguments;
if(a.length > 1){
for(var i = 0, len = a.length; i < len; i++){
this.addProvider(a[i]);
}
return;
}
// if provider has not already been instantiated
if(!provider.events){ // <========================= see this line
provider = new Ext.Direct.PROVIDERS[provider.type](provider);
}
provider.id = provider.id || Ext.id();
this.providers[provider.id] = provider;
provider.on('data', this.onProviderData, this);
provider.on('exception', this.onProviderException, this);
if(!provider.isConnected()){
provider.connect();
}
return provider;
},
示例项目 JavaScript 代码:
Ext.Direct.addProvider(Ext.app.REMOTING_API);
具有 .NET 3.5 实现的“提供者”对象上 JavaScript 调试器的屏幕截图(在 .NET 升级之前)
(在新窗口中打开查看大图)
作为一种解决方法,我对我的 js 文件执行了以下操作并对提供程序(Ext.app.REMOTING_API 变量)进行了硬编码。这本质上是一个 JSON 对象,它是我的 API 描述符。当示例项目使用 .NET 3.5 配置时,我从下面继承的 ASHX 代码中捕获了变量“provider”。出于某种奇怪的原因,我在 ASP.NET 中的通用处理程序没有被调用。Generic Handler 继承的类对我来说似乎是普通的 .NET 4.0 Generic Handler (ASHX) 代码。我在下面粘贴了 HTML、ASHX 和继承的 ASHX。
Ext.onReady(function () {
Ext.app.REMOTING_API = {
"type": "remoting",
"id": "1",
"url": "../directRouter.ashx",
"actions": {
"CallTypes": [{
"name": "Echo",
"len": 1,
"formHandler": false
}, {
"name": "GetTime",
"len": 0,
"formHandler": false
}, {
"name": "UploadHttpRequestParam",
"len": 1,
"formHandler": true
}, {
"name": "UploadNamedParameter",
"len": 1,
"formHandler": true
}, {
"name": "SaveMethod",
"len": 3,
"formHandler": false
}, {
"name": "SaveMethod_Form",
"len": 1,
"formHandler": true
}, {
"name": "DateSample",
"len": 2,
"formHandler": false
}],
"TreeAction": [{
"name": "getChildNodes",
"len": 2,
"formHandler": false
}],
"CRUDSampleMethods": [{
"name": "create",
"len": 1,
"formHandler": false
}, {
"name": "read",
"len": 1,
"formHandler": false
}, {
"name": "update",
"len": 2,
"formHandler": false
}, {
"name": "destroy",
"len": 1,
"formHandler": false
}, {
"name": "reset",
"len": 0,
"formHandler": false
}]
}
};
Ext.Direct.addProvider(Ext.app.REMOTING_API);
//Ext.Direct.addProvider();
var Employee = Ext.data.Record.create([
{ name: 'firstname' }, // map the Record's "firstname" field to the row object's key of the same name
{name: 'job', mapping: 'occupation'} // map the Record's "job" field to the row object's "occupation" key
]);
var reader = new Ext.data.JsonReader({
totalProperty: 'results',
successProperty: 'success',
idProperty: 'id',
root: 'data'
}, [
{ name: 'id' },
{ name: 'email', allowBlank: false },
{ name: 'first', allowBlank: false },
{ name: 'last', allowBlank: false }
]
);
var writer = new Ext.data.JsonWriter({
returnJson: false,
writeAllFields: true
});
var store = new Ext.data.DirectStore({
api: {
read: CRUDSampleMethods.read,
create: CRUDSampleMethods.create,
update: CRUDSampleMethods.update,
destroy: CRUDSampleMethods.destroy
},
reader: reader,
baseParams: { dummy: 'blubb' },
writer: writer, // <-- plug a DataWriter into the store just as you would a Reader
paramsAsHash: true,
batchSave: false,
batch: false,
prettyUrls: false,
remoteSort: true,
listeners: {
load: function (result) {
},
loadexception: function () {
},
scope: this
}
});
//
var myPageSize = 10;
var userColumns = [
{ header: "ID", width: 40, sortable: true, dataIndex: 'id' },
{ header: "Email", width: 100, sortable: true, dataIndex: 'email', editor: new Ext.form.TextField({}) },
{ header: "First", width: 50, sortable: true, dataIndex: 'first', editor: new Ext.form.TextField({}) },
{ header: "Last", width: 50, sortable: true, dataIndex: 'last', editor: new Ext.form.TextField({}) }
];
Ext.onReady(function () {
Ext.QuickTips.init();
var userForm = new App.user.Form({
renderTo: 'user-form',
listeners: {
create: function (fpanel, data) { // <-- custom "create" event defined in App.user.Form class
var rec = new userGrid.store.recordType(data);
userGrid.store.insert(0, rec);
}
}
});
// create user.Grid instance (@see UserGrid.js)
var userGrid = new App.user.Grid({
renderTo: 'user-grid',
store: store,
columns: userColumns,
bbar: new Ext.PagingToolbar({
store: store, // grid and PagingToolbar using same store
displayInfo: true,
pageSize: myPageSize,
prependButtons: true,
items: [
'text 1'
]
}),
listeners: {
rowclick: function (g, index, ev) {
var rec = g.store.getAt(index);
userForm.loadRecord(rec);
},
destroy: function () {
userForm.getForm().reset();
}
}
});
setTimeout(function () {
Ext.get('loading').remove();
Ext.fly('loading-mask').fadeOut({
remove: true
});
store.load({ params: {
start: 0, // specify params for the first page load if using paging
limit: myPageSize,
foo: 'bar'
}
});
}, 250);
});
}); // onready
HTML 代码:
...
<link rel="stylesheet" type="text/css" href="../ext/resources/css/ext-all.css" />
<script type="text/javascript" src="../ext/ext-base-debug.js"></script>
<script type="text/javascript" src="../ext/ext-all-debug.js"></script>
<!-- directProxy.rfc was registred in the web.config -->
<script type="text/javascript" src="../directProxy.ashx"></script>
...
阿什克斯:
使用系统;
using System.Collections;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using ExtDirect4DotNet;
namespace WebApplication1
{
/// <summary>
/// Zusammenfassungsbeschreibung für $codebehindclassname$
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class directProxy : DirectProxy
{
public directProxy()
{
DirectProxy.routerUrl = "../directRouter.ashx";
}
}
}
在 ExtDirect4DotNet 中找到的继承 ASHX(在 .NET 4.0 升级期间代码未更改):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Configuration;
using System.Web.Configuration;
using ExtDirect4DotNet;
using ExtDirect4DotNet.helper;
namespace ExtDirect4DotNet
{
/// <summary>
/// Represents the Proxy For Ext.Direct Comunication.
/// Tha ProccessRequest Methode scanns all the available Assembly for Classes and Methods with the
/// Direct Attribute.
/// </summary>
public class DirectProxy : IHttpHandler
{
private static string url = "";
public static string routerUrl {
get { return url; }
set { url = value; }
}
public static DirectProvider getDirectProviderCache(string apiNameSpace)
{
string routerUrl = (DirectProxy.routerUrl == "") ? ConfigurationCache.getRouterUrl() : DirectProxy.routerUrl;
// set default namspace for the remoting API
string apiNamespace = (apiNameSpace == null || apiNameSpace == "") ? "Ext.app.REMOTING_API" : apiNameSpace;
DirectProviderCache cache = DirectProviderCache.GetInstance();
DirectProvider provider;
//After being configured, the provider should be cached.
if (!cache.ContainsKey(apiNamespace + "/" + routerUrl))
{
provider = new DirectProvider(apiNamespace, routerUrl);
provider.Configure(AppDomain.CurrentDomain.GetAssemblies());
if (!cache.ContainsKey(apiNamespace + "/" + routerUrl))
cache.Add(apiNamespace + "/" + routerUrl, provider);
}
else
{
provider = cache[apiNamespace + "/" + routerUrl];
}
return provider;
}
public void ProcessRequest(HttpContext context)
{
// set default namspace for the remoting API
string apiNamespace = "Ext.app.REMOTING_API";
if (context.Request.Form["ns"] != null)
{
// if there is an namespace parameter, use it...
apiNamespace = context.Request.Form["ns"].ToString();
}
DirectProvider provider = getDirectProviderCache(apiNamespace);
context.Response.Write(provider.ToString());
/*
old code..
// set the Response typ to javascript since the responce gets Parsed into an Script Tag
context.Response.ContentType = "text/JavaScript";
string rem = "{";
rem += "url: \""+routerUrl+"\",";
rem += "type:\"remoting\",";
//string json = DirectProxyGenerator.generateDirectApi();
//rem += json;
rem += "};";
rem = apiNamespace + ".REMOTING_API =" + rem;
rem = "(function(){" + rem + "})();";
context.Response.Write(rem);
*/
}
public bool IsReusable
{
get { return false; }
}
}
}