4

I'm trying to post strings from an AngularJS application (using $http) to a server built on ASP.NET WebApi, but I get 404 as soon as I add a parameter.

The client code is this

$scope.add = function () {
    // ...cut...
    $http({ method: "POST", url: url, data: { fileString: "test string" }}).then(
        function successCallback(response) {
            $log.info(response.data);
        }
    );
}

The server code is

[HttpPost]
public IHttpActionResult UploadExcel(string fileString) {
    // cut
}

I get a 404, but if I remove the parameter on server side it works, so i can use a server side code like this

[HttpPost]
public IHttpActionResult UploadExcel() {
    // cut
}

What is wrong? Should I pass the data in a different way? I tried different combination but I can't get it work.

Naigel
  • 9,086
  • 16
  • 65
  • 106

3 Answers3

5

What you want to do is send a string, not a JSON object as you are doing right now with { fileString: "test string" }. When I want to send a string, what I normally do is that I send data from Angular like this:

$http.post("/Search/QuickSearch?searchQuery="+ searchString);

And my controller I make ready to receive a string like this:

[HttpPost]
public IHttpActionResult QuickSearch(string searchQuery)
{
    // cut
}

If I want to send a JSON object, I tell my controller what it should expect, like this:

[HttpPost]
public IHttpActionResult SaveActivity(ActivityEditForm form);
{
    // cut
}

public class ActivityEditForm
{
    public int? Id { get; set; }
    [Required]
    public string Title { get; set; }

    public string Description { get; set; }
}

And then send my JSON from Angular like this:

$http.post("/Activity/SaveActivity", { form: activity });
Squazz
  • 3,912
  • 7
  • 38
  • 62
  • this workaround can't work because my parameter string is too big – Naigel Jan 12 '16 at 15:02
  • Try sending it as a JSON object and then preparing your controller for the data. Have updated my answer with how I handle that approach. – Squazz Jan 12 '16 at 15:07
  • 1
    Due to some configuration dependent glitches I suggest to always use your "JSON object" solution. Even if it's a single string I decided to create a C# object. – Naigel Apr 13 '16 at 12:21
  • 1
    I'm sorry to hear you had some problems with your solution, but I'm glad that I could be of any help. I myself is rather satisfied with my solution myself, if has served me well for the last two years :) – Squazz Apr 13 '16 at 12:51
2

I suggest you should capture the request send by Angular. By default, Angular send parameters in a json string in request body.

I'm not sure wether Asp.net can parse them from json string in body.

So, you can try to add the below codes (also need jQuery)

angular.module('yourApp').config(function ($httpProvider) {
    $httpProvider.defaults.transformRequest = function(data){
        if (data === undefined) {
            return data;
        }
        return $.param(data);
    }
});
Eric Zeng
  • 135
  • 5
  • 1
    Thank you for the suggestion, I think changing the C# WebApi backend is much more clear, but this should be a viable solution if someone doesn't have control on the backend – Naigel Apr 13 '16 at 12:22
2

The first error is in the controller, [FromBody] should be used with the input parameter.

public IHttpActionResult UploadExcel([FromBody]string fileString)

Then the data variable on the client should be a single string, so

$http({ method: "POST", url: url, data: "test string" }).then(

Anyway I found some issue with this solution later, it seems the simplest but I suggest to avoid it.


Best solution

Thank to @Squazz answer and this SO answer I strongly suggest a change in the webapi controller, client was correct. Just introduce a class to handle a single string and adapt the input parameter

// new class with a single string
public class InputData {
    public string fileString { get; set; }
}

// new controller 
[HttpPost]
public IHttpActionResult UploadExcel([FromBody] InputData myInput) {
    string fileString = myInput.fileString;
    // cut
}

This way JSON code from the client is automatically parsed and it's easy to change the data input.

Extra tip

$scope.add angular function was correct as in the question, but here is a more complete example

$scope.testDelete = function () {
    var url = "http://localhost/yourAppLink/yourControllerName/UploadExcel";
    var data = ({ fileString: "yourStringHere" });
    $http({ method: "POST", url: url, data: data }).then(
        function successCallback(response) {
            console.log("done, here is the answer: ", response.data);
        }, function errorCallback(response) {
            console.log("an error occurred");
        }
    );
}
Community
  • 1
  • 1
Naigel
  • 9,086
  • 16
  • 65
  • 106