0

I'm building an Angular2 service to log certain events, stored in ILog objects, and send them to an API to be stored in a database.

My log service is pretty straightforward:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { EnvironmentModule } from "../environment";
import { ILog } from "./log";


@Injectable()
export class LogService {

   constructor(private _http: Http, private environment: EnvironmentModule) { }

   postLog(log: ILog): void {
       this.json = this.convertToJSON(log);
       this._http.post(this.environment.getWebApiUri() + 'api/Log/PostLog/', log, {})
           .subscribe(
           () => console.log('Success')
       ); //goes to localhost:3304/WebAPI/Log/PostLog/, returns 404 not found
   }

}

And it calls a WebAPI Controller that passes the data off to a service to be processed:

[RoutePrefix("api/Log")]
public class LogController : ApiController
{
    private ILogService _LogService;

    public LogController() : this(new LogService())
    {

    } //constructor

    public LogController(ILogService LogService)
    {
        _LogService = LogService;
    } //constructor

    [HttpPost()] 
    [Route("PostLog")]
    public void PostLog(Log log)
    {
        _LogService.PostLog(log);
    } //PostLog

} //class

Yet, when my service calls the API it throws a 404 Not Found Error.

Navigating to the path in the browser I see this:

<Error>
 <Message>
      No HTTP resource was found that matches the request URI
  'http://localhost:3304/WebAPI/api/Log/PostLog/'.
 </Message>
 <MessageDetail>
      No action was found on the controller 'Log' that matches the request.
 </MessageDetail>
</Error>

Can anyone help me with this? I don't understand why it's behaving this way.

Nathan Foss
  • 595
  • 1
  • 9
  • 34
  • Its because you cant post an atomic value directly to your method as json. You could turn it into an object and then post it as a corresponding object or post it as form uri encoded which also works. This is a limitation of asp.net's web api. – Igor Oct 06 '16 at 20:24
  • @Igor I get the same error whether I POST json or the ILog object. Do you have documentation on this? – Nathan Foss Oct 06 '16 at 20:28
  • I updated my answer, the 2nd link has a good example of how you can just change your javascript code and get it to work (i think). – Igor Oct 06 '16 at 20:34

1 Answers1

6

Its because you cant post an atomic value directly to your method as json. You could turn it into an object and then post it as a corresponding object or post it as form uri encoded which also works. This is a limitation of asp.net's web api.

There are some other similar questions all with similar answers. Here is a quick example of how you could change it to work.

c# code

[HttpPost()] 
[Route("PostLog")]
public void PostLog(LogContainerModel logModel)
{
    _LogService.PostLog(logModel.log);
}

// model
public sealed class LogContainerModel {
    public string log { get; set; }
}

javascript code

private convertToJSON(log: ILog): string {
    return JSON.stringify({log: log});
}

Option 2

Stringify it as an object according to this previous SO answer.

c# code

[HttpPost()] 
[Route("PostLog")]
public void PostLog([FromBody] string jsonString)

javascript code

private convertToJSON(log: ILog): string {
    return JSON.stringify({'': log}); // if that does not work try the snippet below
    // return JSON.stringify({'': JSON.stringify(log)});
}

Option 3

Here are some options from bizcoder.com

Use HttpResponseMessage

[HttpPost()] 
[Route("PostLog")]
public async Task PostLog(HttpRequestMessage request)
{
    var jsonString = await request.Content.ReadAsStringAsync();
    _LogService.PostLog(jsonString);
}

Or use json.net

[HttpPost()] 
[Route("PostLog")]
public void PostLog([FromBody]JToken jsonbody)
{
    var jsonString = jsonbody.ToString();
    _LogService.PostLog(jsonString);
}
Community
  • 1
  • 1
Igor
  • 60,821
  • 10
  • 100
  • 175
  • 1
    Alternatively you can add `[FromBody]` to the `jsonString` parameter of the action method, and have your client side code post something like `"{log:\"message\"}"` (basically encode the log object as JSON twice) in the request body. But the method you describe is nicer. – sgbj Oct 06 '16 at 20:32
  • Great insights. Unfortunately, still having the same issues even after trying all of those ideas – Nathan Foss Oct 06 '16 at 20:45
  • @NathanFoss - added 2 more options under option #3 – Igor Oct 06 '16 at 20:57
  • Thanks for all the help @Igor. I am changing my implementation to pass through the object directly in light of that [bizcoder](http://bizcoder.com/posting-raw-json-to-web-api) article. Unfortunately, I still get a `404` with all of these options. – Nathan Foss Oct 06 '16 at 21:15
  • 1
    @NathanFoss - it might not only be the fact that you are sending json. At this point I would set a break point and copy the string `this.environment.getWebApiUri() + 'api/Log/PostLog/'` and make sure that its correct. Then use Fiddler to test that url with a value. If that does not work try it again and post without a value (remove value as well from web api method). This should help you determine if the issue (at this point) is the url, route, or something other than the parameter you are passing. – Igor Oct 07 '16 at 09:55
  • The reason it wasn't working was because I hadn't cleared the cache, cleaned, and rebuilt my project... Rookie mistakes. Excellent solutions and research @Igor – Nathan Foss Oct 07 '16 at 17:11
  • @NathanFoss - thanks for the update, I am glad you got it working! – Igor Oct 07 '16 at 17:13