I have a kendoGrid that read data with .Read(r => r.Action("CargaNotificacionesPorCliente", "bff").Data("getClaveCliente"))), the call works and the values are displayed in the grid correctly, nothing weird here.
When I open the Chrome DevTools it show the following error:
POST http://localhost:52881/bff/CargaNotificacionesPorCliente 500
(Internal Server Error)
I don't know why is marking it as a POST instead GET.
This my method (actually works)
public ActionResult CargaNotificacionesPorCliente([DataSourceRequest] DataSourceRequest request, string numeroCliente)
{
bff.Configuration.LazyLoadingEnabled = false;
var lstNotificaciones = new List<NotificacionesModel>();
var lstNoPartesNuevas = bff.inspListaNoPartes
.Where(x => x.codeCustomer == numeroCliente &&
x.Estatus == Constantes.EstatusNumParteNuevo &&
x.VistoCte == false)
.Include(i => i.CustomerCUSTOMER)
.ToList();
var cantidadComentariosNuevos = bff.inspCommentNoPartes
.Count(x => x.inspListaNoParte.codeCustomer == numeroCliente &&
x.Visto == false &&
x.Usuario != User.Identity.Name);
if (lstNoPartesNuevas.Any())
{
foreach (var item in lstNoPartesNuevas)
{
if (lstNotificaciones.All(a => a.IdCustomer != item.IdCustomer))
{
lstNotificaciones.Add(new NotificacionesModel
{
Cantidad = lstNoPartesNuevas.Count(x => x.IdCustomer == item.IdCustomer && x.Estatus == Constantes.EstatusNumParteNuevo && x.VistoSup == false) + cantidadComentariosNuevos,
Name = item.CustomerCUSTOMER.name,
IdCustomer = item.IdCustomer,
IdNumPart = item.IdNumPart
});
}
}
}
return Json(lstNotificaciones.ToList().ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
And this is the Preview tab of the error in the DevTools
Server Error in '/' Application.
Input string was not in a correct format.
Description: An unhandled exception occurred during the execution of
the current web request. Please review the stack trace for more
information about the error and where it originated in the code.
Exception Details: System.FormatException: Input string was not in a
correct format.
But as I said, it's weird because it works
Tried adding [HttpGet] but doesn't work, in fact the method is never called with that annotation.
EDIT:
I did the binding by this way:
$("#Notificaciones").data("kendoGrid").dataSource.read(); // Read data
$("#Notificaciones").data("kendoGrid").dataSource.page(1); // Go to page 1
I removed the second line (.dataSource.page(1);) and now the error disappeared, but how this affected the call?, I can't figure it out
Should be able to do something like this
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("Index", "Banques").Type(HttpVerbs.Get))
.PageSize(8)
)
http://www.telerik.com/forums/post-vs-get-request
In the tool you are using, make sure that the HTTP verb is selected as Get. See below for a screenshot from Chrome's Postman
Related
In Asp.Net Core 5 I am using UseExceptionHandler to handle exceptions globally and it works fine unless I send an invalid object. For example I send an object with null value for the required property "Name" I receive the following error in client but the Run function does not hit in debugger.
{"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1" ,"title":"One
or more validation errors
occurred.","status":400,"traceId":"00-2428f0fb9c415843bca2aaef08eda6f6-11ea476efb792849-00","errors":{"Name":["The
field Name is required"]}}
(as the first middleware in the pipeline :)
app.UseExceptionHandler(a => a.Run(async context =>
{
//this does not being exceuted for validation errors
var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
var exception = exceptionHandlerPathFeature.Error;
var exceptionManager = a.ApplicationServices.GetRequiredService<IExceptionManager>();
await context.Response.WriteAsJsonAsync(exceptionManager.Manage(exception, context));
}));
This may help you.
services.AddControllers().ConfigureApiBehaviorOptions(options =>
{
options.InvalidModelStateResponseFactory = context =>
{
var errors = context.ModelState.Keys
.SelectMany(key => context.ModelState[key].Errors.Select(x => $"{key}: {x.ErrorMessage}"))
.ToArray();
var apiError = new CustomErrorClass()
{
Message = "Validation Error",
Errors = errors
};
var result = new ObjectResult(apiError);
result.ContentTypes.Add(MediaTypeNames.Application.Json);
return result;
};
});
I build this API that takes in Id if that Id is found It will return the data. But if that Id is not found I return 409. When I test it in postman I see the status as 409 is that correct? is that all I need or should it also return some text in the body?
[HttpGet]
public IHttpActionResult Read(string type, string id)
{
if (id== null)
{
var msg = new HttpResponseMessage(HttpStatusCode.NotFound) { ReasonPhrase = "Unable to Find Id" };
msg.Content= new StringContent($"No entity with {id} was found");
return ResponseMessage(msg);
}
}
You do see a "not found" text:
You don't see anything in the body, because your API doesn't send a body, just a HTTP header
Re your comment, and linking in GPW's advice, return something custom - let errors be errors, and have this foreseeable condition as an "OK but no" response, perhaps:
[HttpGet]
public ActionResult Read(string type, string id)
{
if (id == null)
return Json(new { status= "fail", message= "id parameter is required" });
else if (type == null)
return Json(new { status= "fail", message= "type parameter is required" });
var ent = dbcontext.Entity.FirstOrDefault(e => e.Type == type && e.Id == id);
if(ent == null)
return Json(new { status="fail", message= "No entity with that type/id was found" });
else
return Json(new { status="ok", entityName= ent.Name });
}
In one of our apps we do use HTTP errors to alter the behavior of the client - there's a promise chain at the client react app and we use returning an error to halt processing of the chain, parse the error out, then go back to parsing knowing the JSON is a slightly different shape. I'm not convinced it's a great way to do it as it's made the client more complex than it could have been but if you want to do that then sure, look at ways of returning meaningful http errors. Personally (and GPW alludes to it) even debugging, many times I've missed the return code in postman, got a blank response, been misled that something else is wrong than what is actually happening/ got a 404 and thought the back end couldn't find the entity when actually I'd got the URL wrong and was getting a 404 for a different reason etc
I'm writing a controller to get the Books with for certain authors with a specific rating. This is the code for the GET method :
public IQueryable<Book> GetBooks(string context)
{
string rating = context.Split('?')[0];
string[] authors = context.context.Split('?')[1].Split(',');
return db.Books.Where(s => authors.Contains(s.AuthorName) && s.Rating == rating);
}
When I run the project and enter this URL :
http://localhost:65239/api/books/5?James,Tom
I get this error:
<Error>
<Message>
The requested resource does not support http method 'GET'.
</Message>
</Error>
What am I doing wrong?
Try this;
public JsonResult GetBooks(string context)
{
string rating = context.Split('?')[0];
string[] authors = context.context.Split('?')[1].Split(',');
var books = db.Books.Where(s => authors.Contains(s.AuthorName) && s.Rating == rating);
return Json(books, JsonRequestBehavior.AllowGet);
}
Turns out I was using the wrong URL format.
http://localhost:65239/api/books?context=5?James,Tom
Am using
1) kendo mvc grid (telerik UI for asp.net MVC)on my view (Q1-2015)
2) Consuming the ODATA end point (similar to the article http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v3/calling-an-odata-service-from-a-net-client) - consuming asp.net web api (odata)
Controller Code
public ActionResult LoadGrid([DataSourceRequest]DataSourceRequest request)
{
if (Request.Cookies["myAPIKeyCookie"] != null)
{
var cookieValue = Request.Cookies["myAPIKeyCookie"].Value;
using (var context = new MyApiClientContext(cookieValue))
{
IQueryable<User> users = context.MyApiContainer.Users;// did a watch - users contains data.
var result = users.ToDataSourceResult(request);// throws an error here - the request url is appended with $count e.g. https://myurl/odata/users()?$count - Shouldnt the toDataSourceResult method add the pagesize as count here automatically?
return Json(result);
}
}
else
{
return RedirectToAction("Index", "Login");
}
return Json(null);
}
My View
#(Html.Kendo().Grid<User>()
.Name("GridAjax")
.DataSource(ds => ds.Ajax()
.Read(readFrom => readFrom.Action("LoadGrid", "Users"))
.Model(m => m.Id(model => model.Id))
.PageSize(5)
)
.Columns(columns =>
{
columns.Bound(u => u.Id).Visible(false);
columns.Bound(u => u.DisplayName);
columns.Bound(u => u.Email);
columns.Bound(u => u.ManagerName);
})
.Pageable()
.Sortable()
.Filterable()
.Editable(e => e.Mode(GridEditMode.InLine))
)
Am encountering an error on the line "users.ToDataSourceResult". Exception below
{"Message":"The OData path is invalid.","ExceptionMessage":"Invalid action detected. '$count' is not an action that can bind to 'Collection([MyApi.Domain.Entities.User Nullable=False])'.","ExceptionType":"Microsoft.Data.OData.ODataException",
"StackTrace":" at System.Web.Http.OData.Routing.DefaultODataPathHandler.ParseAtEntityCollection(IEdmModel model, ODataPathSegment previous, IEdmType previousEdmType, String segment)\r\n at System.Web.Http.OData.Routing.DefaultODataPathHandler.Parse(IEdmModel model,
String odataPath)\r\n at System.Web.Http.OData.Routing.ODataPathRouteConstraint.Match(HttpRequestMessage request, IHttpRoute route, String parameterName, IDictionary`2 values, HttpRouteDirection routeDirection)"}
Attached is the screen shot of my watch that shows the url with an empty count hence the conversion error - but shouldnt the page size be appended to the url automatically ? - should I do it manually? Am I missing something here ?I tried with server binding as well- In that case the page size = something doesnt even work - all data is loaded on a 1st page.
I am using Azure Mobile Services (following the standard Azure TodoItems tutorial), and the most basic GET method that they provide is:
public IQueryable<MyModel> GetAllMyInfo()
{
return Query();
}
This works, but I am trying to extend it so that the method will only return MyModel data for an authenticated user (identified by the X-ZUMO-AUTH authentication header standard for Mobile Service API calls). So I modified the code for:
public IQueryable<MyModel> GetAllMyInfo()
{
// Get the current user
var currentUser = User as ServiceUser;
var ownerId = currentUser.Id;
return Query().Where(s => s.OwnerId == ownerId);
}
This also works when a valid auth token is passed. However, if an invalid auth header is passed, then the currentUser is null, and the query fails (obviously). So I am trying to check for null and return a BadRequest or a 403 HTTP code. Yet a simple `return BadRequest("Invalid authentication") gives a compilation error:
public IQueryable<MyModel> GetAllMyInfo()
{
// Get the current user
var currentUser = User as ServiceUser;
if(currentUser == null) {
return BadRequest("Database has already been created."); // This line gives a compilation error saying I need a cast.
}
var ownerId = currentUser.Id;
return Query().Where(s => s.OwnerId == ownerId);
}
Does anyone know how to check for a valid authentication token and return a 403 on this method (which wants an IQueryable return type?
You can use the [AuthorizeLevel] attribute on this method to indicate that a valid token must be present in order for the method to be invoked. It will return a 401 if not.
So your full method would be:
[AuthorizeLevel(AuthorizationLevel.User)]
public IQueryable<MyModel> GetAllMyInfo()
{
// Get the current user
var currentUser = User as ServiceUser;
var ownerId = currentUser.Id;
return Query().Where(s => s.OwnerId == ownerId);
}
Please note that for the Azure Mobile Apps SDK (not Mobile Services), the above attribute is simply replaced with [Authorize].
I know this is a bit late, but will document here for you and others that may come looking for a similar problem.
(While agreeing with Matt that a 403 could/should be achieved with a [Authorize] attribute, the question is regarding returning a different HttpStatusCode OR IQueryable)
I had a similar scenario where I needed to validate some query parameters and either return my results or a HttpError (in my case I wanted a 404 with content).
I found 2 ways, either keeping the return as IQueryable<T> and throwing a HttpResponseException or changing the return to IHttpActionResult and returning normal with HttpStatusCode or Ok(Data).
I found to prefer the later as throwing an Exception would be breaking the execution while in debug and not a very pleasant development experience.
Option 1 (Preferred)
//Adding Return annotation for API Documentation generation
[ResponseType(typeof(IQueryable<MyModel>))]
public IHttpActionResult GetAllMyInfo()
{
// Get the current user
var currentUser = User as ServiceUser;
if(currentUser == null) {
return BadRequest("Database has already been created.");
}
var ownerId = currentUser.Id;
return Ok(Query().Where(s => s.OwnerId == ownerId));
}
Option 2 (Throwing Exception)
public IQueryable<MyModel> GetAllMyInfo()
{
// Get the current user
var currentUser = User as ServiceUser;
if(currentUser == null) {
throw new HttpResponseException(System.Net.HttpStatusCode.BadRequest)
// Or to add a content message:
throw new HttpResponseException(new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.BadRequest) {
Content = new System.Net.Http.StringContent("Database has already been created.")
});
}
var ownerId = currentUser.Id;
return Query().Where(s => s.OwnerId == ownerId);
}