Web Api Action Attribute not executing when request sent from a new tab - asp.net-web-api

I have an Action Attribute
ReportAccessAttribute
Added this attribute to a controller action
ReportingController
My application is in angularjs
When tested with other controller and action this attribute works fine.
Now I am requesting that Action method of controller from my application by setting the url in an anchor tag.
This anchor tag opens a new tab and sends the request to server.
In this case Action attribute do not execute.
Please suggest.
Code Sample
Action Attribute
public class ReportAccessAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
//Some work...!!
base.OnActionExecuting(actionContext);
}
}
Controller
public class ReportingController : Controller
{
public ReportingController()
{
//Some initializations..!!
}
[Filters.ReportAccess]
public ActionResult Report(string reportName)
{
//Report generation logic.
}
}
When accessed from my angularjs app it gets executed eg: using a service to call that method.
But when I create a url and set anchor tag value to that url and click on that anchor tag. It opens that url in new tab and then it don't executes.

Thanks for the response.
The problem was I create the attribute using namespaces from WebApi dll and the controller from MVC dll.
That's why it wasn't intercepted in the execution pipeline.

Related

Spring sending user to a view when no view is being requested

I have written a book catalog in Spring.
It collects books (pdf, epub, mobi, ebook) from a directory, collects some metadata from them, stores them in a DB and then puts them in a List that is made available to my views:
#Slf4j
#Controller
public class BookCatalogController {
// == Fields ==
private final BookService bookService;
#Autowired
public BookCatalogController(BookService bookService){this.bookService = bookService; }
// == Model attributes ==
#ModelAttribute
public List<Book> bookData(){ return bookService.getBooksFromMemory(); }
public static final File bookDirectory= new File("D:\\edu_repo\\ebooks_test\\");
.
.
.
// Catalog Simple View
#GetMapping(Mappings.CATALOG_SIMPLE)
public String catalogSimple(Model model){
log.info("catalogSimple method called");
// This is adding the entire BookManager book list into the model.
model.addAttribute(AttributeNames.BOOK_DATA, bookData());
return ViewNames.CATALOG_SIMPLE;
}
// Catalog Detail View
#GetMapping(Mappings.CATALOG_DETAIL)
public String catalogDetail(Model model){
log.info("catalogDetail method called");
// This is adding the entire BookManager book list into the model.
model.addAttribute(AttributeNames.BOOK_DATA, bookData());
return ViewNames.CATALOG_DETAIL;
}
.
.
.
#GetMapping(Mappings.LOAD_BOOKS)
public void loadBooks(Model model) {
bookService.loadBooksFromDirectory(bookDirectory);
}
}
Obviously I'm not using #GetMapping(Mappings.LOAD_BOOKS) properly as you can see in the error below:
The error:
There was an unexpected error (type=Internal Server Error, status=500).
Error resolving template [load-books], template might not exist or might not be accessible by any of the configured Template Resolvers
org.thymeleaf.exceptions.TemplateInputException: Error resolving template [load-books], template might not exist or might not be accessible by any of the configured Template Resolvers
How does one invoke a method like I am doing but without Spring trying to redirect the user to another view?
I'm not expecting the page to update at all since I'm not returning a View!
When you click a link in your browser with a load-books anchor, your browser sends it to the server and waits for result, which causes your page to be reloaded. Once the request to a load-books endpoint reached to the server, Spring MVC handles this and starting to looking up an appropriate controller with its method. It founds public void loadBooks(Model model) in your case. When Spring MVC invokes the method, it expects to obtain a view name to resolve and return back to your browser.
Since you haven't provided a View or String as a return type, Spring MVC used the endpoint's path as a view name (I'm not seeing your Mappings.LOAD_BOOKS constant, but it supposed to be load-books).
If you're not going to return any view back to the browser, you can annotate the method like that:
#GetMapping(Mappings.LOAD_BOOKS)
#ResponseBody
public void loadBooks(Model model) {
which tells Spring to treat void as a response body.
But it's not preventing a page refreshing, you'll just see an empty page after clicking the link. In order to fix this you can redirect a user to another page by returning the following string (without ResponseBody annotation on the method)
return "redirect:/path-to-redirect";
When Spring MVC sees this prefix it redirects you to another controller, but user going to notice that too.
If you really don't want to see a blank page for a moment, you'll have to use some JavaScript to perform AJAX request to the server when button is clicked.
Actually, it seems that you want to preload some files in a service by a given path. If it's all you want to do, you can use Spring's runners like that:
#Component
class Preloader implements ApplicationRunner {
private final BookCatalogService bookService;
#Autowired
public Preloader(BookCatalogService service) {
this.bookService = service;
}
#Override
public void run(ApplicationArguments args) throws Exception {
bookService.loadBooksFromDirectory(BookCatalogController.bookDirectory);
}
}
Spring automatically calls all registered runners when application is ready, so your code will be executed without having a user to visit load-books endpoint.

Web API Binding Always Null when Premitive type and application/x-www-form-urlencoded used

Following is default method from Web API template. Most of the time I am using application/json as Content-Type but when I used application/x-www-form-urlencoded and pass data to api as value=test. It is failed to recognize or bind.
public void Post([FromBody]string value)
{
}
This thing work when I pass value as =test instead of value=test but if I pass same thing to MVC controller it is working.
If I do something like this then it is working.
public class TestModel
{
public string value {get;set;}
}
public void Post([FromBody]TestModel model)
{
}
What is issue with first method and why it is not working ? Why it is working with MVC Controller or Binding and not with Web API Parameter Binding ?
When you use form data (application/x-www-form-urlencoded) put [FormForm] instead of [FromBody].

Implementing CustomErrors within Web API project

I'm trying to implement custom error handling within a Web API project using my web.config file. My issue is that the redirect is not happening. I have the following set up in my web config:
<customErrors mode="On" defaultRedirect="~/Page/Error?errorId=59">
<error statusCode="403" redirect="~/Page/Error?errorId=59"/>
</customErrors>
This is where it may be tricky:
I'm using a custom attribute that I'm placing in my controller, and the attribute returns a 403 status code if the request is not coming from a listed referrer.
Here's the attribute Code:
public class Action1DebugActionWebApiFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
// pre-processing
HttpRequestMessage request = actionContext.Request;
string ipAddress = ((HttpContextWrapper)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
if (!IsIpAddressAllowed(ipAddress.Trim()))
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden);
}
}
Then I add the attribute to my controller like so:
[Action1DebugActionWebApiFilter]
[HttpGet]
[Route("MyRedirect")]
public IHttpActionResult MyRedirect([FromUri]UserModel myUser)
I know the 403 is getting produced because I can see it in my Firefox network tab. But the redirect isn't happening (verified in Fiddler). I just get a blank screen on the controller redirect with all the Get parameters just sitting there.
Any ideas?
That is because the <customErrors> section does not apply to asp web api.

Displaying a default view when a condition is true, asp.net mvc3

How to display a default page like Maintenance page for all the views if a web.config key is set to true?
If the key is false, then show the regular views.
Plz note, I don't want to repeat the code in each controller and am looking for a common place, like _ViewStart or _Layout page where this can be defined.
Thanks.
You could create your own ActionFilterAttribute and base Controller, which gives you access to OnActionExecuting. You could then test if the Web.Config value is set (perhaps loading it into an Application variable when you first start your Web app) and if it is set, setting the Controller and Action attributes to your maintenance page. Then all of your controllers, instead of inheriting from the standard Controller would inherit from your controller instead, except for the Maintenance controller which could still inherit from the normal Controller.
For instance:
[RedirectToMaintenancePage]
public class MyController : Controller
{
}
And for a typical controller:
public class SampleController : MyController
{
... Your actions ...
}
Then create a class called RedirectToMaintenancePageAttribute.cs:
public class RedirectToMaintenancePageAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
If Web.config says to go to Maintenance page then...
{
filterContext.Result = RedirectToRouteResult("route name") // Or some other redirect
return;
}
// else
base.OnActionExecuting(filterContext);
}
}
This is all off the top of my head, but I think it should work, and if it doesn't hopefully it'll give you some ideas.

MVC SessionStateAttribute not working as Global Attribute

How do you setup SessionStateAttribute as a global filter in MVC3?
In my Global.asax I have this in the RegisterGlobalFilters method.
filters.Add(new SessionStateAttribute(SessionStateBehavior.Disabled));
And in my home controller I have this.
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
Session["Blend"] = "Will it blend?";
return View();
}
public ActionResult About()
{
return View();
}
}
But for some reason it still lets me use the Session. However if I decorate the HomeController class itself with the attribute, I get an error on the line utilizing the Session about a Object reference being null, which I'm guessing is intended if the Session is never created?
I am starting to wonder if there is something wrong with my project. I've been getting little problems like this one with standard behavior that are supposed to just work.
Anyone else had problems with things like this?
SessionStateAttribute is not an action filter, so you cannot add it as a global action filter. It's a special attribute which allows you to decorate your controllers with and have a more fine grained control over the session mode per controller.
To disable the session globally for the entire application put the following in your web.config:
<sessionState mode="Off" />

Resources