spring MVC change displayed URL in controller - spring-mvc

I have an issue, let me introdues it:
I have a form which registers new users, the form then send information an address: ".../add-user.htm". In controller i have mapping for the address like this:
#RequestMapping(value = "add-user", method = RequestMethod.POST)
public ModelAndView addUser(#ModelAttribute("user") User user) {
ModelAndView modelAndView;
List<String> errors = userService.userRegisterErrors(user);
if(errors.size() == 0) {
//some code here...
modelAndView = new ModelAndView("index");
List<String> info = new ArrayList<String>();
info.add("Registration has been successful");
info.add("Verification e-mail has been sent to Your e-mail address");
modelAndView.addObject("info", info);
} else {
//some code here..
modelAndView = new ModelAndView("user/register");
modelAndView.addObject("user", user);
modelAndView.addObject("errors", errors);
}
return modelAndView;
}
At index page I'd like to show the info/error messages depends on if the registration was successful or not.
Let's assume the registration was correct for example. Then I'd like to see the index page with information for registration which works fine. The problem is with URL displayed at index page - it's not /index.htm as I wish, but it's /add-user.htm like controller defines. That's wrong because if i press "f5" button then it forces me to "re-register" the user.
I tried to use this method before returning modelAndView: modelAndView.setViewName("index.htm"); but nothing happened. I can redirect to index page in controller, but then I would lost all objects in modelAndView so no information would not be displayed. Another idea I had was to use a flag for info and error but it would be very complicated. Do you have a solution? thanks.

RedirectAttributes could suit your needs, especially the method addFlashAttribute. See the class' javadoc, it explains the purpose of using these attributes.

Related

ASP.NET MVC - How to stop rendering of a view childactions on Autharization error

In an Umbraco project I have a controller which requires user to be in a particular role, and a view with many child actions. When user with insufficient access rights tries to access the page then they should see an error message. Sofar I have created a customized Authorize attribute like this:
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizedResult();
}
else if (!AuthorizeCore(filterContext.HttpContext))
{
ViewDataDictionary viewData = new ViewDataDictionary();
viewData.Add("AuthenticationeError", "You do not have sufficient permissions to view this content.");
filterContext.Result = new ViewResult { ViewName = "~/Views/AuthError.cshtml", ViewData = viewData };
}
}
It does the job, although with the following error. On page load the view calls three different child actions from the secured controller and every time it does this, a new authorization error ViewResult is being displayed. Can this behavior be stopped? I want to render only one Error message and stop further view processing after the first error. Also I'd like user to stay on same page and avoid redirects if possible
For ChildAction I ended up returning empty ContentResult. The most simplified version of this is:
if (filterContext.IsChildAction)
{
filterContext.Result = new ContentResult() { Content = "" };
}
This doesn't answers my original question but solves the problem

How to handle exceptions in Odata V4 client?

Asp.Net Web API Odata Controller Action:
public async Task<IHttpActionResult> Post(Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Products.Add(product);
await db.SaveChangesAsync();
return Created(product);
}
Odata client code:
(Odata v4 client code generator v4)
static void AddProduct(Default.Container container, ProductService.Models.Product product)
{
container.AddToProducts(product);
var serviceResponse = container.SaveChanges();
foreach (var operationResponse in serviceResponse)
{
Console.WriteLine("Response: {0}", operationResponse.StatusCode);
}
}
I would like to handle exception in a proper way inside AddProducts() Method while saving the changes.
How can I catch process the ModelState error which is sent from server return BadRequest(ModelState);?
Finally I just want to show the error message to the end uses which was sent from server.
Example:
"Product category is required."
What is the use of ODataException class? Will this help me?
Please help me.
if I understood well, you want to intercept that the ModelState is not valid, and customize the OData error that is shown to the user.
If you just want that the errors of the invalid model show up in the returned payload, you can use:
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
If you want to fully control the exceptions handling and messages shown, I'd suggest several action points for you to accomplish this:
Intercept ModelState is not valid: you can do this with a custom ActionFilterAttribute. In there, you can override the method OnActionExecuting(HttpActionContext actionContext). You can access the ModelState through actionContext.ModelState, check if it is valid, check the fields that have errors, check the nature of these errors and the generated messages for these errors, etc. The ModelState may be not valid for different reasons, like different types than the expected, not meet requirements specified by DataAnnotations, etc. You can check more on Model validation in here. For your case, I guess the Product entity will have a Required data annotation in the Category field.
After checking all errors, you can throw a custom Exception with the error/list of errors with the messages you want. This is necessary to later intercept your custom exception and be able to return your custom message in the error payload.
Intercept your custom exception: create a custom ExceptionFilterAttribute to intercept your thrown exceptions. Overriding the
OnException(HttpActionExecutedContext filterContext) you will have access to the exception, and inspecting it you will be able to build your proper OdataError:
In here you should return the HttpResponseMessage with the BadRequest http status code and the created ODataError as a payload. As an example of very simple code (you can see that it would depend on how you build your custom exception):
public override void OnException(HttpActionExecutedContext filterContext)
{
Exception ex = filterContext.Exception;
HttpRequestMessage currentRequest = filterContext.Request;
if (filterContext.Exception.GetType() == typeof(YourCustomValidationException))
{
var oDataError = new ODataError()
{
ErrorCode = "invalidModel",
Message = "Your model is not valid.",
InnerError = new ODataInnerError()
{
TypeName = ex.TheEntityThatHasErrors
},
};
foreach (var validationError in ex.ValidationErrors)
{
oDataError.InnerError.Message += validationError + ", ";
}
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);
response.RequestMessage = currentRequest;
response.Content = new StringContent(JsonConvert.SerializeObject(oDataError));
filterContext.Response = response;
}
}
Finally, you will have to setup the custom ActionFilterAttribute and the custom ErrorFilterAttribute to be used each time that a request reach your controller. You can decorate your actions, controllers, or you can set the filters for all your API controllers in the WebApiConfig, with config.Filters.Add(...);
You can find more information about all of this in here. In the end, the error and exception handling is the same for ASP.Net Web API, with or without OData; difference is that if you have an OData API, you should return errors in OData style.
Hope all this info is understandable and helps you somehow.

ASP.NET Web API set custom status code

I have the following Api Controller:
[HttpPost]
public User Create(User user)
{
User user = _domain.CreateUser(user);
//set location header to /api/users/{id}
//set status code to 201
//return the created user
}
It seems like we have to depend on Request.CreateResponse(..) and change the signature of the controller so as to return IHttpActionResult.
I do not want to change the method signature as it is very useful for the documentation purpose. I am able to add the Location header using HttpContext.Current.Response... but not able to set the status code.
Anybody has any better idea on this?
Because you are using a custom (other) return type outside of void, HttpResponseMessage, and IHttpActionResult - it's harder to specify the status code. See Action Results in Web API 2.
From Exception Handling in Web API. If you want to stick with not modifying the return type then this might be something you can do to set the status code:
[HttpPost]
public User Create(User user)
{
User user = _domain.CreateUser(user);
//set location header to /api/users/{id}
//set status code to 201
if (user != null)
{
//return the created user
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Created, user);
}
else
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.InternalServerError));
}
}

How to return a custom view OR a JSON when the Authorization fail, instead of showing a username and password dialog

I am working on an asp.net mvc 4 web application , and i wrote the following custom authorization class:-
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class CheckUserPermissionsAttribute : AuthorizeAttribute
{
public string Model { get; set; }
public string Action { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (!httpContext.Request.IsAuthenticated)
return false;
//code goes here
if (!repository.can(ADusername, Model, value)) // implement this method based on your tables and logic
{
return false;
//base.HandleUnauthorizedRequest(filterContext);
}
return true;
// base.OnAuthorization(filterContext);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
var viewResult = new JsonResult();
viewResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
viewResult.Data = (new { IsSuccess = "Unauthorized", description = "Sorry, you do not have the required permission to perform this action." });
filterContext.Result = viewResult;
}
else
{
var viewResult = new ViewResult();
viewResult.ViewName = "~/Views/Errors/_Unauthorized.cshtml";
filterContext.Result = viewResult;
}
base.HandleUnauthorizedRequest(filterContext);
}
}
}
but the only problem i am facing now is that if the authorization fail then the user will be prompted to enter username and password, although i have override the HandleUnauthorizedRequest to return a view or JSON based on if the request is AJAX or not. so can you advice why the user is being prompted to enter his username and password when the authorization fail, instead of receiving the _unauthorized view or the JSON containing an error message
but the only problem i am facing now is that if the authorization fail
then the user will be prompted to enter username and password,
although i have override the HandleUnauthorizedRequest to return a
view or JSON based on if the request is AJAX or not.
That's because you are absolutely always hitting the following line in your HandleUnauthorizedRequest method:
base.HandleUnauthorizedRequest(filterContext);
You know what this line do? It calls the base method. You know what the base method do? It returns 401 status code. You know what happens when 401 status response code is returned in an ASP.NET application in which you are using Forms Authentication? You get the login page.
So yeah, if you are using AJAX or something and intend to be returning some JSON or something make sure that the base stuff is never called. By the way in your else condition you seem to be attempting to render some ~/Views/Errors/_Unauthorized.cshtml view which obviously is useless once again because you are also calling the base method which will simply redirect to the login page.
I think that at this stage of my answer you already know what to do: get rid of this last line of your HandleUnauthorizedRequest method in which you are throwing all your efforts into the trash by calling the base method.
And if you want to do things properly and return 401 status code and not get the login page but instead return some custom JSON you could use the SuppressFormsAuthenticationRedirect property on the Response object. And if you are using some legacy version of the .NET framework which doesn't have this property you might find the following blog post useful in which Phil Haack explains how to handle this case.

Spring login need custom msg on screen

I want to display custom message which will be fetched from database when user try to login on login page. This message can be changed by administrator. So always need to be fetched from database.
We are using acegi spring.
Do anybody know how to do this?
Jaydeep.
set your login page to be served from a controller, then you can set a modelattribute with your custom message and show it on the login screen
e.g.
#ModelAttribute("customMessage")
public String populateCustomeMessage() {
String msg // Code to get message from db and set it into a string
return msg;
}
#RequestMapping(value = "/login.html", method = RequestMethod.GET)
public String handleRequest() {
return "login";
}
Following link somewhat discusses on the topic you need (but not fetching from database)
how to display custom error message in jsp for spring security auth exception

Resources