0

Below is part of the Angular controller I use to populate three cascading lists of address data, with the last being a BootStrap Tab Page widget. I have only tested on Chrome and Edge so far, with similar results.

public class AreaController : BaseController
{
    private readonly AreaClient _areaClient = new AreaClient(UserHelper.CurrentUser);
    private readonly AgentClient _agentClient = new AgentClient();

    [HttpPost]
    public JsonResult ProvincesJson()
    {
        return Json(_areaClient.GetProvinces().ToList());
    }

    [HttpPost]
    public JsonResult AreasJson(int provinceId)
    {
        var model = _areaClient.GetAreas(provinceId).ToList();
        return Json(model);
    }

    [HttpGet]
    public JsonResult SuburbsJson(int agentId, int areaId)
    {
        var allBurbs = _areaClient.GetSuburbs(areaId).ToList();
        var agentBurbIds = _agentClient.GetAgentSuburbs(agentId).Select(ab => ab.SuburbId).ToList();

        var model = allBurbs.Select(burb => new CheckListItemModel { Id = burb.SuburbId, Label = burb.SuburbName, IsChecked = agentBurbIds.Contains(burb.SuburbId) }).ToList();
        return Json(model);
    }
}

ProvincesJson and AreasJson work perfectly for this partial view:

<div id="areas-and-suburbs" ng-controller="areasCtrl">
    <div class="form-group">
        <select id="ProvinceId" ng-model="geo.provinces.selectedId" ng-change="geo.getAreas(agentId, geo.provinces.selectedId)" class="form-control">
            <option ng-repeat="item in geo.provinces" ng-value="{{item.provinceId}}" class=".area-option">{{item.provinceName}}</option>
        </select>    
    </div>
    <div class="form-group">
        <select id="AreaId" ng-model="geo.areas.selectedId" ng-change="geo.setSuburbs(geo.areas.selectedId)" class="form-control">
            <option ng-repeat="item in geo.areas" ng-value="{{item.areaId}}" class=".area-option">{{item.areaName}}</option>
        </select>
    </div>
    <div class="form-group">
        <div id="area-suburbs-partial">
            @Html.Partial("_Suburbs")
        </div>
    </div>
</div>

The inner partial, _Suburbs looks like this:

$scope.geo.getSuburbs = function(agentId, areaId) {
    var geoUrl = "\/Area/SuburbsJson";
    $http.post(geoUrl, { areaId: 3, agentId: 1 }, postOptions)
        .then(function(response) {
                var model = angular.fromJson(response.data);
                $scope.agentSuburbs = model.$values;
                _.defer(function() {
                    $scope.$apply();
                });
            },
            function error(response) {
                alert("Ajax error [getSuburbs]: " + response.responseText);
            });
};

Yet when the outer parial renders __Suburbs, which calls geo.setSuburbs, I get "localhost refused to connect" error in Chrome. Everything in this project is same domain, just one project, and the Provinces and Areas dropdowns cascade properly, but when I select a new Area, to trigger fetching suburbs for that area, I get the error.

I see very little difference between the three actions, so I really don't understand why a connection to the third is refused. I even removed the business logic from SuburbsJson to return a simple array of int, and called it directly from the browser, vs. from my Angular controller's Ajax logic, and I still got a refused connection.

What could be behind just this one controller action causing a refused connection?

BREAKING: I was a touch dyslexic somewhere with the spelling of area. Fixing that solved everything on that day.

ProfK
  • 49,207
  • 121
  • 399
  • 775
  • Is that really `_Suburbs` in it's entirety? – DavidG May 26 '16 at 18:58
  • PS You are also `POST`ing the suburbs action but it's decorated with `HttpGet`. – DavidG May 26 '16 at 19:04
  • Yes, @DavidG, all it takes is to update the model ($scope) and an `ng-repeat` and I have my nice little checkbox list of suburbs. Must admit, I did commit the partial view for suburbs, as it was undergoing gruesome surgery. – ProfK Jun 01 '16 at 13:34
  • I asked because you have Javascript inside a div and no surrounding `script` tag. – DavidG Jun 01 '16 at 13:36

1 Answers1

0

For one, you're POSTing to your GET method, so MVC won't route it for you.

HTTPGET Methods in MVC have to have the JsonRequestBehavior.AllowGet flag as the second parameter of the return Json.

Instead

// Do other stuff to get model
return Json(model, JsonRequestBehavior.AllowGet);

See this other SO post for why AllowGet is necessary

Community
  • 1
  • 1
rictionaryFever
  • 751
  • 8
  • 14
  • It was a 'middle-of-posting' mistake. I made the action and Angular methods Get, then went back to post and forgot to change the attribute before I copy and pasted. It gives me the same error when properly set up for get and post. – ProfK May 26 '16 at 20:14
  • Once it is set to HTTPGet, you will need the allow get parameter when you return your JsonResult. Do you get the error still after adding that parameter? – rictionaryFever May 26 '16 at 20:31
  • Yes, I still get the error. But I'll try making it GET again and try, to be sure. I've understood the link between a POST request and `AllowGet` and `DenyGet` for many years already, but I could have slipped up somewhere. – ProfK May 27 '16 at 03:51