Answers.Body: <p>Ok so thanks to @BradBell's suggestion, I regenerated the skeleton of my plugin and it's controller using <a href="http://pluginfactory.io" rel="nofollow noreferrer">pluginfactory.io</a> and it now magically works! Still not sure exactly what the difference was, but it does its job now!</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-07-20T23:17:06.590Z
Answers.LastActivityDate: 2017-07-20T23:17:06.590Z
Answers.UserDisplayName: stojda
Body: <p>Before I dive into my problem, I do want to mention that I <strong>did</strong> do my due diligence and spent the last two days researching this problem, to no avail, so here it goes: </p>
  
  <p>So I'm getting the following error when trying to load an action method from the controller: <code>Unable to resolve the request "ecaApi/main/doGeocodeRequest".</code> I get this error if I try and navigate directly to it, e.g. domain.com/actions/ecaApi/main/doGeocodeRequest</p>
  
  <p>The AJAX request below also generates a 404.</p>
  
  <p><strong>File Structure:</strong></p>
  
  <pre><code>- craft/plugins
    - ecaapi
      - controllers
        --EcaApi_MainController.php
      --EcaApiPlugin.php
  </code></pre>
  
  <p><strong>EcaApi_MainController.php</strong></p>
  
  <pre><code> namespace Craft;
  
      class EcaApi_MainController extends BaseController
      {
          protected $allowAnonymous = true;
  
          public function actionDoGeocodeRequest() {
              //.....
              $this-&gt;returnJson($result);
          }
      }
  </code></pre>
  
  <p><strong>JS ajax call to the action method</strong></p>
  
  <pre><code>    var data = {
          address: "{{ event.event_location }}"
      };
      data[csrfTokenName] = csrfTokenValue;
      data['action'] = 'ecaApi/main/doGeocodeRequest';
      $.ajax({
          method: "POST",
          url: "/",
          data: data
      })
          .done(function (data) {
              console.log(data);
              markers[{{ event.id }}] = new google.maps.Marker({
                  position: new google.maps.LatLng(data.results[0].geometry.location.lat, data.results[0].geometry.location.lng),
                  map: map,
                  {% if mapSettings.mapIcon %}
                  icon: mapMarkerIcon,
                  {% endif %}
                  title: "{{ event.title }}"
              });
              var content = '&lt;a href="{{ event.url|replace({'http://': 'https://'}) }}"&gt;{{ event.title }}&lt;/a&gt;';
              var window = new google.maps.InfoWindow({
                  content: content
              });
              markers[{{ event.id }}].addListener('click', function () {
                  window.open(map, markers[{{ event.id }}]);
              });
  
          });
  </code></pre>
  
  <p>Any help would be appreciated, I've been pulling out my hair for days over this.</p>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-07-20T03:22:30.287Z
Comments.Text: "Unable to resolve the request "ecaApi/main/test". Was that the actual error or was it "Unable to resolve the request "ecaApi/main/doGeocodeRequest"? Not seeing a controller action named test in your example.
Comments.UserDisplayName: Brad Bell
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-07-20T03:27:15.557Z
Comments.Text: @BradBell I clarified that part, pasted the wrong error!
Comments.UserDisplayName: stojda
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-07-20T03:29:15.653Z
Comments.Text: Your `EcaApiPlugin.php` file has a class name of `EcaApiPlugin`?
Comments.UserDisplayName: Brad Bell
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-07-20T03:32:54.037Z
Comments.Text: @BradBell Yes indeed!
Comments.UserDisplayName: stojda
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-07-20T03:35:32.317Z
Comments.Text: Hrm... my gut says it's some silly case sensitivity issue, but I'm not seeing it from the example. Couldn't hurt to generate the boilerplate plugin code from https://pluginfactory.io/ to help rule that out.
Comments.UserDisplayName: Brad Bell
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-07-20T17:15:22.977Z
Comments.Text: @BradBell We are getting somewhere! I generated the skeletal plugin as suggested, and for the first time it actually appeared in my plugins list. I was also able to log a "Hello World" to the plugin's log file, so it seems to be working! Im going to re-write the guts of my original controller tonight and lets see what happens. 
  
  Im curious to see what changed in the structure/files to make it wake up and see my plugin, time to pull up BeyondCompare :) 
  
  Thanks!
Comments.UserDisplayName: stojda
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-07-20T20:24:25.537Z
Comments.Text: Beyond Compare is the best! Be sure and add an official answer once you get to the bottom of it in case it ends up helping someone in the future. :)
Comments.UserDisplayName: Brad Bell
Tags: <ajax><controller><jquery>
Title: Error 404 When trying to POST to plugin Controller action
ThreadText: # Error 404 When trying to POST to plugin Controller action
  
  (Asked by: username_0 on 2017-07-20)
  
  Before I dive into my problem, I do want to mention that I **did** do my due diligence and spent the last two days researching this problem, to no avail, so here it goes:
  
  So I'm getting the following error when trying to load an action method from the controller: `Unable to resolve the request "ecaApi/main/doGeocodeRequest".` I get this error if I try and navigate directly to it, e.g. domain.com/actions/ecaApi/main/doGeocodeRequest
  
  The AJAX request below also generates a 404.
  
  **File Structure:**
  
  ```
  - craft/plugins
    - ecaapi
      - controllers
        --EcaApi_MainController.php
      --EcaApiPlugin.php
  
  ```
  
  **EcaApi\_MainController.php**
  
  ```
   namespace Craft;
  
      class EcaApi_MainController extends BaseController
      {
          protected $allowAnonymous = true;
  
          public function actionDoGeocodeRequest() {
              //.....
              $this->returnJson($result);
          }
      }
  
  ```
  
  **JS ajax call to the action method**
  
  ```
      var data = {
          address: "{{ event.event_location }}"
      };
      data[csrfTokenName] = csrfTokenValue;
      data['action'] = 'ecaApi/main/doGeocodeRequest';
      $.ajax({
          method: "POST",
          url: "/",
          data: data
      })
          .done(function (data) {
              console.log(data);
              markers[{{ event.id }}] = new google.maps.Marker({
                  position: new google.maps.LatLng(data.results[0].geometry.location.lat, data.results[0].geometry.location.lng),
                  map: map,
                  {% if mapSettings.mapIcon %}
                  icon: mapMarkerIcon,
                  {% endif %}
                  title: "{{ event.title }}"
              });
              var content = '<a href="{{ event.url|replace({'http://': 'https://'}) }}">{{ event.title }}</a>';
              var window = new google.maps.InfoWindow({
                  content: content
              });
              markers[{{ event.id }}].addListener('click', function () {
                  window.open(map, markers[{{ event.id }}]);
              });
  
          });
  
  ```
  
  Any help would be appreciated, I've been pulling out my hair for days over this.
  
  **Tags:** ajax, controller, jquery
  
  > **Comments:**
  > **username_1**: "Unable to resolve the request "ecaApi/main/test". Was that the actual error or was it "Unable to resolve the request "ecaApi/main/doGeocodeRequest"? Not seeing a controller action named test in your example.  
  > **username_0**: @username_1 I clarified that part, pasted the wrong error!  
  > **username_1**: Your `EcaApiPlugin.php` file has a class name of `EcaApiPlugin`?  
  > **username_0**: @username_1 Yes indeed!  
  > **username_1**: Hrm... my gut says it's some silly case sensitivity issue, but I'm not seeing it from the example. Couldn't hurt to generate the boilerplate plugin code from https://pluginfactory.io/ to help rule that out.  
  > **username_0**: @username_1 We are getting somewhere! I generated the skeletal plugin as suggested, and for the first time it actually appeared in my plugins list. I was also able to log a "Hello World" to the plugin's log file, so it seems to be working! Im going to re-write the guts of my original controller tonight and lets see what happens.   Im curious to see what changed in the structure/files to make it wake up and see my plugin, time to pull up BeyondCompare :)   Thanks!  
  > **username_1**: Beyond Compare is the best! Be sure and add an official answer once you get to the bottom of it in case it ends up helping someone in the future. :)  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_0 on 2017-07-20. Score: 1 | Accepted answer
  
  Ok so thanks to @username_1's suggestion, I regenerated the skeleton of my plugin and it's controller using [pluginfactory.io](http://pluginfactory.io) and it now magically works! Still not sure exactly what the difference was, but it does its job now!
  
  
  ---
  
  