dimanche 12 juin 2016

angularjs access denied when calling remote webapi using $resource

I am not sure if I have CORS issue with my Angular app calling WebAPI. My ASP.Net MVC/Angular App1 and the Web API are hosted on the same IIS server. For example, the url for App1 is https://example.com/App1. The Web API url is http://example.com/wcf_webapi/clinicaluserprofile/api/{userNetworkName}. On a MVC view page there is a <div ng-include=" 'path to an angular view template' "></div> that uses $resource to get data from the WebAPI. In Visual Studio 2013 IDE when I hit F5 to debug on my development workstation everything works as expected. I can see a call to the Web API in IE Developer Tools' Network tab. However, when I publish App1 to that IIS server, the Web API call doesn't seem to be made. Instead, I saw access denied in the IE Developer Tools Console. I have another MVC/Angular App2 on the same IIS in different folder with almost identical Angular code. The url for App2 is https://example.com/App2. It doesn't get access denied. Can you help? Thanks.

Here is the Config.js

/// <reference path="C:UsersmyNameSourceReposAppsApp1Scripts/angular.js" />
(function() {
  'use strict'

  var moduleName = 'configModule';
  angular.module(moduleName, []);

  var apiKeyValuePair = {
    'api': {
      centralAdmin: 'http://example.com/wcf_webapi/CentralAdmin/api/',
      fsr: 'http://example.com/FSRManagement/api/',
      userProfile: 'http://example.com/wcf_webapi/clinicaluserprofile/api/'
    }
  }

  var userKeyValuePair = {
    'userAccount': {
      //this is bootstraped and updated in MVC view page <script> block
      userName: ''
    }
  }

  //populate the constant collection
  angular.forEach(apiKeyValuePair, function(val, key) {
    angular.module(moduleName).constant(key, val);
  });
   
  //populate the value collection
  angular.forEach(userKeyValuePair, function(val, key) {
    angular.module(moduleName).value(key, val);
  });
})();

Here is the App.js

/// <reference path="C:UsersmyNameSourceReposAppsApp1Scripts/angular.js" />
(function() {
  'use strict'
  var moduleName = 'ufsrAppModule';
  var requiredModules = [
    'configModule',
    'fsrFactoryModule',
    'userFsrFactoryModule',
    'userProfileFactoryModule'
  ]
  var app = angular.module(moduleName, requiredModules);
  //  app.config(
  //    )

})();

Here is the userProfileFactory.js

/// <reference path="C:UsersmyNameSourceReposAppsApp1Scripts/angular.js" />
/// <reference path="C:UsersmyNameSourceReposAppsApp1Scripts/angular-resource.js" />
/// <reference path="../config.js" />

(function() {
  'use strict';

  var moduleName = 'userProfileFactoryModule';
  var factoryName = 'userProfileFactory';
  var requiredModules = ["ngResource", "configModule"];
  var dependencyInjection = ['$resource', 'api', 'userAccount', internalFunc];

  angular.module(moduleName, requiredModules)
    .factory(factoryName, dependencyInjection);

  function internalFunc($resource, api, userAccount) {
    function getUserProfile() {
      return $resource(api.userProfile + 'user/profile/:NN', {
        NN: '@NN'
      });
    };

    return {
      //usage: userProfileFactory.getUserProfile()
      getUserProfile /*public method*/ : getUserProfile /*internal method above*/
    }
  }
})();

Here is the Angular template being included in the MVC view

<div ng-controller="ufsrController as ufsrCtrl">
  <div class="container">
    <div class="row">
      <div class="widget-body">
        <div class="col-md-6 col-sm-6 fa fa-border">
          <div class="row">
            <div class="col-md-2 col-sm-2"><label class=" form-label">Facility:</label></div>
            <div class="col-md-9 col-sm-9" style="padding: 0; margin: 0">
              <select ng-model="ufsrCtrl.facility" name="facility"
                      ng-options="fac.FacilityID as fac.FacilityName for fac in ufsrCtrl.facilities"
                      ng-disabled="(ufsrCtrl.facilities === undefined || ufsrCtrl.facilities.length <= 0)"
                      ng-change="ufsrCtrl.facilityChanged()"
                      class="form-control"></select>
            </div>
            <!--
              <div class="col-md-1 col-sm-1">
                <i ng-show="ufsrCtrl.facilities === undefined || ufsrCtrl.facilities.length <= 0" class="fa fa-refresh fa-spin"></i>
              </div>
            -->
          </div>

          <div class="row">
            <input type="text" name="service" ng-model="ufsrCtrl.service.ServiceName" style="display:none" />
            <div class="col-md-2 col-sm-2"><label class="form-label">Service:</label></div>
            <div class="col-md-9 col-sm-9" style="padding: 0; margin: 0">
              <select ng-model="ufsrCtrl.service" name="serviceId"
                      ng-options="ser.ServiceName for ser in ufsrCtrl.services track by ser.ServiceID "
                      ng-disabled="(ufsrCtrl.services === undefined || ufsrCtrl.services.length <= 0)"
                      ng-change="ufsrCtrl.serviceChanged()"
                      class="form-control">
                <option value="">-- Choose Service --</option>
              </select>
            </div>
            <div class="col-md-1 col-sm-1">
              <i ng-show="ufsrCtrl.services === undefined || ufsrCtrl.services.length <= 0" class="fa fa-refresh fa-spin"></i>
            </div>

          </div>

          <div class="row">
            <input type="text" name="role" ng-model="ufsrCtrl.role.RoleName" style="display:none" />
            <div class="col-md-2 col-sm-2"><label class="form-label">Role:</label></div>
            <div class="col-md-9 col-sm-9" style="padding: 0; margin: 0">
              <select ng-model="ufsrCtrl.role" name="roleId"
                      ng-options="role.RoleName for role in ufsrCtrl.roles track by role.FacilityServiceRoleID"
                      ng-disabled="(ufsrCtrl.roles === undefined || ufsrCtrl.roles.length <= 0)"
                      ng-change="ufsrCtrl.roleChanged()"
                      class="form-control">
                <option value="">-- Choose Role --</option>
              </select>
            </div>
            <div class="col-md-1 col-sm-1" title="select a Service to dismiss me">
              <i ng-show="ufsrCtrl.roles === undefined || ufsrCtrl.roles.length <= 0" class="fa fa-refresh fa-spin"></i>
            </div>


          </div>

          <!--<div class="form-group">
            <button class="btn btn-primary" ng-disabled="(ufsrCtrl.role === undefined)" ng-click="ufsrCtrl.add()" disabled="disabled">
              Add new role {{ufsrCtrl.role.FacilityServiceRoleID}} ({{ufsrCtrl.role.RoleName}})
            </button>
            <span ng-show="(ufsrCtrl.postStatus === true)" class="alert-success"><i class="fa fa-check"></i>Success</span>
            <span ng-show="(ufsrCtrl.postStatus === false)" class="alert-danger"><i class="fa fa-warning"></i>Failure</span>
          </div>-->
        </div>
        <div class="col-md-6 col-sm-6">
          <ul style="list-style-type:disc">
            <li>Select your service then role from the dropdown lists.  The rotating icons will disappear when the selected data is retrieved from the database.</li>
            <li>Check the accuracy of your name and email address and correct them address if incorrect</li>
            <li>Click <b>Send</b> button to send email to the administrators</li>
          </ul>
        </div>
      </div>
    </div>
  </div>
</div>

Here is the controller.js where "Access denied" occurred on line

userProfileFactory.getUserProfile().get({ NN: userAccount.networkName }

/// <reference path="C:UsersmyNameSourceReposAppsApp1Scripts/angular.js" />
/// <reference path="UserProfile/userProfileFactory.js" />
(
  function() {
    'use strict';

    var moduleName = 'ufsrAppModule';
    var controllerName = 'ufsrController';
    var dependencyInjection = ['api', 'userAccount', 'userProfileFactory', 'fsrFactory', 'userFsrFactory', internalFunc];

    angular.module(moduleName)
      .controller(controllerName, dependencyInjection);

    function internalFunc(api, userAccount, userProfileFactory, fsrFactory, userFsrFactory) {

      var vm = this; //controller AS in ng-controller, do not use $scope

      vm.postStatus = undefined;
      vm.deleteStatus = undefined;
      vm.showFSRSpinner = true;

      //the following REST call to the WebAPI is access denied
      userProfileFactory.getUserProfile().get({
          NN: userAccount.networkName
        },
        function(data) {
          //debugger;

          vm.userProfile = data;

          if (vm.userProfile != undefined || vm.userProfile != null) {
            if (vm.userProfile.SimpleUser != undefined)
              vm.userId = vm.userProfile.SimpleUser.UserID;

            if (vm.userProfile.UserFSRs != null && vm.userProfile.UserFSRs !== undefined) {
              if (vm.userProfile.UserFSRs.length > 1) {
                vm.role === undefined;
                vm.deletable = true;
              }
            }

            //due to the userProfileFactory uses async to make REST api call
            //the vm.userProfile.InferredFacility won't be avaialbe until the success callback is executed
            //and until then the vm.facilities will make api call to fsrFactory.facility().get()

            vm.facility; //for binding to facility dropdown selected item (ng-model)

            //the fsrFacility.facility().get() returns an object
            //but the vm.facilities is bound to ng-option in the <select> element which expects an array
            //so the returned object needs to be wrapped in aryFacility array

            var aryFacility = [];

            var tempFacilityObj = fsrFactory.facility().get({
              id: vm.userProfile.InferredFacility.FacilityID
            }); //get only facility of the user's inferred facility
            aryFacility.push(tempFacilityObj);
            console.log(aryFacility);

            vm.facilities = aryFacility;
            console.log(vm.facilities);

            vm.facility = vm.userProfile.InferredFacility.FacilityID;
            console.log(vm.facility);

            vm.postStatus = undefined;
            vm.services = undefined;
            vm.roles = undefined;
            vm.services = fsrFactory.service().query({
              FacilityID: vm.facility
            });
          }
        }
      );

      vm.facilityChanged = function() {
        vm.postStatus = undefined;
        vm.services = undefined;
        vm.roles = undefined;
        vm.services = fsrFactory.service().query({
          FacilityID: vm.facility
        });
      }

      vm.service; //for binding to service dropdown selected item (ng-model)
      vm.serviceChanged = function() {
        console.log(vm.service);
        vm.postStatus = undefined;
        vm.roles = undefined;
        vm.roles = fsrFactory.role().query({
          FacilityID: vm.facility,
          ServiceID: vm.service.ServiceID
        });
      }

      vm.role; //for binding to role dropdown selected item (ng-model)
      vm.roleChanged = function() {
        console.log(vm.role);
        vm.postStatus = undefined;
      }

      vm.add = function() {
        //debugger;
        vm.postStatus = undefined;
        vm.deleteStatus = undefined;
        userFsrFactory.addUserFSR().save({
            userId: vm.userId,
            fsrId: vm.role.FacilityServiceRoleID
          },
          function() {
            alert("New role added");
            vm.postStatus = true;

            //vm.userProfile.UserFSRs.push({
            //  UserFacilityServiceRoleID: vm.userId,
            //  dtoFSR: {
            //    FacilityName: vm.facility.FacilityName,
            //    ServiceName: vm.service.ServiceName,
            //    RoleName: vm.role.RoleName,
            //  }
            //})
            userProfileFactory.getUserProfile().get(function(data) {
              vm.userProfile = data; //after add requery userProfile to get the list of user FSR
              if (vm.userProfile.UserFSRs != undefined && vm.userProfile.UserFSRs.length > 1) {
                vm.deletable = true;
                vm.disabled = false;
                vm.role = undefined;
              }
            });
          },
          function() {
            alert("add role failed");
            vm.postStatus = false;
          });
      }

      vm.delete = function(idx, ufsrId) {
        vm.postStatus = undefined;
        vm.deleteStatus = undefined;
        userFsrDeleteFactory.deleteUserFSR().delete({
            userId: vm.userId,
            ufsrId: ufsrId
          },
          function() {
            alert("Delete Succeeded");
            vm.deleteStatus = true;

            vm.userProfile.UserFSRs.splice(idx, 1); //remove from the fsr array
            if (vm.userProfile.UserFSRs != undefined && vm.userProfile.UserFSRs.length > 1)
              vm.deletable = true;

            //$route.reload();
            //location.reload(true); //jquery
          },
          function() {
            alert("Delete failed")
            vm.deleteStatus = false;
          }
        );
      }
    }
  })();

Aucun commentaire:

Enregistrer un commentaire