I'm running a REST API service that has this action :
[HttpPost]
public FooResponse DoFoo(FooRequest request)
//public FooResponse DoFoo([FromBody] FooRequest request)
{
return null;
}
My request:
public class FooRequest
{
public string FooId;
}
I have an Angular client, that's making this call :
startFoo(fooId: string)
{
const url = `${this.baseUrl}StartFoo`;
const params = new HttpParams()
.set('FooId', fooId);
console.log(`params : ${params}`);
const result = this.httpClient.post<fooItem>(url, {params}).toPromise();
return result;
}
When I make the call from PostMan, the FooId is populated, when I call it from Angular, the endpoint is hit, but the param is always null. When I look in the console log, the parameters is there.
I've tried this solution, but it did not resolve my issue.
What am I missing?
You should add [FromBody] attribute in method .
[HttpPost]
public FooResponse DoFoo([FromBody] FooRequest request)
{
return null;
}
While you send the request to api, your request body must be in json format.
var fooRequest = { FooId : 1};
const result = this.httpClient.post<fooItem>(url, JSON.stringify(fooRequest) ).toPromise();
I did not try, I guess that It will work.
Related
I have a ASP.NET Core Web API and I'm having problems receiving my parameter in my controller method. I do receive the request parameter in the RetrieveMultipleEmployees method, but the Where property is null.
The sequence is as follows:
Create the StandardRequest<Employee> with the Where property defined.
Call the RetrieveMultipleEmployeesAsync method and pass the created StandardRequest<Employee>.
The RetrieveMultipleEmployeesAsync calls the RetrieveMultipleEmployeesRoute method and passes the request along.
The RetrieveMultipleEmployees controller method gets hit, the parameter is not null but the Where property is null.
Here is what I have:
Base controller:
[ApiController]
[Route("data/v{version:apiVersion}/[controller]/{action}")]
public class BaseController<TController> : ControllerBase
{
private IMediator _mediatorInstance;
protected IMediator _mediator => _mediatorInstance ??= HttpContext.RequestServices.GetService<IMediator>();
private ILogger<TController> _loggerInstance;
protected ILogger<TController> _logger => _loggerInstance ??= HttpContext.RequestServices.GetService<ILogger<TController>>();
}
EmployeesController:
public class EmployeesController : BaseController<EmployeesController>
{
[HttpGet]
[ActionName("retrievemultipleemployees")]
public async Task<IActionResult> RetrieveMultipleEmployees([FromQuery] StandardRequest<Employee> request)
{
var response = await _mediator.Send(new EmployeeQueries.RetrieveMultipleQuery() { Request = request });
return Ok(response);
}
}
StandardRequest:
public class StandardRequest<TEntity>
{
public Expression<Func<TEntity, bool>> Where { get; set; }
}
Url:
public static string RetrieveMultipleEmployeesRoute(StandardRequest<Employee> request)
{
var url = $"data/v1/employees/retrievemultipleemployees?{request}";
return url;
}
Request:
public async Task<StandardResult<List<EmployeeModel>>> RetrieveMultipleEmployeesAsync(StandardRequest<Employee> request)
{
var response = await _httpClient.GetAsync(EmployeeRoutes.RetrieveMultipleEmployeesRoute(request));
return await response.ToStandardResultAsync<List<EmployeeModel>>();
}
Where am I going wrong? Might it be something in my API setup?
Some advise on this would be greatly appreciated.
This bit of code looks suspect:
public static string RetrieveMultipleEmployeesRoute(StandardRequest<Employee> request)
{
var url = $"data/v1/employees/retrievemultipleemployees?{request}";
return url;
}
That is simply going to call ToString() on request, resulting in something like this being returned (assuming you haven't overridden it to create an actual query string):
data/v1/employees/retrievemultipleemployees?StandardRequest`[Employee]
Which is clearly bogus. You're going to need to convert that incoming request into a proper query string using something like QueryString.Create for example.
Is recommended to put your ComplexObject into a Class Library common to both projects the Client and the API
REQUESTOR
using Newtonsoft.Json;
using System.Net.Http.Headers;
private readonly string ExtractEpridDbcisinfo = "http://localhost:5281/domething";
public void consumeAPI(){
Uri uri = new Uri(*yourBaseURI*);
client.BaseAddress = uri;
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
string sParam1= JsonConvert.SerializeObject(complexobject,typeof(ComplexObject) ,null);
HttpResponseMessage response = client.GetAsync($"?paramComplexObject={sParam1}").Result;
.
.
.
GET REST API
[HttpGet]
[Route("domething")]
public IActionResult Index(string paramComplexObject){
ComplexObject complexObject = JsonConvert.DeserializeObject<ComplexObject>(paramComplexObject);
.
.
.
I have a RESTful service in .NET and i would like all actions return an object of type JsonResult, JsonResult is an object defined by me like this:
public class JsonResult<T>
{
public Notify Notify {get; set;}
public T Data {get; set;}
public static CreateResponse(T Data, Notify Notify = null, HttpStatusCode Code = HttpStatusCode.OK)
{
//Code param not manage, at the moment
return new JsonResult<T>
{
Data = Data,
Notify = Notify
};
}
}
public class Notify
{
public string Message {get; set;}
public Severity Severity {get; set;}
}
public enum Severity
{
Error,
Info,
Warning,
Fatal,
}
so at the moment i have actions look like that:
public JsonResult<string> Get()
{
return JsonResult<string>.CreateResponse("Ciao Mondo!");
}
it works and i like this form 'cause when i read the firm i already know what i want to return to the client (JsonResult, T is the type of my data)... but the problem is when i want to manage the status code.
Before to create this new project, to manage the status code i used the HttpResponseMessage and the method Request.CreateResponse to return some data to the client:
public HttpResponseMessage Get()
{
return Request.CreateResponse(HttpStatusCode.BadRequest, "Ciao Mondo!");
}
but i don't like that 'cause it is not immediate to know the returned type.
so... my question is... how can i manage the status code into my JsonResult.CreateResponse(T, Notify[, HttpStatusCode]) method?
this method is moved into an CustomApiController (inherits from ApiController), so i have HttpContext and Request available.
Thanks so much to all
You could call Content which accepts a HttpStatusCode as well as a generic object. It does require you to change your method's return type to IHttpActionResult which is generally preferred.
public IHttpActionResult Get()
{
if(someErrorCondition)
return Content(HttpStatusCode.BadRequest, JsonResult<string>.CreateResponse("Ciao Mondo!"));
return Ok(JsonResult<string>.CreateResponse("Ciao Mondo!"));
}
Its preferred to use IHttpActionResult, don't forcefully define it to
JsonResult. This should be configurable through content-negotiation.
You can try as below:
public IHttpActionResult Get()
{
if(error)
BadRequest("Bad Request !!");
return Ok("Ciao Mondo!");
}
Your answer were be very helpful. I was looking for another solution, but you gave me a good idea and i have found this solution:
public class CustomApiController : ApiController
{
public class JsonResult<Target> : NegotiatedContentResult<Target>
{
public JsonResult(HttpStatusCode statusCode, Json<Target> content, ApiController controller) : base(statusCode, content.Data, controller)
{
this.Content = content;
}
public JsonResult(HttpStatusCode statusCode, Target content, ApiController controller) : base(statusCode, content, controller)
{
}
public JsonResult(HttpStatusCode statusCode, Target content, IContentNegotiator contentNegotiator, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
: base(statusCode, content, contentNegotiator, request, formatters)
{
}
public new Json<Target> Content { get; private set; }
}
public JsonResult<Target> CreateResponse<Target>(Target Data, string Notify, HttpStatusCode Code = HttpStatusCode.OK)
{
Json<Target> json = new Json<Target>
{
Notify = Notify,
Data = Data
};
return new JsonResult<Target>(Code, json, this);
}
}
so i can inherit from CustomApiController and write action like that:
public JsonResult<IEnumerable<string>> Get(bool test)
{
if (test)
{
return this.CreateResponse(new string[] { "test1", "test2", "test3" } as IEnumerable<string>, null, System.Net.HttpStatusCode.OK);
}
else
{
return this.CreateResponse(new string[] { "test1", "test2", "test3" } as IEnumerable<string>, null, System.Net.HttpStatusCode.BadRequest);
}
}
thanks a lot!
In my WebApi I have a HttpGet and HttpPost method, the get method is working fine and the post method is called but the body content is always null, unless used in a HttpRequestMessage. I tried providing the body content in a string format(preferred datatype) aswell as in a model but neither one of those methods worked. I also tried switching the content type without success. Does anyone know if I'm doing something wrong or how I can easily get the variable data from the HttpRequestMessage, which in the example below is "test".
Method 1:
[System.Web.Http.HttpPost]
[Route("api/v1/AddItem")]
public IHttpActionResult AddItem([FromBody]string filecontent, string companycode)
{
MessageBox.Show(filecontent);
Return Ok("");
}
Method 2 (with model):
[System.Web.Http.HttpPost]
[Route("api/v1/AddItem")]
public IHttpActionResult AddItem([FromBody]ItemXML filecontent, string companycode)
{
MessageBox.Show(filecontent.XMLContent);
Return Ok("");
}
Model:
public class ItemXML
{
public ItemXML(string content)
{
XMLContent = content;
}
public string XMLContent { get; set; }
}
Method 3:
[System.Web.Http.HttpPost]
[Route("api/v1/AddItem")]
public IHttpActionResult AddItem(HttpRequestMessage filecontent, string companycode)
{
var content = filecontent.Content.ReadAsStringAsync().Result;
MessageBox.Show(content);
Return Ok("");
}
Method 3 content string ("test" is the provided value): " content "------WebKitFormBoundarydu7BJizb50runvq0\r\nContent-Disposition: form-data; name=\"filecontent\"\r\n\r\n\"test\"\r\n------WebKitFormBoundarydu7BJizb50runvq0--\r\n" string"
Create a model store data to be sent to server
public class Model {
public string filecontent { get; set;}
public string companycode { get; set;}
}
Update Action
[HttpPost]
[Route("api/v1/AddItem")]
public IHttpActionResult AddItem([FromBody]Model model) {
if(ModelStat.IsValid) {
return Ok(model); //...just for testing
}
return BadRequest();
}
On the client make sure the request is being sent properly. In this case going to use JSON.
public client = new HttpClient();
var model = new {
filecontent = "Hello World",
companycode = "test"
};
var response = await client.PostAsJsonAsync(url, model);
If using another type of client ensure that the data being sent is formatted correctly for the Web API action to accept the request.
Reference Parameter Binding in ASP.NET Web API
I am trying to support multiple Get() methods per controller, as well as just specially named methods accessible through web api. I have done this in MVC 5, but can't seem to figure out how it is done in MVC 6. Any ideas? Thanks.
You cannot have multiple Get methods with same url pattern. You can use attribute routing and setup multiple GET method's for different url patterns.
[Route("api/[controller]")]
public class IssuesController : Controller
{
// GET: api/Issues
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "item 1", "item 2" };
}
// GET api/Issues/5
[HttpGet("{id}")]
public string Get(int id)
{
return "request for "+ id;
}
// GET api/Issues/special/5
[HttpGet("special/{id}")]
public string GetSpecial(int id)
{
return "special request for "+id;
}
// GET another/5
[HttpGet("~/another/{id}")]
public string AnotherOne(int id)
{
return "request for AnotherOne method with id:" + id;
}
// GET api/special2/5
[HttpGet()]
[Route("~/api/special2/{id}")]
public string GetSpecial2(int id)
{
return "request for GetSpecial2 method with id:" + id;
}
}
You can see that i used both HttpGet and Route attributes for defining the route patterns.
With the above configuration, you you will get the below responses
Request Url : yourSite/api/issues/
Result ["value1","value2"]
Request Url : yourSite/api/issues/4
Result request for 4
Request Url : yourSite/api/special2/6
Result request for GetSpecial2 method with id:6
Request Url : yourSite/another/3
Result request for AnotherOne method with id:3
You can use attribute routing link this -
[Route("api/[controller]")] /* this is the defualt prefix for all routes, see line 20 for overridding it */
public class ValuesController : Controller
{
[HttpGet] // this api/Values
public string Get()
{
return string.Format("Get: simple get");
}
[Route("GetByAdminId")] /* this route becomes api/[controller]/GetByAdminId */
public string GetByAdminId([FromQuery] int adminId)
{
return $"GetByAdminId: You passed in {adminId}";
}
[Route("/someotherapi/[controller]/GetByMemberId")] /* note the / at the start, you need this to override the route at the controller level */
public string GetByMemberId([FromQuery] int memberId)
{
return $"GetByMemberId: You passed in {memberId}";
}
[HttpGet]
[Route("IsFirstNumberBigger")] /* this route becomes api/[controller]/IsFirstNumberBigger */
public string IsFirstNumberBigger([FromQuery] int firstNum, int secondNum)
{
if (firstNum > secondNum)
{
return $"{firstNum} is bigger than {secondNum}";
}
return $"{firstNum} is NOT bigger than {secondNum}";
}
}
See here for more detail - http://nodogmablog.bryanhogan.net/2016/01/asp-net-5-web-api-controller-with-multiple-get-methods/
I am consuming a web api wrote in c#, MVC, that looks like:
public IEnumerable<Day> Post([FromBody] string postObject)
Using fiddler or poster I can post to that REST service since my body has a = before my sending JSON, something like
={"BillTypeId":"4","RestId":"1"}
Using retrofit to make this call I can not send that initial = and my request looks like
{"BillTypeId":"4","RestId":"1"}
That makes the rest service receive always a null parameter.
Do you know a way to send it before my json? Since I am calling that rest like this
void postToGetDayList(#Body ResquestListenerBillType request, Callback<List<Day>> callback);
Thank you!!!
If you haven't fixed your issue, I think you can refer to my following code:
WebAPI:
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// POST api/values
public string Post([FromBody]string value)
{
return value;
}
}
Retrofit WebAPIService:
public interface WebAPIService {
#GET("/api/values")
List<String> listValues();
#POST("/api/values")
String postValues(#Body String value);
}
Call webAPIService.postValues("BNK");
You will find the result as the following image. Hope this helps!
before send class convert to string and add one " fist string and add one " on last string then send body
my client API is :
[Put("/WebPage/{key}/")]
Task<string> PutWebPage([AliasAs("key")]string id, [Body]string value);
sample code is :
WebPageModel webPageModelSave = new WebPageModel();
webPageModelSave = ObjectCopier.CloneClass(Public.CashEntity.webPageModel);
webPageModelSave.Address = uxLabel_AddressTitle.Text;
string codeingData = JsonConvert.SerializeObject(webPageModelSave);
codeingData = ArmanSerialize.CryptoString.Encrypt(codeingData, "5552552");
string resutlt = await Public.Helper.ApiServer.PutWebPage("123", "\""+codeingData+"\"");
and on server remove the " fist and last string like this:
// PUT api/<controller>/5
[HttpPut("{id}/")]
public string Put(string id, [FromBody]string value)
{
string removeCotation = value.Remove(value.Length - 1, 1).Remove(0, 1);
string valueItem = ArmanSerialize.CryptoString.Decrypt(value, "5552552");
string baseUrl = Request.Host.Host;
baseUrl = baseUrl.ToLower().Replace("http://", "").Replace("https://", "");
var serverID = 123;
if (id.Replace("\"", "") == serverID.Replace("\"","") && !string.IsNullOrEmpty(valueItem))
{
WebPageModel webPageModel = new WebPageModel();
webPageModel = JsonConvert.DeserializeObject<WebPageModel>(valueItem);
EntityFrameworkCore.LogicLayer logicLayer = new EntityFrameworkCore.LogicLayer();
logicLayer.UpdateWebPageModel(webPageModel);
return JsonConvert.SerializeObject("OK");
}
else
{
//error
return JsonConvert.SerializeObject("Error");
}
}
I test it on xamarin form and asp.net core 3 its work it.