首页 文章

Angular Posting to .net Web API

提问于
浏览
3

我正在尝试从我的角应用程序执行 POST 到.net Web API 实例,但服务器返回null

服务器

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

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

angular *请注意我使用的是 HttpClient 而不是 Http ..不确定这是否也是问题所在

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);}}}

****配置

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}
            );
        }
    }

通过上面的设置,我不会在客户端 side(by 检查 chrome 的控制台中生成任何 404 服务器错误,但它在后端返回 null.但是当我尝试使用 Postman 时,它会使用相同的 url 正确发送值.如果我在后端的方法中没有包含[8],我在客户端会收到 404 服务器错误.此外,消息显示“未找到与请求 URI 匹配的 HTTP 资源”.类似的问题似乎通过[9]解决问题,但我仍然得到一个空...我也怀疑也许我的 web 配置 file(not 上面的那个)应该包含一些标题,所以当我添加一些像内容类型的标题是 json 等,然后我在客户端获得 500 服务器错误。在这一点上,我真的很困惑,不知道该怎么做。

**** UPDATE1

以下服务器代码返回消息,但我仍然将正文设置为 null ..没有观察到任何错误

[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());
            }
        }

3 回答

  • 5

    我看到为什么在代码中会出现意外错误和空值的原因有多种:

    • (错误)你的.net 方法callBcknd甚至不应该编译,因为它只能在有异常的情况下返回一些内容。

    • (错误)你应该在向 api 控制器发送数据时发送 json 消息体和 api 控制器方法应该接受一个复杂的对象而不是原始类型string/int/bool等。

    • (警告)您的角度服务应该公开功能并返回组件可以订阅的可观察或承诺。不要直接暴露HttpClient

    • (警告)您的 web api 应该直接返回接口IHttpActionResult而不是类型。然后,您可以使用 Ok,Content 和 BadRequest 等内置方法返回状态信息和数据。另见Web API 2 中的操作结果

    • (建议)使用RouteRoutePrefix作为属性,而不是依赖路由配置。这更灵活,您还可以指定要包含在 URL 中的参数,这将使更多 RESTful 设计成为可能。另见ASP.NET Web API 2 中的属性路由

    • (建议)添加CamelCasePropertyNamesContractResolver以解决前端和后端之间的 camel 和 pascal 外壳之间的问题。另见使用 ContractResolver 进行序列化


    这是如何调用 Web API 以及如何构建代码的一个很好的示例。

    请注意,这些代码示例仅显示已添加或修改的相关部分

    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));
    }
    

    请注意以下事项:

    • ApiModel表示请求中的传入对象。然后,角度调用发送{content: 'This is what I have sent'},它反映了这种类型。

    • IHttpActionResult是 Web API 方法的响应类型

    • 您可以在方法CallBcknd中返回不同类型以及状态信息

    • 添加了RouteRoutePrefix以更好地控制 uri 路径。

    • 角度组件和服务已分为 2 个方法,服务返回一个 observable,组件调用服务方法和子目录到返回的 observable。当您扩展此示例时,您希望使用接口将any替换为定义的预期结果,对于要发送的任何传入参数也是如此。

  • 1

    从“Angular”对 API 的 Tipical 调用

    update(data: string): Observable<IResponse> {
        console.log(data);
        let url = '...';
        let headers = new Headers({
            'Content-Type': 'application/json; charset=utf-8',
        });
        let options = new RequestOptions({ headers: headers })
    
        return this._http.post(url, data, options)
            .map((res: any) => {
                return res.json();
            })
            .catch(this.handleError);
    
    }
    

    API 中的代码

    [HttpPost] 
    public string callBcknd([FromBody]string body)
    {
       try
       {
          Log.Info(string.Format("{0}", body));
          //You must return something
          return "Post Realized";
       }
       catch(Exception ex)
       {
          return "error";
       }
    }
    
    //I like call async
    
    [HttpPost] 
    
    public async Task<IActionResult>callBcknd([FromBody]string body)
    {
       try
       {
          Log.Info(string.Format("{0}", body));
          //await "some action"
          //You can return OK("success") or an object
          return Ok(new { success = true, description = "callback sucesfully" });;
       }
       catch(Exception ex)
       {
                //You can return OK("error") or an object
          return Ok(new { success = false, description = ex.InnerException });;
       }
    }
    
  • 0

    那么,你发布的内容会是什么样

    {"body":{// something here }}
    

    而您的控制器期望:

    "valuehere"(这是字符串的有效 json)。

    您需要更改 c#代码以获得 DTO 的模型:

    public class PostedObject{
     public object Data {get;set;}
    }
    
      [HttpPost] 
        public string callBcknd([FromBody]PostedObject body)
        {
        // do things
    
    }
    

相关问题