首页 文章

如何将json POST数据作为对象传递给Web API方法?

提问于
浏览
256

ASP.NET MVC4 Web API应用程序定义了保存客户的post方法 . 客户在POST请求正文中以json格式传递 . post方法中的customer参数包含属性的空值 .

如何解决这个问题,以便发布的数据作为客户对象传递?

如果可能的话Content-Type:application / x-www-form-urlencoded应该使用,因为我不知道如何在发布表单的javascript方法中更改它 .

控制器:

public class CustomersController : ApiController {

  public object Post([FromBody] Customer customer)
        {
            return Request.CreateResponse(HttpStatusCode.OK,
            new
            {
                customer = customer
            });
        }
    }
}

public class Customer
    {
        public string company_name { get; set; }
        public string contact_name { get; set; }
     }

请求:

POST http://localhost:52216/api/customers HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=UTF-8

{"contact_name":"sdfsd","company_name":"ssssd"}

9 回答

  • 62

    Following code to return data in the json format ,instead of the xml -Web API 2 :-

    将以下行放在Global.asax文件中

    GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
    
  • 0

    EDIT :31/10/2017

    相同的代码/方法也适用于 Asp.Net Core 2.0 . 主要区别在于,在asp.net核心中,web api控制器和Mvc控制器都合并为单个控制器模型 . 所以你的返回类型可能是 IActionResult 或其中一个实现(例如: OkObjectResult


    使用

    contentType:"application/json"
    

    发送时需要使用 JSON.stringify 方法将其转换为JSON字符串,

    模型 Binders 将json数据绑定到您的类对象 .

    以下代码将正常工作(测试)

    $(function () {
        var customer = {contact_name :"Scott",company_name:"HP"};
        $.ajax({
            type: "POST",
            data :JSON.stringify(customer),
            url: "api/Customer",
            contentType: "application/json"
        });
    });
    

    Result

    enter image description here

    contentType 属性告诉服务器我们正在以JSON格式发送数据 . 由于我们发送了JSON数据结构,因此模型绑定将正确发生 .

    如果检查ajax请求的标头,则可以看到 Content-Type 值设置为 application/json .

    如果未明确指定contentType,它将使用默认内容类型 application/x-www-form-urlencoded;


    在2015年11月编辑,以解决评论中提出的其他可能问题

    发布复杂对象

    假设你有一个复杂的视图模型类作为你的web api动作方法参数

    public class CreateUserViewModel
    {
       public int Id {set;get;}
       public string Name {set;get;}  
       public List<TagViewModel> Tags {set;get;}
    }
    public class TagViewModel
    {
      public int Id {set;get;}
      public string Code {set;get;}
    }
    

    和你的web api终点就像

    public class ProductController : Controller
    {
        [HttpPost]
        public CreateUserViewMode Save([FromBody] CreateUserViewModel m)
        {
            // I am just returning the posted model as it is. 
            // You may do other stuff and return different response.
            // Ex : missileService.LaunchMissile(m);
            return m;
        }
    }
    

    在撰写本文时,ASP.NET MVC 6是最新的稳定版本,在MVC6中,Web api控制器和MVC控制器都继承自 Microsoft.AspNet.Mvc.Controller 基类 .

    要从客户端向方法发送数据,下面的代码应该可以正常工作

    //Build an object which matches the structure of our view model class
    var model = {
        Name: "Shyju",
        Id: 123,
        Tags: [{ Id: 12, Code: "C" }, { Id: 33, Code: "Swift" }]
    };
    
    $.ajax({
        type: "POST",
        data: JSON.stringify(model),
        url: "../product/save",
        contentType: "application/json"
    }).done(function(res) {       
        console.log('res', res);
        // Do something with the result :)
    });
    

    模型绑定适用于某些属性,但不是全部!为什么?

    如果不使用 [FromBody] 属性装饰web api方法参数

    [HttpPost]
    public CreateUserViewModel Save(CreateUserViewModel m)
    {
        return m;
    }
    

    并且在不指定contentType属性值的情况下发送模型(原始javascript对象,而不是JSON格式)

    $.ajax({
        type: "POST",
        data: model,
        url: "../product/save"
    }).done(function (res) {
         console.log('res', res);
    });
    

    模型绑定适用于模型上的平面属性,而不适用于类型复杂/其他类型的属性 . 在我们的例子中, IdName 属性将正确绑定到参数 m ,但 Tags 属性将是一个空列表 .

    如果您使用的是短版本 $.post ,在发送请求时将使用默认的Content-Type,则会出现同样的问题 .

    $.post("../product/save", model, function (res) {
        //res contains the markup returned by the partial view
        console.log('res', res);
    });
    
  • 0

    使用 JSON.stringify() 以JSON格式获取字符串,确保在进行AJAX调用时传递下面提到的属性:

    • contentType:'application/json'

    • dataType:'json'

    下面是给jQuery的代码来调用asp.net web api的ajax:

    var product =
        JSON.stringify({
            productGroup: "Fablet",
            productId: 1,
            productName: "Lumia 1525 64 GB",
            sellingPrice: 700
        });
    
    $.ajax({
        URL: 'http://localhost/api/Products',
        type: 'POST',
        contentType: 'application/json',
        dataType: 'json',
        data: product,
        success: function (data, status, xhr) {
            alert('Success!');
        },
        error: function (xhr, status, error) {
            alert('Update Error occurred - ' + error);
        }
    });
    
  • 1

    1)在您的客户端,您可以发送http.post请求,如下所示

    var IndexInfo = JSON.stringify(this.scope.IndexTree);
    this.$http.post('../../../api/EvaluationProcess/InsertEvaluationProcessInputType', "'" + IndexInfo + "'" ).then((response: any) => {}
    

    2)然后在您的web api控制器中,您可以反序列化它

    public ApiResponce InsertEvaluationProcessInputType([FromBody]string IndexInfo)
        {
    var des = (ApiReceivedListOfObjects<TempDistributedIndex>)Newtonsoft.Json.JsonConvert.DeserializeObject(DecryptedProcessInfo, typeof(ApiReceivedListOfObjects<TempDistributedIndex>));}
    

    3)您的ApiReceivedListOfObjects类应如下所示

    public class ApiReceivedListOfObjects<T>
        {
            public List<T> element { get; set; }
    
        }
    

    4)确保在步骤2中的JsonConvert.DeserializeObject命令之前,序列化字符串(此处为IndexInfo)变为如下结构

    var resp = @"
        {
            ""element"": [
            {
                ""A"": ""A Jones"",
                ""B"": ""500015763""
            },
            {
                ""A"": ""B Smith"",
                ""B"": ""504986213""
            },
            {
                ""A"": ""C Brown"",
                ""B"": ""509034361""
            }
            ]
        }";
    
  • 473

    我刚刚玩这个并发现了一个相当奇怪的结果 . 假设您在C#中的类具有公共属性,如下所示:

    public class Customer
    {
        public string contact_name;
        public string company_name;
    }
    

    然后你必须按照Shyju的建议做JSON.stringify技巧,并像这样调用它:

    var customer = {contact_name :"Scott",company_name:"HP"};
    $.ajax({
        type: "POST",
        data :JSON.stringify(customer),
        url: "api/Customer",
        contentType: "application/json"
    });
    

    但是,如果您在类上定义getter和setter,如下所示:

    public class Customer
    {
        public string contact_name { get; set; }
        public string company_name { get; set; }
    }
    

    然后你可以更简单地调用它:

    $.ajax({
        type: "POST",
        data :customer,
        url: "api/Customer"
    });
    

    这使用HTTP标头:

    Content-Type:application/x-www-form-urlencoded
    

    我不太确定这里发生了什么,但它看起来像框架中的一个bug(功能?) . 据推测,不同的绑定方法调用不同的“适配器”,而应用程序/ json的适配器使用公共属性,而表单编码数据的适配器则不然 .

    我不知道哪个被认为是最好的做法 .

  • 10
    @model MVCClient.Models.ProductDetails
    
    @{
        ViewBag.Title = "ProductDetails";
    }
    <script src="~/Scripts/jquery-1.8.2.min.js"></script>
    <script type="text/javascript">
    
        $(document).ready(function () {
            $("#Save").click(function () {
                var ProductDetails = new Object();
                ProductDetails.ProductName =  $("#txt_productName").val();
                ProductDetails.ProductDetail = $("#txt_desc").val();
                ProductDetails.Price= $("#txt_price").val();
                $.ajax({
                    url: "http://localhost:24481/api/Product/addProduct",
                    type: "Post",
                    dataType:'JSON',
                    data:ProductDetails, 
    
                    success: function (data) {
                        alert('Updated Successfully');
                        //window.location.href = "../Index";
                    },
                    error: function (msg) { alert(msg); }
                });
            });
        });
        </script>
    <h2>ProductDetails</h2>
    
    <form id="form1" method="post">
        <fieldset>
            <legend>ProductDetails</legend>
    
    
            <div class="editor-label">
                @Html.LabelFor(model => model.ProductName)
            </div>
            <div class="editor-field">
    
                <input id="txt_productName" type="text" name="fname">
                @Html.ValidationMessageFor(model => model.ProductName)
            </div>
    
            <div class="editor-label">
                @Html.LabelFor(model => model.ProductDetail)
            </div>
            <div class="editor-field">
    
                <input id="txt_desc" type="text" name="fname">
                @Html.ValidationMessageFor(model => model.ProductDetail)
            </div>
    
            <div class="editor-label">
                @Html.LabelFor(model => model.Price)
            </div>
            <div class="editor-field">
    
                <input id="txt_price" type="text" name="fname">
                @Html.ValidationMessageFor(model => model.Price)
            </div>
    
    
    
            <p>
                <input id="Save" type="button" value="Create" />
            </p>
        </fieldset>
    
    </form>
        <div>
            @Html.ActionLink("Back to List", "Index")
        </div>
    
    </form>
    
    
    
    @section Scripts {
        @Scripts.Render("~/bundles/jqueryval")
    }
    
  • 0

    微软给出了一个很好的例子:

    https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-1

    首先验证请求

    if (ModelState.IsValid)
    

    而不是使用序列化数据 .

    Content = new StringContent(update.Status)
    

    这里的“状态”是复杂类型中的一个字段 . 序列化由.NET完成,无需担心 .

  • 0

    确保您的WebAPI服务期望一个强类型对象,其结构与您传递的JSON相匹配 . 并确保您对要发布的JSON进行字符串化 .

    这是我的JavaScript(使用AngluarJS):

    $scope.updateUserActivity = function (_objuserActivity) {
            $http
            ({
                method: 'post',
                url: 'your url here',
                headers: { 'Content-Type': 'application/json'},
                data: JSON.stringify(_objuserActivity)
            })
            .then(function (response)
            {
                alert("success");
            })
            .catch(function (response)
            {
                alert("failure");
            })
            .finally(function ()
            {
            });
    

    这是我的WebAPI控制器:

    [HttpPost]
    [AcceptVerbs("POST")]
    public string POSTMe([FromBody]Models.UserActivity _activity)
    {
        return "hello";
    }
    
  • 0

    在webapi中使用POST可能很棘手!想补充已经正确的答案..

    将专注于POST,因为处理GET是微不足道的 . 我不认为很多人会搜索通过webapis解决GET问题 . 无论如何..

    如果您的问题是 - 在MVC Web Api中,如何 - 使用除通用HTTP谓词之外的自定义操作方法名称? - 执行多个帖子? - 发布多种简单类型? - 通过jQuery发布复杂类型?

    那么以下解决方案可能有所帮助

    首先,要在Web API中使用 Custom Action Methods,请添加web api路由:

    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "ActionApi",
            routeTemplate: "api/{controller}/{action}");
    }
    

    然后你可以创建动作方法,如:

    [HttpPost]
    public string TestMethod([FromBody]string value)
    {
        return "Hello from http post web api controller: " + value;
    }
    

    现在,从浏览器控制台激发以下jQuery

    $.ajax({
        type: 'POST',
        url: 'http://localhost:33649/api/TestApi/TestMethod',
        data: {'':'hello'},
        contentType: 'application/x-www-form-urlencoded',
        dataType: 'json',
        success: function(data){ console.log(data) }
    });
    

    第二,到 perform multiple posts ,很简单,创建多个动作方法并用[HttpPost] attrib进行装饰 . 使用[ActionName("MyAction")]分配自定义名称等 . 将在下面的第四点介绍jQuery

    第三,首先,无法在单个操作中发布多个 SIMPLE 类型 . 此外,有一个 special format 甚至发布 single simple type (除了在查询字符串或REST样式中传递参数) . 这就是让我与Rest Clients(如Fiddler和Chrome的高级REST客户端扩展)一起敲打我的头,并在网上狩猎近5个小时,最终,以下网址被证明是有帮助的 . 会引用链接的相关内容可能会变死!

    Content-Type: application/x-www-form-urlencoded
    in the request header and add a = before the JSON statement:
    ={"Name":"Turbo Tina","Email":"na@Turbo.Tina"}
    

    PS:注意到特殊的语法?

    http://forums.asp.net/t/1883467.aspx?The+received+value+is+null+when+I+try+to+Post+to+my+Web+Api

    无论如何,让我们克服那个故事 . 继续:

    第四, posting complex types 通过jQuery,当然,$ .ajax()将立即进入角色:

    我们假设action方法接受一个具有id和name的Person对象 . 所以,从javascript:

    var person = { PersonId:1, Name:"James" }
    $.ajax({
        type: 'POST',
        url: 'http://mydomain/api/TestApi/TestMethod',
        data: JSON.stringify(person),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        success: function(data){ console.log(data) }
    });
    

    行动将如下所示:

    [HttpPost]
    public string TestMethod(Person person)
    {
        return "Hello from http post web api controller: " + person.Name;
    }
    

    以上所有,为我工作!!干杯!

相关问题