Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Posting to .net Web API

I am trying to execute a POST from my angular application to a .net Web API instance but the server returns null.

server

    [HttpPost] 
    public string callBcknd([FromBody]string body)
    {
        try
        {
            Log.Info(string.Format("{0}", body));

        }
        catch(Exception ex)
        {
            return "error";
        }
    }
}

angular *note that I am using HttpClient instead of Http.. not sure if this is also the problem

callServer(){
    var test = { "name": "John" }
    let data = JSON.stringify(test);
    let headers = new HttpHeaders(); 
    headers.set('Content-Type', 'application/json');
    this.appService.http.post('http://localhost:3000/api/WebApI/callBcknd', 
                          test, 
                          {headers: headers})
  .subscribe(data => {console.log(data);}}}

config

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {

            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new {action = "GET", id = RouteParameter.Optional}
            );
        }
    }

With above setting, I don't gen any 404 server error in client side(by checking chrome's console) but it returns null in backend. But as I tried with Postman, it sends values properly with the same url. If I don't include [FromBody] inside of method in backend, I get an 404 server error in client side. Furthermore, messages says "NO HTTP resource was found that matches the request URI". Similar question to this seems solving the problem by having [FromBody] but I still get a null... I also suspected maybe my web config file(not the one in above) should contain some headers, so when I added some headers like content type to be json and etc then I get 500 server error in client side. At this point i am really confused and not sure what to proceed.

UPDATE1

Following server code returns the message but I am still getting the body as null.. no errors have been observed

[HttpPost]
        public IHttpActionResult Callbcknd([FromBody] string body)
        {
            try
            {
                Log.Info(string.Format("called with data {0}", body));

                return Ok(new { Message = "It worked!" });
            }

            catch(Exception ex)
            {
                return base.Content(HttpStatusCode.InternalServerError, ex.ToString());
            }
        }
like image 448
Zlatko Loa Avatar asked Dec 11 '22 09:12

Zlatko Loa


1 Answers

I see multiple reasons why you would get unexpected errors and null values in your code:

  1. (error) Your .net method callBcknd should not even compile as it can only return something if there is an Exception.
  2. (error) You should send json when sending data to your api controller the message body and the api controller method should accept an complex object and not a primitive type like string/int/bool etc.
  3. (warning) Your angular service should expose functionality and return either observables or promises that the component can then subscribe to. Do not expose the HttpClient directly.
  4. (warning) Your web api should return interface IHttpActionResult instead of the type directly. Then you can use the built in methods like Ok and Content and BadRequest to return status information along with data. See also Action Results in Web API 2
  5. (suggestion) Use Route and RoutePrefix as attributes instead of relying on the route config. This is more flexible and will allow you to also specify parameters to be included in the URL which will make for a more RESTful design. See also Attribute Routing in ASP.NET Web API 2
  6. (suggestion) Add CamelCasePropertyNamesContractResolver to resolve between camel and pascal casing between your front end and backend. See also Serialization using ContractResolver

This is a good example of how make calls to a Web API and how to structure your code.

Note that these code samples only show the relevant parts that were added or modified

WebApiConfig.cs

public static class WebApiConfig {
    public static void Register(HttpConfiguration config) {
        // add this to ensure that casing is converted between camel case (front end) and pascal case (c#/backend)
        var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
        json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

        config.MapHttpAttributeRoutes();
    }
}

ApiModel.cs

public class ApiModel {
    public string Content {get;set;}
}

WebApIController.cs

[RoutePrefix("api/WebApI")]
public class WebApIController : ApiController {

    [HttpPost] 
    [Route("callBcknd")]
    public IHttpActionResult CallBcknd([FromBody] ApiModel body)
    {
        try
        {
            Log.Info(string.Format("{0}", body.Content));
            return Ok(new {Message = "It worked!"});
        }
        catch(Exception ex)
        {
            // example of how to return error with content. I would not recommend actually returning the exception details to the client in a production setting
            return base.Content(HttpStatusCode.InternalServerError, ex.ToString());
        }
    }
}

application.service.ts

constructor(private httpClient: HttpClient){}

callServer(data: {content: string}) : Observable<any> {
    return this.httpClient.post('http://localhost:3000/api/WebApI/callBcknd', data);
}

application.component.ts

constructor(private myService: MyService){}

onDoSomething(){
    this.myService.callServer({content: 'This is what I have sent'})
        .subscribe(data => console.log("Succeeded, result = " + data), (err)=> console.error("Failed! " + err));
}

Notice the following:

  1. ApiModel represents the incoming object in the request. The angular call then sends {content: 'This is what I have sent'} which mirrors this type.
  2. IHttpActionResult is the response type for your Web API method
  3. You can return different types along with status information in the method CallBcknd
  4. Route and RoutePrefix were added to give more control over the uri path.
  5. The angular component and service have been split into 2 methods, the service returns an observable and the component calls the service methods and subcribes to the returning observable. When you extend this example you want to replace any with defined expected results using interfaces and the same is true for any incoming parameters you want to send.
like image 109
Igor Avatar answered Dec 27 '22 05:12

Igor