Unable to call web api PUT method - asp.net

[System.Web.Http.Route("{id}")]
[System.Web.Http.HttpPut]
public async Task<ComplaintVM> Put(int id,int? employeeId)
{
var obj = _resolver.GetService<Complaint>();
obj.FranchiseId = 1;
obj.Id = id;
await obj.GetDetailAsyc();
obj.EmployeeId = employeeId;
await obj.AllocateAndManageCallAsyc();
return obj.EntityToVM();
}
This is put method with [System.Web.Http.RoutePrefix("api/app/complaint")]
so when i call my method with a PUT request i get the following error "message: "The requested resource does not support http method 'PUT'.".
but when i make the same call when the method does not have int? employeeId parameter. The call happens fine.
I am passing the employeeId as a json formatted request. I am using fiddler to test the code

The issue with Put(int id,int? employeeId) is the variable int? employeeId, since it was not part of the URL the model binder was not able to bind the attribute and hence was not able call the method with 2 parameters.
Using the [FormBody] did not work, the value returned was null, this is because the input was in form of a json.
The issue was solved by using a parameter of type Employee which had a property of EmployeeId so the value was mapped to the EmployeeId of the employee object, the method signature is Put(int id,Employee employee),
if there is no model class to bind, a parameter of type JObject can used as a input parameter and later the value can be extracted from JObject.

Related

How to pass value to a [FormBody] variable from RestAssured?

I have a web api method as given below
// POST api/values
public void Post([FromBody] string value)
{
names = names.Concat( new string[] { value } ).ToArray();
}
I would like to pass value to a "value" variable from RestAssured, I tried with the following RestAssured code and it did not work ( value is not getting passed)
request.contentType(ContentType.JSON);
JSONObject jsonobj = new JSONObject();
jsonobj.put("value",new String("test45#test.com"));
request.body(jsonobj.toString());
// Get Response and verify the status code
Response response = restAssuredManager.getAPIResponse(request, "Api/Values",RequestPostType.Post);
It is observed that the value "test45#test.com" is not getting binded with the "value" variable in Post method. however I could send the value from Postmain tool ( selected content-type as json and provided "rajkumar" as value in "raw" tab)
I was expecting the value to be passed from RestAssured code.

Can I disable model binding and use the raw request body in an action in dotnet core?

I want to setup an endpoint for testing webhooks from third parties. Their documentation is uniformly poor and there is no way ahead of time to tell exactly what I will be getting. What I've done is setup an ApiController that will just take a request and add a row to a table with what they are sending. This lets me at least verify they are calling the webhook, and to see the data so I can program to it.
// ANY api/webook/*
[Route("{*path}")]
public ActionResult Any(string path)
{
string method = Request.Method;
string name = "path";
string apiUrl = Request.Path;
string apiQuery = Request.QueryString.ToString();
string apiHeaders = JsonConvert.SerializeObject(Request.Headers);
string apiBody = null;
using (StreamReader reader = new StreamReader(Request.Body))
{
apiBody = reader.ReadToEnd();
}
Add(method, name, apiUrl, apiQuery, apiHeaders, apiBody);
return new JsonResult(new { }, JsonSettings.Default);
}
This works great, except for this new webhook I am usign that posts as form data so some middleware is reading the body and it ends up null in my code. Is there any way to disable the model processing so I can get at the request body?
You could actually use model binding to your advantage and skip all that stream reading, using the FromBody attribute. Try this:
[Route("{*path}")]
[HttpPost]
public ActionResult Any(string path, [FromBody] string apiBody)

Query string parameter vs regular parameter ASP.Net MVC 5

I have been working on desktop applications mostly and thought to learn web development using ASP.Net MVC5 and thus going through the book by Jon Galloway. So I was reading about how you can pass the parameters to action methods using query string like
/Store/Browse?genre=Disco
or directly embed them in the url like
/Store/Details/5
Now the controller code that I wrote (taken from book) is below :
namespace MvcMusicStore.Controllers
{
public class StoreController : Controller
{
// GET: Store
public string Index()
{
return "Hello from Store.Index()";
}
public string Browse(string genre)
{
string message = HttpUtility.HtmlEncode("Store.Browser, Genre = " + genre);
return message;
}
public string Details(int id)
{
string message = "Store.Details, ID = " + id;
return message;
}
}
}
The url opens fine and the actions return the message as expected. But just to try I tried to pass the genre value by embedding it in the url like
/Store/Browse/Rap
but that doesn't work like it did for the Details() action. I thought it may have to do something with the datatype of genre, so I tried changing the data type of id in Details() to string as below :
public string Details(string id)
{
string message = "Store.Details, ID = " + id;
return message;
}
}
and opened the url
/Store/Details/5
and the Details() action returns message with id value 5, but when i do the same for Browse() action
/Store/Browse/Rap
the action doesn't return the message with genre value "Rap". I tried to pass the genre value and removed the html encoding to see if that had anything to do with it, but it didn't.
I looked at the post here but that didn't help either. Any comments appreciated.
Your using the Default route which is defined as
url: "{controller}/{action}/{id}",
and expects a value for id. When you use /Store/Browse/Rap, then the value of the 3rd segment ("Rap") will be bound to a paramater named id, but your Browse() method does not contain one (its named genre).
Either change the name of the parameter so its
public string Browse(string id)
and the value of id will be "Rap",
Or create a specific route definition and place it before the Default route (and keep the Browse() method as is)
routes.MapRoute(
name: "Browse",
url: "Store/Browse/{genre}",
defaults: new { controller = "Store", action = "Browse", genre = UrlParameter.Optional }
);
... // default route here
Side note: You do not need to change the type of the parameter in the Details method if your always passing a value that is a valid int

Send object as parameter in client.PutAsync

I am facing a problem in using PutAsync. PutAsync update an object. Below is my code. (Mongodb database)
Controller Code:
stringData = JsonConvert.SerializeObject(businessUnit); //businessUnit is updated object
var contentData = new StringContent(stringData, System.Text.Encoding.UTF8, "application/json");
response = client.PutAsync(baseAddress + "/api/BusinessUnit/" + businessUnit.Id, contentData).Result;
API Controller Code :
[HttpPut("{id}")]
public async Task<string> Put(string id, BusinessUnit businessUnit)
{
if (string.IsNullOrEmpty(id)) return "Invalid id !!!";
return await _businessUnitRepository.Update(id, businessUnit);
}
Given code works good but my problem is in API controller businessUnit parameter's all fields become null instead of id.
My Confusion is, if businessUnit parameter's all fields are null then why its primary key "id" is not null ??
I want to get all fields as parameter in businessUnit object from controller to api controller. How can I do it?
Thanks in advance.
Add the [FromBody] attribute to the 'businessUnit' parameter:
public async Task<string> Put(string id, [FromBody] BusinessUnit businessUnit)
This is called an Model Binding and allows to map data from HTTP requests to action method parameters:
[FromBody]: Use the configured formatters to bind data from the request body. The formatter is selected based on content type of the request.

How to set content type dynamically in a Spring MVC controller (depending on presence of request param)?

I have a REST API that until now always returned JSONP (JSON data wrapped in whatever function call client wanted):
static final String JAVASCRIPT = "application/javascript;charset=UTF-8";
#RequestMapping(value = "/matches", produces = JAVASCRIPT)
#ResponseBody
public String matches(#RequestParam String callback) {
String json = jsonService.getCachedJson("/matches");
return toJsonp(callback, json);
}
Now, things have changed so that I need to return either JSON or JSONP: if client provides a callback function name, we return JSONP and otherwise pure JSON.
With regards to content type, I'd like to be as correct as possible and use application/json for JSON and application/javascript for JSONP.
So, something like this:
#RequestMapping(value = "/matches")
#ResponseBody
public String matches(#RequestParam(required = false) String callback) {
String json = jsonService.getCachedJson("/matches");
// TODO: if callback == null, set content type to "application/json",
// otherwise to "application/javascript"
return jsonOrJsonp(callback, json);
}
String jsonOrJsonp(String callback, String json) {
return Strings.isNullOrEmpty(callback) ? json : toJsonP(callback, json);
}
Looks like I can no longer use produces attribute of #RequestMapping. What's the simplest way to set content type with Spring MVC in the scenario above?
I'd like to avoid defining HttpMessageConverters (or other Spring hassle) or changing the method return type, if at all possible! And obviously I wouldn't like duplicated method declarations where produces value is the only significant difference. What I'm looking for is minimal changes to the above code.
Latest Spring (3.2.3).
Have you tried just using two request handler methods?
#RequestMapping(value = "/matches", produces = JAVASCRIPT, params="callback")
#ResponseBody
public String Jsonp(#RequestParam String callback) {
return toJsonp(callback, jsonService.getCachedJson("/matches"));
}
#RequestMapping(value = "/matches", produces = JSON)
#ResponseBody
public String json() {
return toJson(jsonService.getCachedJson("/matches"));
}
The first method with the params parameter will only be mapped to requests where the callback param is present.

Resources