Refit [FromQuery] with custom class not getting values - c#

I'm having a problem with a Get method in my Web API: The API gets the object but with the default values.
For instance:
myRefitClient.GetSummary(new MyClass() { Prop = 1 });
The Web API correctly receives a MyClass instance, but Prop is 0!
This is all that I have:
The Get method (Controller in the Web API):
[HttpGet]
async Task<ActionResult> Get([FromQuery]MyClass req)
MyClass is:
public class MyClass
{
public int Prop { get; set; }
}
and my Web API interface for Refit is:
public interface IMyWebApi
{
[Get("/api/mycontroller")]
Task<PositionSummary> GetSummary(MyClass req);
}
So, as I said, upon the call:
service.GetSummary(new MyClass() { Prop = 1 });
I'm getting a MyClass Instance in my Controller, but Prop is 0, instead of 1.
What am I doing wrong?

To force ASP.NET Web API (not ASP.NET Core) to read a complex type from the URI, add the [FromUri] attribute to the parameter:
[HttpGet]
public async Task<ActionResult> Get([FromUri]MyClass req)
If you are using ASP.NET Core then use [FromQuery] attribute
[HttpGet]
public async Task<ActionResult> Get([FromQuery]MyClass req)
I'm getting a MyClass Instance in my Controller, but Prop is 0,
instead of 1.
If /api/mycontroller is set as launchUrl in launchSettings.json then you will get MyClass Instance with Prop = 0 at the start of application. But next call using Refit should pass parameters

I think your problem is model binding. The way refit serializes your object and how API serialization/deserialization works should match. Refit has serialization settings, you need to adjust. can you look it that?
Take a look at :
https://reactiveui.github.io/refit/
Under JSON content section.
Similarly, your API should work with the same serialization settings. You can configure it at your services in Startup.cs

The solution was to implement IFormattable. Found that after going through the Refit source code, weird it's not documented.

Related

How can I bind simple type coming from body of the request in ASP.NET Core 5 Web API

I tried to send a JSON object with the same name that action argument has but It seems not working I don't know what I did wrong.
My question is how to bind simple types like the example shown, without the need to create complex type that wrap my value property?
Action
public IActionResult Test([FromBody] string value)
{
}
PostMan : raw > JSON
{
"value":"testValue"
}
public class MyRequest {
public string Value { get; set; }
}
//controller
IActionResult Test([FromBody] MyRequest request)
This should do the job.
The class/type related to the frombody object should match the whole json object and not only one property of it
This cannot work with GET requests, so try a POST

How to pass Byte Array as a class property to OData function in ASP.NET Web API?

I am using OData V4 with ASP.NET Web API. After doing a lot of research and experiments I am still not able to pass the Byte array (byte[]) as a class model property. I am not sure that how the .Net Framework is receiving it as a string. But when I configure the controller action to receive only the Byte array (byte[]) parameter then it receives the correct data. It does not receive it as a class property.
Here is my class model.
public class TempFileModel
{
public string Name { get; set; }
public byte[] Content { get; set; }
}
Here is the OData model configuration:
public class TransientFileConfiguration : IModelConfiguration
{
public void Apply(ODataModelBuilder builder, ApiVersion apiVersion, string routePrefix)
{
builder.EntitySet<TransientFileModel>("TransientFiles");
builder.EntityType<TransientFileModel>().HasKey(e => e.Key);
builder.Action("UploadFile")
.Returns<List<string>>()
.CollectionParameter<TempFileModel>("file");
}
}
My Controller action for this:
[HttpPost]
[ODataRoute("UploadFile")]
public async Task<IHttpActionResult> UploadFile(ODataActionParameters parameters)
{
var paramValue = parameters["file"];
return Ok(new List<string>());
}
The error I get every time:
Error Message: "Invalid cast from 'System.String' to 'System.Byte[]'."
Here are few links that I have searched for unbound action using OData API and working with this issue:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/odata-actions-and-functions
https://learn.microsoft.com/en-us/odata/webapi/action-parameter-support
How to pass Array to OData function in ASP.NET Web API implementation?
How to make an unbound POST action in webapi 2.2 odata
A question on StackOverflow with similar context maybe (just to understand the issue):
Pass two byte array to asp.net web api post method

asp.net - how to get value from post method

In asp.net app i receive a form values from angular app.
[HttpPost]
public IActionResult addChange([FromBody] Change change)
{
return Json(change.Status);
}
How to get object or some value of object to use it in another class?
You should be able to access property like that: change.PropertyName.
But you might send data from angular as FormData, then you should change [FromBody] to [FromForm].
It's most likely that you are doing something wrong at angular site. You should check this endpoint via postman.
Edit:
To use this object in another method you should pass it through.
[HttpPost]
public IActionResult addChange([FromBody] Change change)
{
AnotherMethod(change);
return Json(change.Status);
}
public void AnotherMethod(Change change)
{
var foo = change.Status;
}

ASP.NET Core API - Dynamic Routing (Make API route behave like "one-parameter query string")

Aloha :D
I would like to create a dynamic route binding.
What I mean by this, is basically replacing the Query String with a dynamic route.
Example:
Instead of this:
POST http://localhost:5000/api/documents?templatename=individualemploymentagreement
this:
POST http://localhost:5000/api/documents/individualemploymentagreement
Note: after "http://localhost:5000/api/documents/" I want to put anything I want, but this route will always be used and what comes after should be used like a variable. Obviously, this will lead to a non-existing API Route at the moment. But is there any way to deal with this?
Note 2: The reasons I want to use this are:
- According to RESTful services "rules", query strings should be used just for queries, In this case I'm not using a query, I'm calling a generic document service, which however, treats every document slightly different when needed. So query strings are not recommended in my case.
- This service will deal with hundreds of document types, so I can't really make a different path / api for each one of them. So this is not recommended as well.
My code (In which I'm using a query string for {templateName}:
namespace DocumentGenerator.Api.Controllers
{
[Route("api/{controller}")]
[ApiController]
public class DocumentsController : ControllerBase
{
//useless details
[HttpPost]
public async Task<IActionResult> Generate([FromQuery] string templateName, [FromBody] object properties)
{
// according to {templateName} do this or that...
// useless details
}
}
}
What I would want in code:
namespace DocumentGenerator.Api.Controllers
{
[Route("api/{controller}")]
[ApiController]
public class DocumentsController : ControllerBase
{
//useless details
[HttpPost("{templateName}"]
public async Task<IActionResult> Generate([FromBody] object properties)
{
// according to {templateName} do this or that...
// useless details
}
}
}
You can specify the parameter name as a route attribute value in HttpPost :
[HttpPost("{templateName}"]
public async Task<IActionResult> Generate(string templateName, [FromBody] object properties)
{
}
or even
[HttpPost("/api/documents/{templateName}"]
public async Task<IActionResult> Generate(string templateName, [FromBody] object properties)
{
}

Correct way to call WebApi RTM from an mvc4 application

So there is a heap of examples around but finding ones that are relevant to the rtm bits seems to be a little harder to find.
I have 2 projects one is an WebApi & the other is MVC4 .net 4.5 application.
I want to make a make an update to an item
I have a controller within my API that does something like
[HttpPut]
public MyModel Update(MyModel model)
{
//make update
return model;
}
Is this correct? should I be using a HttpResponseMessage instead of just using my MyModel class? I want to return the correct httpstatus details as much as possible as I am wanting to open up this api to 3rd parties not just my application
Calling this api from my mvc application from my controller how do I do this?
The beste way is to use HttpResponseMessage like this:
[HttpPut]
public HttpResponseMessage Update(MyModel model)
{
if(notfound)
{
return this.Request.CreateResponse(HttpStatusCode.NotFound);
}
//make update
return this.Request.CreateResponse<MyModel>(HttpStatusCode.OK, Model);;
}
I mostly use EasyHttp if I want want to call a WebApi method from my MVC app:
var model = new ExpandoObject(); // or use a stronly typed class.
model.Id = 1,
model.Name = "foo"
var http = new HttpClient();
http.Post("url", model, HttpContentTypes.ApplicationJson);
If you want to respond with httpstaus code you have to return HttpResponseMessage.
You may choose to have a common method returning your BOs and call it from the Action and from your other mvc application code. Then your rest calls would always be wrapped with a status code and other calls get an object.
[HttpPut]
public MyModel Update(MyModel model)
{
return base.Request.CreateResponse<MyModel>(HttpStatusCode.OK, UpdateModel(model));;
}
[NonAction]
internal MyModel UpdateModel(MyModel model)
{
//make update
return model;
}

Categories