I have a basic question about basics on Web Api. FYI, I have checked before but could not found what I was looking for.
I have a piece of code as described below these lines. Just like any other Method in general terms my method called: Post, it has to return something,a JSON for example, How do I do that.
Specifically, what am I supposed to write after the word " return " in order to get the 3 fields( loginRequest.Username,loginRequest.Password,loginRequest.ContractItemId ) as Json.
Coments: Do not worry about username,password and contractID are in comments, I do get their value in my LinQ. It's just the return whta I nened now, greetings to all who would like to throw some notes about this.
[System.Web.Http.HttpPost]
public HttpResponseMessage Post(LoginModel loginRequest)
{
//loginRequest.Username = "staw_60";
//loginRequest.Password = "john31";
//loginRequest.ContractItemId = 2443;
try
{
Membership member =
(from m in db.Memberships
where
m.LoginID == loginRequest.Username
&& m.Password == loginRequest.Password
&& m.ContractItemID == loginRequest.ContractItemId
select m).SingleOrDefault();
}
catch (Exception e)
{
throw new Exception(e.Message);
}
return ???;
}
Try this:
HttpResponseMessage response = new HttpResponseMessage();
response.Content = new ObjectContent<Response>(
new Response() {
responseCode = Response.ResponseCodes.ItemNotFound
},
new JsonMediaTypeFormatter(), "application/json");
or just create another response from Request object itself.
return Request.CreateResponse<Response>(HttpStatusCode.OK,
new Response() { responseCode = Response.ResponseCodes.ItemNotFound })
You can also turn all your response types to JSON by updating the HttpConfiguration(Formatter.Remove) just remove the default xml serialization and put JSON.
You could perhaps create a LoginResponseModel class that you can use to send back information to the caller about the success/failure of the login attempt. Something like:
public class LoginResponseModel
{
public bool LoginSuccessful {get; set;}
public string ErrorMessage {get; set;}
public LoginResponseModel()
{
}
}
Then you can return this directly from the controller if you like:
[System.Web.Http.HttpPost]
public LoginResponseModel Post(LoginModel loginRequest)
{
...
return new LoginResponseModel() { LoginSuccessful = true, ErrorMessage = "" };
}
Or you can still use a HttpResponseMessage as return type, but send a LoginResponseModel as the json response:
[System.Web.Http.HttpPost]
public HttpResponseMessage Post(LoginModel loginRequest)
{
...
var resp = Request.CreateResponse<LoginResponseModel>(
HttpStatusCode.OK,
new LoginResponseModel() { LoginSuccessful = true, ErrorMessage = "" }
);
return resp;
}
Related
I need to save the changes I make in my model through API call in my database. I have checked my API is working fine when I am running it individually on Web. But its giving me an error StatusCode: 405, ReasonPhrase: 'Method Not Allowed'. I am trying to send and object and trying to see whether the request made was completed or not. When I am trying to debug it, it is not sending hit on my API controller.
Here is my model class:
public class Customer
{
[Required]
public Guid CustomerId { get; set; }
public int Age { get; set; }
public int Phone { get; set; }
}
PUT Method in API:
[HttpPut]
[Route("api/[controller]/{customer}")]
public IActionResult EditCustomer(Customer customer)
{
var cust = _customerData.EditCustomer(customer);
if (cust == string.Empty)
{
return Ok();
}
else
{
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
}
}
The method I am using in project to call API:
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(apiBaseUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")
);
var sum = await client.PutAsJsonAsync("api/Customer/", customer);
if (sum.StatusCode == System.Net.HttpStatusCode.OK)
{
return RedirectToActionPermanent(actionName: "SingIn");
}
else
{
TempData["msg"] = "There is an error";
return View();
}
where baseaddress= {https://localhost:44398/}
EditCustomer Method
public string EditCustomer(Customer customer)
{
try
{
var pro = _customerContext.Customer.Where(e => e.CustomerId == customer.CustomerId).FirstOrDefault();
pro.Age = customer.Age;
pro.Phone = customer.Phone;
pro.Name = customer.Name;
_customerContext.Entry(pro).State = EntityState.Modified;
_customerContext.SaveChanges();
}
catch(Exception e)
{
return e.Message;
}
return string.Empty;
}
You need to fix your action route by removing {Customer}, since you send customer in request body, not as a route value
[Route("~/api/Customer")]
and request
var sum = await client.PutAsJsonAsync("/api/Customer", customer);
or better fix the acttion route name to meaningfull
[Route("~/api/EditCustomer")]
and
var sum = await client.PutAsJsonAsync("/api/EditCustomer", customer);
AsJsonAsync sometimes causes problems
try this code
var json = JsonSerializer.Serialize(customer);
//or if you are using Newtonsoft
var json = JsonConvert.SerializeObject(customer);
var contentData = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PutAsync("/api/Customer", contentData);
if (response.IsSuccessStatusCode)
return RedirectToActionPermanent("SingIn");
else
{
TempData["msg"] = "There is an error";
return View();
}
but IMHO I would prefer to use
client.PostAsync("/api/EditCustomer", contentData);
instead of Put.
and added [FromBody] to action
[HttpPost("~/api/EditCustomer")]
public IActionResult EditCustomer([FromBody] Customer customer)
I am no pro in web APIs but I suspect it could be due to the fact that the API expects customer to be in request URL.
Try and change the API route to [Route("api/[controller]")]
This could've been a comment but I don't have enough reputation :)
I am trying to create a simple web API.
I have data going into the controller but I can't return it in the JSON API. I think the problem is returning the IEnumerable String.
BLL:
public IEnumerable<DTO.Gettod> Gettods()
{
DAL.todDataController tdc = new DAL.todDataController();
return tdc.GetToddMobiles();
}
Model:
public class TodViewModel
{
public IEnumerable<DTO.Gettod> ModelGetTod { get; set; }
}
Controller:
public IEnumerable<string> Get()
{
BLL.todManager tm = new BLL.todManager();
Models.TodViewModel tvm = new Models.TodViewModel();
tvm.ModelGetTod = tm.Gettods().ToArray();
return tvm as IEnumerable<string>;
}
JSON file returns only a Null but I'm expecting an Array.
The Correct Code is below, crediting: Bruno in the below answer:
public IHttpActionResult GetToddData()
{
BLL.todManager tm = new BLL.todManager();
Models.TodViewModel tvm = new Models.TodViewModel();
tvm.ModelGetTod = tm.Gettods().ToList();
//HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, tvm.ModelGetTod as IEnumerable<string>);
return Ok(tvm.ModelGetTod);
}
Try changing your controller to the below:
Edit: Changing the accepted answer to what worked for the user
public IHttpActionResult GetToddData () {
BLL.todManager tm = new BLL.todManager ();
Models.TodViewModel tvm = new Models.TodViewModel ();
tvm.ModelGetTod = tm.Gettods ().ToList ();
//HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, tvm.ModelGetTod as IEnumerable<string>);
return Ok (tvm.ModelGetTod);
}
Also, debug and see if you are getting the expected values in the tvm.ModelGetTod property.
I want to post data form my code but no data changed . when I debug the code it got me 200 which mean code is good . I tried to test in fiddler and data is changed successfully . I want to know where is the wrong ?
this is my service including url
public static async Task<string> PostOrderAsync(MachinePostModel Order)
{
try
{
var client = new HttpClient();
string data = JsonConvert.SerializeObject(Order);
var content = new StringContent(data, Encoding.UTF8, "application/json");
var response = await client.PostAsync("http://94.205.253.150:2016/api/JobOrder", content);
return data;
}
catch
{
return null;
}
}
and this is the step where i send order object
private async Task<bool> AcceptPostOrder()
{
MachinePostModel OrderDetails = new MachinePostModel();
try
{
OrderDetails.ID = 1163;
OrderDetails.joStatus = "should to wait";
OrderDetails.remarks = "hello remarks";
var Client = await Services.MachineTestPostService.PostOrderAsync(OrderDetails);
return true;
}
catch (Exception exc)
{
await MachineTestOrderView.machineobj.DisplayAlert("Alert", exc.Message, "OK");
return false;
}
}
finally my model
public class MachinePostModel
{
public int ID { get; set; }
public string remarks { get; set; }
public string joStatus { get; set; }
}
Get link to check if data is changed
http://94.205.253.150:2016/api/JobOrder/Get?regId=1&driverID=35&status=All%20Status
There are some mistakes in your code. Firstly, decorate your action with HttpPost attribute and add a parameter for sent complex object.
[HttpPost]
private async Task<bool> AcceptPostOrder(MachinePostModel Order)
{
MachinePostModel OrderDetails = new MachinePostModel();
try
{
OrderDetails.ID = 1163;
OrderDetails.joStatus = "should to wait";
OrderDetails.remarks = "hello remarks";
var Client = await Services.MachineTestPostService.PostOrderAsync(OrderDetails);
return true;
}
catch (Exception exc)
{
await MachineTestOrderView.machineobj.DisplayAlert("Alert", exc.Message, "OK");
return false;
}
}
And, there is no routing definition as api/JobOrder, so I assume that you are trying to post the data AcceptPostOrder method. Change the request endpoint;
var response = await client.PostAsync("http://94.205.253.150:2016/api/AcceptPostOrder", content);
I'm trying to return an HttpResponseException from a POST Web API action using 'Request':
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.NotFound, "File not in a correct size"));
When doing so, I get Value cannot be null. Parameter name: request.
Essentially - Request is null.
What am I missing?
Thank you
I found that my Request object was null within my ApiController because I have nested one ApiController call within another. The second, nested ApiController was therefore never initialized. You can't initialize it manually, but you can leverage the setter on the Request object to pass from wrapper to nested ApiController. A mockup is below, in my real code it fixed my Request.CreateErrorResponse(...) error.
public class WrapperController : ApiController
{
// POST api/wrapper
public void Post(ComplexWithChild value)
{
var other = value.otherdata;
var childcontroller = new ChildController();
childcontroller.Post(value.child); // ChildController is not initialized, and has null Request
/*inside ChildController...// causes null reference exception due to null Request
Request.CreateErrorResponse(HttpStatusCode.BadRequest, "my message");
*/
childcontroller.Request = this.Request;
childcontroller.Post(value.child); // ChildController uses same Request
/*inside ChildController...// this works now
Request.CreateErrorResponse(HttpStatusCode.BadRequest, "my message");
*/
}
}
public class ChildController : ApiController
{
public void Post(Child value)
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "my message"));
}
}
Use this:
HttpResponseMessage message = new HttpResponseMessage(HttpStatusCode.InternalServerError);
message.Content = new ObjectContent(typeof(MessageResponse), "Invalid Size", GlobalConfiguration.Configuration.Formatters.JsonFormatter);
throw new HttpResponseException(message);
Note: you can change "Invalid Size" with any object you may want to return for the user.
e.g.:
public ErrorMessage
{
public string Error;
public int ErrorCode;
}
ErrorMessage msg = new ErrorMessage();
msg.Error = "Invalid Size";
msg.ErrorCode = 500;
HttpResponseMessage message = new HttpResponseMessage(HttpStatusCode.InternalServerError);
message.Content = new ObjectContent(typeof(MessageResponse), msg, GlobalConfiguration.Configuration.Formatters.JsonFormatter);
throw new HttpResponseException(message);
Another solution for people like #DavB.cs who have nested ApiControllers like:
public class ParentController : ApiController
{
public IHttpActionResult Foo()
{
ChildRepository.Foo();
return Ok(...);
}
}
public class ChildRepository : ApiController
{
public HttpResponseMessage Foo()
{
// Do something
return Request.CreateResponse(...);
}
}
Is simply to just pass in Request from the ParentController as such:
public class ParentController : ApiController
{
public IHttpActionResult Foo()
{
ChildRepository.Foo(Request);
return Ok(...);
}
}
public class ChildRepository
{
public HttpResponseMessage Foo(HttpRequestMessage request)
{
// Do something
return request.CreateResponse(...);
}
}
Request comes from ApiController. This will get you past the 'Request is null' issue.
Hope this helps someone.
nizari's answer is correct however I ended up using the following:
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("Invalid image dimensions. Image file must be " + image.Width + "x" + image.Height + "px"),
StatusCode = HttpStatusCode.Forbidden
});
and accessing the content on client side using jqXHR.responseText
Thanks everyone!
Expanding on nizari's answer, Here's what I did in order to include a list of ErrorMessage objects:
IEnumerable errorList = new List<ErrorMessage>();
// ...
var error = new HttpError( "There were errors." )
{
{ "Errors", errorList }
};
var message = new HttpResponseMessage( HttpStatusCode.BadRequest )
{
Content = new ObjectContent<HttpError>( error, GlobalConfiguration.Configuration.Formatters.JsonFormatter )
};
throw new HttpResponseException( message );
you have to create a new instance of the System.Net.Http.HttpRequestMessage. the below would work
var request = new HttpRequestMessage();
var response = request.CreateErrorResponse(HttpStatusCode.NotFound, "File not in a correct size");
throw new HttpResponseException(response);
HttpResponseMessage message = new HttpResponseMessage(HttpStatusCode.InternalServerError);
message.Content = new ObjectContent(typeof(MessageResponse),
"Invalid Size",
GlobalConfiguration.Configuration.Formatters.JsonFormatter);
throw new HttpResponseException(message);
I'm trying to return a status code of 304 not modified for a GET method in a web api controller.
The only way I succeeded was something like this:
public class TryController : ApiController
{
public User GetUser(int userId, DateTime lastModifiedAtClient)
{
var user = new DataEntities().Users.First(p => p.Id == userId);
if (user.LastModified <= lastModifiedAtClient)
{
throw new HttpResponseException(HttpStatusCode.NotModified);
}
return user;
}
}
The problem here is that it's not an exception, It's just not modified so the client cache is OK.
I also want the return type to be a User (as all the web api examples shows with GET) not return HttpResponseMessage or something like this.
I did not know the answer so asked the ASP.NET team here.
So the trick is to change the signature to HttpResponseMessage and use Request.CreateResponse.
[ResponseType(typeof(User))]
public HttpResponseMessage GetUser(HttpRequestMessage request, int userId, DateTime lastModifiedAtClient)
{
var user = new DataEntities().Users.First(p => p.Id == userId);
if (user.LastModified <= lastModifiedAtClient)
{
return new HttpResponseMessage(HttpStatusCode.NotModified);
}
return request.CreateResponse(HttpStatusCode.OK, user);
}
You can also do the following if you want to preserve the action signature as returning User:
public User GetUser(int userId, DateTime lastModifiedAtClient)
If you want to return something other than 200 then you throw an HttpResponseException in your action and pass in the HttpResponseMessage you want to send to the client.
Change the GetXxx API method to return HttpResponseMessage and then return a typed version for the full response and the untyped version for the NotModified response.
public HttpResponseMessage GetComputingDevice(string id)
{
ComputingDevice computingDevice =
_db.Devices.OfType<ComputingDevice>()
.SingleOrDefault(c => c.AssetId == id);
if (computingDevice == null)
{
return this.Request.CreateResponse(HttpStatusCode.NotFound);
}
if (this.Request.ClientHasStaleData(computingDevice.ModifiedDate))
{
return this.Request.CreateResponse<ComputingDevice>(
HttpStatusCode.OK, computingDevice);
}
else
{
return this.Request.CreateResponse(HttpStatusCode.NotModified);
}
}
*The ClientHasStale data is my extension for checking ETag and IfModifiedSince headers.
The MVC framework should still serialize and return your object.
NOTE
I think the generic version is being removed in some future version of the Web API.
In MVC 5, things got easier:
return new StatusCodeResult(HttpStatusCode.NotModified, this);
For ASP.NET Web Api 2, this post from MS suggests to change the method's return type to IHttpActionResult. You can then return a built in IHttpActionResult implementation like Ok, BadRequest, etc (see here) or return your own implementation.
For your code, it could be done like:
public IHttpActionResult GetUser(int userId, DateTime lastModifiedAtClient)
{
var user = new DataEntities().Users.First(p => p.Id == userId);
if (user.LastModified <= lastModifiedAtClient)
{
return StatusCode(HttpStatusCode.NotModified);
}
return Ok(user);
}
I hate bumping old articles but this is the first result for this in google search and I had a heck of a time with this problem (even with the support of you guys). So here goes nothing...
Hopefully my solution will help those that also was confused.
namespace MyApplication.WebAPI.Controllers
{
public class BaseController : ApiController
{
public T SendResponse<T>(T response, HttpStatusCode statusCode = HttpStatusCode.OK)
{
if (statusCode != HttpStatusCode.OK)
{
// leave it up to microsoft to make this way more complicated than it needs to be
// seriously i used to be able to just set the status and leave it at that but nooo... now
// i need to throw an exception
var badResponse =
new HttpResponseMessage(statusCode)
{
Content = new StringContent(JsonConvert.SerializeObject(response), Encoding.UTF8, "application/json")
};
throw new HttpResponseException(badResponse);
}
return response;
}
}
}
and then just inherit from the BaseController
[RoutePrefix("api/devicemanagement")]
public class DeviceManagementController : BaseController
{...
and then using it
[HttpGet]
[Route("device/search/{property}/{value}")]
public SearchForDeviceResponse SearchForDevice(string property, string value)
{
//todo: limit search property here?
var response = new SearchForDeviceResponse();
var results = _deviceManagementBusiness.SearchForDevices(property, value);
response.Success = true;
response.Data = results;
var statusCode = results == null || !results.Any() ? HttpStatusCode.NoContent : HttpStatusCode.OK;
return SendResponse(response, statusCode);
}
.net core 2.2 returning 304 status code. This is using an ApiController.
[HttpGet]
public ActionResult<YOUROBJECT> Get()
{
return StatusCode(304);
}
Optionally you can return an object with the response
[HttpGet]
public ActionResult<YOUROBJECT> Get()
{
return StatusCode(304, YOUROBJECT);
}
I don't like having to change my signature to use the HttpCreateResponse type, so I came up with a little bit of an extended solution to hide that.
public class HttpActionResult : IHttpActionResult
{
public HttpActionResult(HttpRequestMessage request) : this(request, HttpStatusCode.OK)
{
}
public HttpActionResult(HttpRequestMessage request, HttpStatusCode code) : this(request, code, null)
{
}
public HttpActionResult(HttpRequestMessage request, HttpStatusCode code, object result)
{
Request = request;
Code = code;
Result = result;
}
public HttpRequestMessage Request { get; }
public HttpStatusCode Code { get; }
public object Result { get; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Request.CreateResponse(Code, Result));
}
}
You can then add a method to your ApiController (or better your base controller) like this:
protected IHttpActionResult CustomResult(HttpStatusCode code, object data)
{
// Request here is the property on the controller.
return new HttpActionResult(Request, code, data);
}
Then you can return it just like any of the built in methods:
[HttpPost]
public IHttpActionResult Post(Model model)
{
return model.Id == 1 ?
Ok() :
CustomResult(HttpStatusCode.NotAcceptable, new {
data = model,
error = "The ID needs to be 1."
});
}
Try this :
return new ContentResult() {
StatusCode = 404,
Content = "Not found"
};
If you need to return an IHttpActionResult and want to return the error code plus a message, use:
return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.NotModified, "Error message here"));
Another option:
return new NotModified();
public class NotModified : IHttpActionResult
{
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage(HttpStatusCode.NotModified);
return Task.FromResult(response);
}
}
public HttpResponseMessage Post(Article article)
{
HttpResponseMessage response = Request.CreateResponse<Article>(HttpStatusCode.Created, article);
string uriToTheCreatedItem = Url.Route(null, new { id = article.Id });
response.Headers.Location = new Uri(Request.RequestUri, uriToTheCreatedItem);
return response;
}
An update to #Aliostads answer using the more moden IHttpActionResult introduced in Web API 2.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/action-results#ihttpactionresult
public class TryController : ApiController
{
public IHttpActionResult GetUser(int userId, DateTime lastModifiedAtClient)
{
var user = new DataEntities().Users.First(p => p.Id == userId);
if (user.LastModified <= lastModifiedAtClient)
{
return StatusCode(HttpStatusCode.NotModified);
// If you would like to return a Http Status code with any object instead:
// return Content(HttpStatusCode.InternalServerError, "My Message");
}
return Ok(user);
}
}
I know there are several good answers here but this is what I needed so I figured I'd add this code in case anyone else needs to return whatever status code and response body they wanted in 4.7.x with webAPI.
public class DuplicateResponseResult<TResponse> : IHttpActionResult
{
private TResponse _response;
private HttpStatusCode _statusCode;
private HttpRequestMessage _httpRequestMessage;
public DuplicateResponseResult(HttpRequestMessage httpRequestMessage, TResponse response, HttpStatusCode statusCode)
{
_httpRequestMessage = httpRequestMessage;
_response = response;
_statusCode = statusCode;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage(_statusCode);
return Task.FromResult(_httpRequestMessage.CreateResponse(_statusCode, _response));
}
}