I was looking at our logs and came across an error:
A required anti-forgery token was not supplied or was invalid.
It seems like one of the developers may have not added the token onto a page or did not send it via an AJAX call. The problem is I have no idea where in our code base this originated. It was logged by the [HandleError] logging code we added but we have no way of knowing which method caused this.
The stack trace only shows us the following which doesn't seem very helpful:
at System.Web.Helpers.AntiForgeryWorker.Validate(HttpContextBase
context, String salt) at
System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext
controllerContext, IList`1 filters, ActionDescriptor actionDescriptor)
at
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext
controllerContext, String actionName)
The OnException method in our BaseController looks as follows:
protected override void OnException(ExceptionContext filterContext)
{
Exception ex = filterContext.Exception;
//
// Custom logging code here was removed for brevity
if (filterContext.Exception.Data.Contains("Description") == false)
filterContext.Exception.Data.Add("Description", "Oops. Something went wrong!");
//Displays a friendly error, doesn't require HandleError
filterContext.ExceptionHandled = true;
//Displays a friendly error, *requires* HandlError
base.OnException(filterContext);
}
My question is:
Is there a way to get the source of the exception, ie. to know what controller or source file threw the exception using ExceptionContext.
Appreciate the help.
Based on BuildStarted's response, the answer lies in the RouteData property of filterContext. I have an object dumper that writes out the properties of any object and here is what I see in our logs now.
RouteData:
[0]: [controller, Assess]
[1]: [action, Setup]
[2]: [id, 2]
So now I know the exact method that caused this.
Related
I want to understand why FromBody behave like this for common request.
Case 1:
Controller
public void Post([FromBody]string value)
{
}
POSTMAN Request
Problem
In this case value is my post method will not bind to value parameter to test.
Case 2:
Model
public class Test
{
public string value { get; set; }
}
Controller
public void Post([FromBody]Test model)
{
}
POSTMAN Request
Same as Case 1
Result :
Now model value property successfully bind to "test".
Why it is behave like this ?
Because that's the way the API was designed. Note that in your second example you could have elided [FromBody] and WebApi would have searched the body for the data anyways because Test is a complex type.
This article explains the rules by which WebApi binds data:
http://blogs.msdn.com/b/jmstall/archive/2012/04/16/how-webapi-does-parameter-binding.aspx
EDIT: As commented, the article linked above clearly states you should be able to do
void Get([FromBody]string value)
This is true, but it means you can read the value of the body as plain text into the parameter value. This means if you go this route, you MUST use the raw option (from postman) and either clear Content-Type or make sure it's set to text/plain.
In other words, on Postman, if you set the send method to raw, and type in "this is a sentence" as is in the text area provided, your value, when the issue below is fixed, will be "this is a sentence".
Now, if you tried doing this from a fresh template, you will run into this error:
{
"Message": "The request entity's media type 'text/plain' is not supported for this resource.",
"ExceptionMessage": "No MediaTypeFormatter is available to read an object of type 'String' from content with media type 'text/plain'.",
"ExceptionType": "System.Net.Http.UnsupportedMediaTypeException",
"StackTrace": " at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)\r\n at System.Web.Http.ModelBinding.FormatterParameterBinding.ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)"
}
This article explains how to allow WebApi to accept text/plain data from the body:
https://myadventuresincoding.wordpress.com/2012/06/19/c-supporting-textplain-in-an-mvc-4-rc-web-api-application/
It's kind of stupid that the default ValuesController exposes a method with that signature, but does not provide a MediaTypeFormatter for text/plain, but I guess that's Microsoft for you.
Given this method:
// POST api/values
[HttpPost]
public void Post([FromBody]string value)
{
Values.Add(value);
}
Postman must be configured correctly in order for our value to bind to its C# string object...one way to ensure this works in our case is to send our server a JSON request. Follow these steps:
Make sure you've selected POST.
Make sure you've entered an appropriate URL, i.e. http://localhost:1337/api/values.
Go to Body, tick the option for raw.
In the drop-down to the right, select JSON (application/json).
In the text area of Postman, insert only "Hello, world." (with the quotes as well, otherwise it won't be valid JSON).
It should now work once you hit Send.
For JSON you can do this:
public HttpResponseMessage Webhook(JToken json)
{
}
Where JToken is Newtonsoft.Json.Linq.JToken.
JObject works if the data is an actual JSON object (not an array)
Hi all wicket pros out there,
I would like to get extra parameter I added to the AjaxRequest in the respond(AjaxRequestTarget target) method of a AbstractDefaultAjaxBehaviour.
I build the Wicket.Ajax.get(...) call by myself and I could manage that the respond(AjaxRequestTarget target) method of the AbstractDefaultAjaxBehaviour is invoked, but I get stock in how to get the extra parameters I added in my js call.
So here the code what I'm doing:
js that is called onSelect:
Wicket.ajax.get({'u':'callbackUrl','c':'componetId', 'ep':{'objectId':'OBJECT_ID'}});
java snippet of the AbstractDefaultAjaxBehaviour:
onSelectBehavior = new AbstractDefaultAjaxBehavior(){
#Override
protected void respond(AjaxRequestTarget target) {
//here I want to get the OBJECT_ID I added in the Wicket.Ajax.get call above
}
};
The respond() method is invoked as expected, but I don't know how to get the OBJECT_ID.
Actually I'm not sure at all if I added the extra parameter in the right way to the wicket.ajax.get call.
In Wicket 1.4 I added the extra parameters as a url query string like ajaxCallUrl...?objectId=OBJECT_ID and in respond() I got them back from the RequestCycle RequestCycle().get().getRequest().getParameter('objectId')
If anyone could give me a hint, I would appreciate it :)
Thanks in advance,
Ronny
Your approach is correct. You should be able to get the parameter like this:
#Override
protected void respond(AjaxRequestTarget target)
{
getRequest().getRequestParameters().getParameterValue("objectId");
}
See my answer to this question for passing parameters directly from Wicket without constructing the ajax call yourself.
I'm working on a team-project and I am in the following situation:
I created my own Exception class, and I want all the thrown exceptions of type myException to be handled and automatically redirected to the Error view where I would nicely display the error, which is ok to do. This is what I added in my Web.config:
<customErrors mode="On" defaultRedirect="Error" />
The issue is I want all the rest of the exceptions to be thrown normally, seeing all the information about it, including the stack trace, the source file and the line error, which would be really good for the team-project.
I've tried the [HandleError(ExceptionType=typeof(myException)], but it is no use.
I also tried to override the OnException function of the controller and if the exception is not myException then i would throw it again, but i still get in the Error view.
protected override void OnException(System.Web.Mvc.ExceptionContext filterContext)
{
if (filterContext.Exception.GetType() != typeof(myException)) {
throw filterContext.Exception;
}
base.OnException(filterContext);
}
Any idea which could work?
Thanks.
You may get the result you want by leaving custom errors Off (so that for all the errors you get the stack trace displayed), and redirecting the exceptions you want to the controller/view you need (so that a friendly-looking page will be displayed).
You could define a base controller for all your controllers, and override its OnException method with something like below:
if (filterContext.Exception.GetType() == typeof(YourCustomException))
{
filterContext.ExceptionHandled = true;
filterContext.Result = RedirectToAction("ActionName", "ControllerName", new { customMessage = "You may want to pass a custom error message, or any other parameters here"});
}
else
{
base.OnException(filterContext);
}
I've implemented an ActionFilterAttribute responsible for NHibernate transaction management. Transactions are committed in the OnResultedExecuted override, which occasionally will result in an exception being thrown.
I'm able to successfully intercept these exceptions in the controllers OnException override, however the page still redirects as if the transaction were successful.
What I'd like to be able to do is return the same view action that caused the error with the exceptions message added to the ModelState.
I've tried a number of different things, none of which seem to work.. here's my latest attempt:
[HttpPost]
[Transaction]
[HandleError]
public ActionResult Enroll(EnrollNewEmployeeCommand command)
{
if(command.IsValid())
{
try
{
_commandProcessor.Process(command);
}
catch(Exception exception)
{
ModelState.AddModelError("", exception.Message);
return View(command);
}
return this.RedirectToAction(x => x.Index()); // redirects to index even if an error occurs
}
return View(command);
}
protected override void OnException(ExceptionContext filterContext)
{
//dont interfere if the exception is already handled
if (filterContext.ExceptionHandled)
return;
ModelState.AddModelError("", filterContext.Exception.Message);
filterContext.ExceptionHandled = true;
// want to return original view with updated modelstate
filterContext.Result = new ViewResult
{
ViewName = filterContext.RequestContext.RouteData.Values["action"].ToString(),
ViewData = filterContext.Controller.ViewData
};
}
What I'd like to be able to do is return the same view action that caused the error with the exceptions message added to the ModelState
You can't. OnResultedExecuted happens too late. The view rendering has ended and you can no longer modify what will be sent to the client at this stage.
Your last chance if you want to still be able to modify the returned result to the client is OnResultExecuting. So you could commit your transactions there. Wouldn't be so penalizing I guess.
At the contrary, I would even commit transactions in the OnActionExecuted event, as at this stage all you've got should be a fully initialized view models passed to the view for rendering. That's where your transaction boundaries should end. The process of rendering of the views should be excluded from any transactions and DB stuff. It's just HTML (or something) rendering from a view model, plain and simple.
I'm recieving the following error message,
A public action method 'RenderMenu'
was not found on controller
'Web.Controllers.SiteController'.
However this action DOES exist and the controller does exist (As it work everywhere on the site) I looked at the inner exception.
Execution of the child request failed.
Please examine the InnerException for
more information.
(This is the inner exception...)
Stack Trace
at
System.Web.Mvc.HttpHandlerUtil.ServerExecuteHttpHandlerWrapper.Wrap[TResult](Func`1
func) at
System.Web.HttpServerUtility.ExecuteInternal(IHttpHandler
handler, TextWriter writer, Boolean
preserveForm, Boolean setPreviousPage,
VirtualPath path, VirtualPath
filePath, String physPath, Exception
error, String queryStringOverride)
Now, we have a website set-up with a dynamic menu system so we are using RenderAction() on a generic controller to build this menu system up.
<% Html.RenderAction("RenderMenu", "Site"); %>
This call is made from the MasterPage and it works fine until there was a validation error like so,
[HttpPost]
public ActionResult Register(UserModel UserToAdd)
{
if(!ModelState.IsValid)
{
return View(UserToAdd);
}
//Run some validation
if (_UserService.DoesEmailExist(UserToAdd.EMail))
{
TempData["error"] = "Email Address Already in use!";
return View(UserToAdd);
}
//Add the user
TempData["info"] = "User Added - " + UserO.ID;
return View("Success");
}
It works fine when there this is a new user, but if someone enters an email that already exist we get the above error. THis RenderAction Method works all over the site (This is the first form we have added)
Any suggestions?
Fixed:
The RenderAction() Method is below
[HttpGet]
public ActionResult RenderMenu()
{
//Do Stuff
}
Removing the HttpGet Attribute has resolved the issue.
public ActionResult RenderMenu()
{
//Do Stuff
}
Would love to know why?
This is because your parent request is an [HttpPost], and the child request operates in the same verb as the parent. If your method is marked as [HttpGet], it will not respond to [HttpPost] requests. Hitting the action directly through your browser works because that is a GET. Hitting the action as a child action in the context of a POST will not work.