jones.busy

technical musings of a caffeine converter

NAVIGATION - SEARCH

Extending Angular $http service

Recently, I’ve been working with AngularJs, developing an Azure targeted application with an Entity Framework (Code First) backend, Web Api v2.0 middle tier and an AngularJs front-end. I like AngularJS for a number of reasons, one of which is that, as a .Net, WPF developer for most of my time, having so many different options and approaches to consider with client-side web development, having a framework that minimises those options into one core approach is beneficial to me. I completely understand that this same reason could be seen as a negative and I am well aware of the impending re-write of Angular due this year but to move from the safety net of a strongly typed .net background to the javascript playground, AngularJS feels a little like I’ve got some stabilisers on my dev bike Smile

Using the $http service over the weekend, I stumbled across a couple of issues:

1. Calling a web api method with a simple string parameter:

public async Task<IHttpActionResult> PostRole([FromBody]string roleName)

The issue is that by sending the string across as a variable causes some misinterpretation of as it as a json literal so instead of the value finding its way to the web api method, you get a null object instead. So, instead of calling the following:

return $http.post(serviceBase + 'api/admin/roles', roleName);

You need to do this:

return $http.post(serviceBase + 'api/admin/roles', "'" + roleName + "'");

2. Calling a ‘get’ method from within IE:

public async Task<IHttpActionResult> Get()

For some unknown reason, no matter how hard I tried to stop this from caching when testing in IE, I had no luck. In the end, the only approach that worked for me was to randomise the request as follows:

return $http.get(serviceBase + 'api/admin/roles?rnd=' + new Date().getTime());

It’s not very pretty is it? Firstly, I must asking anyone reading that has any suggestions or comments about what I’ve done or the issues I have faced, please do get in touch as it is perfectly feasible I have completely crossed my wires with this and there is another approach I should have taken. But for now, these are the issues I hit, Googled, and then put in some workarounds.

Now, having found a workaround, I realised that these sorts of calls could be a regular occurrence and so I don’t want to have to remember to apply these fixes each time. My first thought was to see whether I could extend the $http service to wrap this functionality in a neat bundle for me. Coming from C# extension methods i looked at the following options:

1. prototyping

2. behaviours

3. providers

I’ve heard about most of these approaches but never seen any in practice. I really wanted to stick to passing in $http and just being able to either handle or extend the functionality to handle these requirements but could not get this to work with my limited javascript knowledge. In the end, I create a new service, extendedHttpService, which is actually a factory class that returns an extended version of the $http service:

(function (ng, app) { "use strict"; app.factory('extendedHttpService', ['$http', function($http) { var forceGet = function(url) { return $http.get(url + "?rnd=" + new Date().getTime()); }; var postString = function(url, str) { return $http.post(url, "\"" + str + "\""); }; $http['forceGet'] = forceGet; $http['postString'] = postString; return $http; } ]); })(angular, app);

Allowing me to then call the extended functions as follows:

(function (ng, app) { "use strict"; app.service('rolesService', ['extendedHttpService', 'appSettings', function (extendedHttpService, appSettings) { var serviceBase = appSettings.apiServiceBaseUri; this.getAllRoles = function () { return extendedHttpService.forceGet(serviceBase + "api/admin/roles/"); }; this.createRole = function (roleName) { return extendedHttpService.postString(serviceBase + 'api/admin/roles', roleName); }; this.updateRole = function (role) { return extendedHttpService.put(serviceBase + 'api/admin/roles', role); }; }]); })(angular, app);

This is much neater, but I’d love to hear on other approaches that I could have used in this scenario.

Add comment