【问题标题】:MVC WebApi HttpGet with complex object具有复杂对象的 MVC WebApi HttpGet
【发布时间】:2013-03-15 09:49:13
【问题描述】:

我有一个现有的 WebApi 操作,我想从 HttpPost 切换到 HttpGet。它目前将单个复杂对象作为参数。

型号:

public class BarRequest
{
    [JsonProperty("catid")]
    public int CategoryId { get; set; }
}

控制器:

public class FooController : ApiController
{
    //[HttpPost]
    [HttpGet]
    [ActionName("bar")]
    public void Bar([FromUri] BarRequest request)
    {
        if (request != null)
        {
            // CategoryId should be 123, not 0
            Debug.WriteLine("Category ID :: {0}", request.CategoryId);
        }
    }
}

现在,当我发送以下请求时,一切正常。

GET /foo/bar?CategoryId=123

旧的 POST 请求也按预期工作。

POST /foo/bar {"catid":123}

但现在我需要以下请求才能工作:

GET /foo/bar?catid=123

我怎样才能做到这一点?

【问题讨论】:

  • 为什么不直接使用 CategoryID 呢?或者为什么不使用 CatID 作为属性名称,或者使用 CatID 作为方法的参数?
  • 真实模型具有更多属性。属性命名无法更改(每一端的命名准则 - server/c# 和 client/js)。
  • 这能回答你的问题吗? How to make GET request with a complex object?
  • @MichaelFreidgeim - OP 需要将CategoryId 属性绑定到catid,所以Changing the parameter name Web Api model binding 不会更密切相关吗?

标签: asp.net asp.net-web-api deserialization json.net


【解决方案1】:

System.Net.Http.UriExtensions 中的URI 上有一个扩展方法,可以完全满足您的要求:TryReadQueryAs<T>(out T model)。您可以从 ApiController 中的请求中获取 URI:Request.RequestUri。下面是它的样子:

public class FooController : ApiController
{
    //[HttpPost]
    [HttpGet]
    [ActionName("bar")]
    public void Bar()
    {
        BarRequest request;
        if (Request.RequestUri.TryReadQueryAs(out model))
        {
            // CategoryId should be 123, not 0
            Debug.WriteLine("Category ID :: {0}", request.CategoryId);
        }
    }
}

这可能仅在您像 Joan 建议的那样指定 [DataContract] 时才有效。

但请注意,将解析空查询字符串,因此如果您过去根据数据是否为 ​​POSTed 执行不同的操作,则需要检查模型的有效性。不过希望你还是那样做。

【讨论】:

    【解决方案2】:

    感谢您的建议,但唯一适合我的解决方案如下。

    之前:

    var data = {
        catid: 123,
        // <snip>
    };
    var json = JSON.stringify(data);
    $.post('/foo/bar', json, callback);
    
    public class FooController : ApiController
    {
        [HttpPost, ActionName("bar")]
        public void Bar(BarRequest request)
        {
            // use request.Category to process request
        }
    }
    

    之后:

    var data = {
        catid: 123,
        // <snip>
    };
    var json = JSON.stringify(data);
    $.get('/foo/bar?data=' + encodeURIComponent(json), callback);
    
    public class FooController : ApiController
    {
        [HttpGet, ActionName("bar")]
        public void Bar(string data)
        {
            var request = JsonConvert.DeserializeObject<BarRequest>(data);
            // use request.Category to process request
        }
    }
    

    这样我就不需要在客户端或服务器上接触任何模型、验证器等。此外,所有其他解决方案都要求我更改服务器端或客户端的命名约定。

    【讨论】:

    • 谢谢,这正是我正在寻找的答案,因为我想达到同样的结果。
    • 请记住,使用这种方法会丢失属性验证等功能。
    【解决方案3】:

    您可以通过使用 datacontracts 和 datamember 属性来做到这一点:

    http://msdn.microsoft.com/en-us/library/ms733127.aspx

    [DataContract]
    public class BarRequest{  
    
       [DataMember(Name="catid")]  
        public int CategoryId { get; set; }
    }
    

    如果是 Post 方法

    但使用 get 方法,这是复杂对象的结构示例:

    api/Bar?request.CategoryId =1&request.AnotherProp=foo
    

    【讨论】:

    • 试过了,结果和JsonProperty一样; CategoryId 仍为 0(默认值)。
    • 你应用这个方法:JsonConvert.DeserializeObject&lt;BarRequest&gt;(json);?
    • 你是什么意思?客户端是否应该通过 GET 发送 json?
    • json 也可以是一个帖子,它作为参数传递到您的控制器中
    • 请阅读最初的问题。我需要从 POST 切换到 GET。
    猜你喜欢
    • 2020-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-06
    • 2015-05-17
    • 1970-01-01
    相关资源
    最近更新 更多