title: ASP.NET Generic Handler not getting called after .NET 3.5 to .NET 4.0 upgrade
body: <p>This old title describes the visible issue, but the new title describes the root cause issue a little better.  I'm still not sure why the ASHX isn't getting called, so I'm still looking for an answer.  I have a workaround for now by hard coding the API descriptor (Ext.app.REMOTING_API variable).  I got that JSON object (Ext.app.REMOTING_API variable) from the DirectProxy "provider" returned variable, from the original code running .NET 3.5.  I just used an online JavaScript beautifier to make it look beautiful (so you can read it, instead of being on a single line).</p>
  
  <p>Old Title: <code>ExtJS 3 Ext.Direct proxy error: Uncaught TypeError: Cannot read property 'events' of undefined</code></p>
  
  <p>I just upgraded the extdirect4dotnet project from .NET 3.5 to .NET 4.0.  That project and a sample project can be found here <a href="https://code.google.com/p/extdirect4dotnet/" rel="nofollow noreferrer">https://code.google.com/p/extdirect4dotnet/</a>.  When I did this, I had to temporarily copy the Web.Config file when I changed the project version.  I fixed the parameter list of two override methods that was due to inheriting a class in JSON.NET found at <a href="http://json.codeplex.com/SourceControl/latest#readme.txt" rel="nofollow noreferrer">http://json.codeplex.com/SourceControl/latest#readme.txt</a>.  I also fixed the way DLL references were being made in both projects.  I then replaced all occurances of "3.5" to "4.0" in the Web.Config.</p>
  
  <p>Unfortunately, this project uses ExtJs 3.0.0, not ExtJs 4.2.* which is the framework version I'm implementing the Ext.Direct proxy for with this .NET server-side stack (extdirect4dotnet) with.  So it still uses some old syntax.  Below I'm trying to figure out how to fix a particular error after the .NET upgrade.  It's still using ExtJs 3.0.0.  See "see this line" in the "addProvider" function to see the line it's failing on.  When I debug this from JavaScript, "provider" is undefined.  I guess it doesn't know how to get provider <code>Ext.app.REMOTING_API</code> after I upgraded this to .NET 4.0.</p>
  
  <p><strong>JavaScript error:</strong></p>
  
  <pre><code>Uncaught TypeError: Cannot read property 'events' of undefined 
  </code></pre>
  
  <p><strong>ExtJs code:</strong></p>
  
  <pre><code>/*!
   * Ext JS Library 3.0.0
   * Copyright(c) 2006-2009 Ext JS, LLC
   * licensing@extjs.com
   * http://www.extjs.com/license
   */
  </code></pre>
  
  <p>...</p>
  
  <pre><code> * &lt;/code&gt;&lt;/pre&gt;
   * @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 &gt; 1){
          for(var i = 0, len = a.length; i &lt; len; i++){
              this.addProvider(a[i]);
          }
          return;
      }
  
      // if provider has not already been instantiated
      if(!provider.events){  // &lt;========================= 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;
  },
  </code></pre>
  
  <p><strong>Sample project JavaScript code:</strong></p>
  
  <pre><code>Ext.Direct.addProvider(Ext.app.REMOTING_API); 
  </code></pre>
  
  <p><strong>Screen shot of JavaScript debugger on "provider" object with .NET 3.5 implementation (before .NET upgrade)</strong></p>
  
  <p>(open in new window to see a larger image)</p>
  
  <p><img src="https://i.stack.imgur.com/Fs5EN.jpg" alt="enter image description here"></p>
  
  <p>As a workaround, I've done the following to my js file and hard coded the provider (Ext.app.REMOTING_API variable).  This is essentially a JSON object which is my API Descriptor.  I captured the variable "provider" from the inherited ASHX code below when the sample project was configured with .NET 3.5.  For some strange reason, my Generic Handler in ASP.NET is not getting called.  The class the Generic Handler is inheriting from seems like normal .NET 4.0 Generic Handler (ASHX) code to me.  I've pasted the HTML, ASHX and inherited ASHX below.</p>
  
  <pre><code>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,     // &lt;-- 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) {   // &lt;-- 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
  </code></pre>
  
  <p><strong>HTML code:</strong></p>
  
  <p>...</p>
  
  <pre><code>&lt;link rel="stylesheet" type="text/css" href="../ext/resources/css/ext-all.css" /&gt;    
  &lt;script type="text/javascript" src="../ext/ext-base-debug.js"&gt;&lt;/script&gt;     
  &lt;script type="text/javascript" src="../ext/ext-all-debug.js"&gt;&lt;/script&gt;
  &lt;!-- directProxy.rfc was registred in the web.config --&gt;
  &lt;script type="text/javascript" src="../directProxy.ashx"&gt;&lt;/script&gt;
  </code></pre>
  
  <p>...</p>
  
  <p><strong>ASHX:</strong></p>
  
  <p>using System;</p>
  
  <pre><code>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
  {
     /// &lt;summary&gt;
      /// Zusammenfassungsbeschreibung für $codebehindclassname$
      /// &lt;/summary&gt;
      [WebService(Namespace = "http://tempuri.org/")]
      [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
      public class directProxy : DirectProxy
      {
          public directProxy()
          {
              DirectProxy.routerUrl = "../directRouter.ashx";
          }
  
      }
  }
  </code></pre>
  
  <p><strong>Inherited ASHX found within ExtDirect4DotNet (code didn't change during .NET 4.0 upgrade):</strong></p>
  
  <pre><code>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
  {
      /// &lt;summary&gt;
      /// Represents the Proxy For Ext.Direct Comunication.
      /// Tha ProccessRequest Methode scanns all the available Assembly for Classes and Methods with the 
      /// Direct Attribute.
      /// &lt;/summary&gt;
      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; }
          }
      }
  }
  </code></pre>