8

I have an existing WebApi action, that I want to switch from HttpPost to HttpGet. It currently takes a single complex object as parameter.

The model:

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

The controller:

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

Now when I send the following request, everything works as expected.

GET /foo/bar?CategoryId=123

Also the old POST request worked as expected.

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

But now I need the following request to work:

GET /foo/bar?catid=123

How can I accomplish this?

Daniel Kuppitz
  • 10,846
  • 1
  • 25
  • 34
  • Why not just use CategoryID to do this? Or why just not use CatID as the property name, or use CatID as the parameter to the method? – Brian Mains Mar 25 '13 at 20:13
  • The real model has much more properties. Property naming can not be changed (naming guidelines on each side - server/c# and client/js). – Daniel Kuppitz Mar 25 '13 at 20:39
  • Does this answer your question? [How to make GET request with a complex object?](https://stackoverflow.com/questions/50215288/how-to-make-get-request-with-a-complex-object) – Michael Freidgeim Sep 03 '20 at 03:01
  • @MichaelFreidgeim - OP needs for the `CategoryId` property to be bound to `catid` so wouldn't [Changing the parameter name Web Api model binding](https://stackoverflow.com/q/26600275/3744182) be more closely related? – dbc Sep 06 '20 at 15:44

3 Answers3

12

Thanks for suggestions, but the only solution that works for me, is the following.

Before:

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

After:

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

This way I don't need to touch any model, validator, etc. on the client or server. Additionally every other solution required me to change the naming conventions on either the server or the client side.

Daniel Kuppitz
  • 10,846
  • 1
  • 25
  • 34
2

you can do it by using datacontracts and datamember attribute:

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

[DataContract]
public class BarRequest{  

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

if it's a Post method

but with get method this is an example of structure for complex objects :

api/Bar?request.CategoryId =1&request.AnotherProp=foo
Joan Caron
  • 1,969
  • 18
  • 21
0

There is an extension method on URI in System.Net.Http.UriExtensions that will do exactly what you want: TryReadQueryAs<T>(out T model). You can get the URI from your request in an ApiController: Request.RequestUri. Here's what it will look like:

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

This may only work if you specify a [DataContract] like Joan suggested.

Be aware however that an empty query string will parse, so if you used to do something different depending on whether data was POSTed or not, you will need to check the validity of your model. Hope you were doing that anyway though.

meustrus
  • 6,637
  • 5
  • 42
  • 53