Is it possible to enable some static checking for tag helpers? - razor

For example I can write this code in default mvc template
<a asp-area="" asp-route-returnUrlFoo="foo"
asp-controller="Account" asp-action="RegisterFoo">Register</a>
And it would generate incorrect url
/Account/RegisterFoo?returnUrlFoo=foo
Is it possible to throw an error when there is incorrect action name or route argument?

Fallback Method: "Universally" Handling Mismatched Controller and Actions
You can add a new route that will redirect all your invalid requests to your own specific controller and action:
app.UseMvc(routes =>
{
// your other routes here
routes.MapRoute(_
name: "Fallback",
url: "{*any}",
defaults: new { controller = "Error", action = "Handler"});
}
In the above case, this will map everything (that is not defined) to go to /Error/Handler. You can modify this to meet your own requirements.
You can read more about route templates here:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing#route-template-reference
Alternative: Handle it per controller
Of course, there is the alternative which is to just deal with it on a controller basis instead. This approach is less generic and will allow you to create more targetted ways to deal with URI / routing errors.
Alternative: Check if the controller or action exists
string actionName = this.ControllerContext.RouteData.Values["action"].ToString();
string controllerName = this.ControllerContext.RouteData.Values["controller"].ToString();

Related

Can you set a default route in Fat-Free Framework

If the Fat-Free Framework (F3) sees that an incoming HTTP request does not match any of the routes defined in your application, is there a way to set a default route for these cases. For example, to put at the end of all the routes you have defined in the file, a route where any incoming HTTP request that did not match any preceding routes to go there?
Basically, I would like to route any request that doesn't find a match to a specific class/controller. It seems like this would be something that is possible to do, but I cannot find it anywhere in the F3 docs.
Not able to test it but what if you use a wildcard as last route option?
$f3->route('GET /*')
Instead of registering a default route it's better to register a custom error handler which is able to process 404 and other error codes. This approach allows to reuse the error controller or error function when triggering these errors programmatically; e.g. with Base->error(404).
Register the handler with ONERROR
Parse ERROR with the registered ONERROR handler
It's also possible to use the beforeRoute() and afterRoute() events.
Example
<?php
/** #var base $f3 */
$f3->set('ONERROR', 'App\Module\Error\Controller\ErrorController->onError');
class ErrorController
{
public function onError(Base $f3)
{
if ($f3->get('ERROR.code') == 404) {
/**
* TODO Generate an appropriate HTTP 404 page
*/
// Handled the `404` error.
return true;
}
// Let Fat-Free Framework's default error handler do the work.
return false;
}
}

Trying to call action from cshtml fails with routing error?

I'm trying to call an action on a controller in an MVC project from a view and I get the following error:
This can happen when a controller uses RouteAttribute for routing, but no action on that controller matches the request
I've read some people have removed the attribute routing to get this to work but that seems a bit extreme. Does anyone know where to start with this one?
//Calling in view like so
#Html.Action("Edit", new { datablockId = 227 })
//THe controller
[RoutePrefix("CustomData")]
public class CustomDataController : Controller, ICustomDataController
{
[Route("Edit")]
[HttpGet]
public ActionResult Edit(int datablockId)
{
return this.PartialView(new CustomDataEditViewModel() { DataRows = Data, DataBlockId = datablockId });
}
}
Try routing the action to that particular controller explicitly like this:
#Html.Action("Edit", "CustomData" ,new { datablockId = 227 })
Html action accepts aditional parameters that might fix your routing issue, those parameters are: Html.Action("Action", "Controller", Parameters)

ZF2 View strategy

I'm trying to implement the following:
Simple controller and action. Action should return response of 2 types depending on the request:
HTML in case of ordinary request (text\html),
JSON in case of ajax request (application\json)
I've managed to do this via a plugin for controller, but this requres to write
return $this->myCallBackFunction($data)
in each action. And what if I wan't to do this to whole controller? Was trying to figure out how to implement it via event listener, but could not succed.
Any tips or link to some article would be appreciated!
ZF2 has the acceptable view model selector controller plugin specifically for this purpose. It will select an appropriate ViewModel based on a mapping you define by looking at the Accepts header sent by the client.
For your example, you first need to enable the JSON view strategy by adding it to your view manager config (typically in module.config.php):
'view_manager' => array(
'strategies' => array(
'ViewJsonStrategy'
)
),
(It's likely you'll already have a view_manager key in there, in which case add the 'strategies' part to your current configuration.)
Then in your controller you call the controller plugin, using your mapping as the parameter:
class IndexController extends AbstractActionController
{
protected $acceptMapping = array(
'Zend\View\Model\ViewModel' => array(
'text/html'
),
'Zend\View\Model\JsonModel' => array(
'application/json'
)
);
public function indexAction()
{
$viewModel = $this->acceptableViewModelSelector($this->acceptMapping);
return $viewModel;
}
}
This will return a normal ViewModel for standard requests, and a JsonModel for requests that accept a JSON response (i.e. AJAX requests).
Any variables you assign to the JsonModel will be shown in the JSON output.

passing json data of webapi method from controller to view

I have data in my apicontroller in following way-
public class OutletPOCController : ApiController
{
OutletPOCContext db = new OutletPOCContext();
[System.Web.Http.ActionName("GetTabText")]
public TabTextModel GetTabText(int bizId)
{
var outlet = db.Info.Where(t => t.BizId == bizId).SingleOrDefault();
return new TabTextModel
{
HomeTab = outlet.BizHomeTabText,
AboutTab = outlet.BizAboutTabText,
TimingsTab = outlet.BizTimingsTabText,
};
}
And now i want to retrieve this data into my view. How shall i create view for this controller and pass the above data? What will be my action method? I am new to webapi and json. Any help is appreciable! Thanks in advance!
The API controller dosent really have views in the sense that you create a cshtml page that takes care of how you display your data. The purpose of the ApiController is simply to return data in the format that you want to consume it.
Basically the API exposes raw data to the web, you consume it in some way, and then display it..
I use something similar to this to load data dynamically into a web page.
Just a simple web api that returns data to the client.
public class APIController : ApiController
{
[HttpGet]
[HttpPost] // allow both post and get requests
public IEnumerable<String> GetData()
{
return new List<string>() { "test1", "test2" };
}
}
When you browse to the API method above it returns this xml data
<ArrayOfstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<string>test1</string>
<string>test2</string>
</ArrayOfstring>
Which I get using Jquery and do what I please with (http://api.jquery.com/jQuery.get/):
$.get("/api/GetData", function(data) {
alert("Data Loaded: " + data);
});
Examples of XML parsing with JS/Jquery:
http://tech.pro/tutorial/877/xml-parsing-with-jquery
http://www.kawa.net/works/js/jkl/parsexml-e.html
If you are simply looking to get data into a regular view and work with it there without going through javascript I wouldent use a webapi, but instead get the data in the controller and send it to the view for displaying (ASP MVC4 - Pass List to view via view model).
You can also check out the ViewBag container for passing random odd data to the view http://goo.gl/03JTR
On the off chance you really do want to render your data in a view, check this out: Web API - Rendering Razor view by default?

Spring MVC Request URLs in JSP

I am writing a web application using Spring MVC. I am using annotations for the controllers, etc. Everything is working fine, except when it comes to actual links in the application (form actions, <a> tags, etc.) Current, I have this (obviously abbreviated):
//In the controller
#RequestMapping(value="/admin/listPeople", method=RequestMethod.GET)
//In the JSP
Go to People List
When I directly enter the URL like "http://localhost:8080/MyApp/admin/listPeople", the page loads correctly. However, the link above does not work. It looses the application name "MyApp".
Does anyone know if there is a way to configure Spring to throw on the application name on there?
Let me know if you need to see any of my Spring configuration. I am using the standard dispatcher servlet with a view resolver, etc.
You need to prepend context path to your links.
// somewhere on the top of your JSP
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
...
Go to People List
The c:url tag will append the context path to your URL. For example:
<c:url value="/admin/listPeople"/>
Alternately, I prefer to use relative URLs as much as possible in my Spring MVC apps as well. So if the page is at /MyApp/index, the link <a href="admin/listPeople"> will take me to the listPeople page.
This also works if you are deeper in the URL hierarchy. You can use the .. to traverse back up a level. So on the page at/MyApp/admin/people/aPerson, using <a href="../listPeople"> will like back to the list page
I prefer to use BASE tag:
<base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/" />
Then, all your links can be like:
Go to People List
As i have just been trying to find the answer to this question and this is the first google result.
This can be done now using the MvcUriComponentsBuilder
This is part of the 4.0 version of Spring MVC
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.html
The method needed is fromMappingName
From the documentation :
Create a URL from the name of a Spring MVC controller method's request mapping.
The configured HandlerMethodMappingNamingStrategy determines the names of controller method request mappings at startup. By default all mappings are assigned a name based on the capital letters of the class name, followed by "#" as separator, and then the method name. For example "PC#getPerson" for a class named PersonController with method getPerson. In case the naming convention does not produce unique results, an explicit name may be assigned through the name attribute of the #RequestMapping annotation.
This is aimed primarily for use in view rendering technologies and EL expressions. The Spring URL tag library registers this method as a function called "mvcUrl".
For example, given this controller:
#RequestMapping("/people")
class PersonController {
#RequestMapping("/{id}")
public HttpEntity getPerson(#PathVariable String id) { ... }
}
A JSP can prepare a URL to the controller method as follows:
<%# taglib uri="http://www.springframework.org/tags" prefix="s" %>
Get Person
I usually configure tomcat to use context root of "/" or deploy the war as ROOT.war. Either way the war name does not become part of the URL.
You could use a servletRelativeAction. I'm not sure what versions this is available in (I'm using 4.0.x currently) and I haven't seen much documentation on this, but if you look at the code backing the spring form you can probably guess. Just make sure the path you pass it starts with a "/".
Example:
<form:form class="form-horizontal" name="form" servletRelativeAction="/j_spring_security_check" method="POST">
See org.springframework.web.servlet.tags.form.FormTag:
protected String resolveAction() throws JspException {
String action = getAction();
String servletRelativeAction = getServletRelativeAction();
if (StringUtils.hasText(action)) {
action = getDisplayString(evaluate(ACTION_ATTRIBUTE, action));
return processAction(action);
}
else if (StringUtils.hasText(servletRelativeAction)) {
String pathToServlet = getRequestContext().getPathToServlet();
if (servletRelativeAction.startsWith("/") && !servletRelativeAction.startsWith(getRequestContext().getContextPath())) {
servletRelativeAction = pathToServlet + servletRelativeAction;
}
servletRelativeAction = getDisplayString(evaluate(ACTION_ATTRIBUTE, servletRelativeAction));
return processAction(servletRelativeAction);
}
else {
String requestUri = getRequestContext().getRequestUri();
ServletResponse response = this.pageContext.getResponse();
if (response instanceof HttpServletResponse) {
requestUri = ((HttpServletResponse) response).encodeURL(requestUri);
String queryString = getRequestContext().getQueryString();
if (StringUtils.hasText(queryString)) {
requestUri += "?" + HtmlUtils.htmlEscape(queryString);
}
}
if (StringUtils.hasText(requestUri)) {
return processAction(requestUri);
}
else {
throw new IllegalArgumentException("Attribute 'action' is required. " +
"Attempted to resolve against current request URI but request URI was null.");
}
}
}
Since it's been some years I thought I'd chip in for others looking for this. If you are using annotations and have a controller action like this for instance:
#RequestMapping("/new") //<--- relative url
public ModelAndView newConsultant() {
ModelAndView mv = new ModelAndView("new_consultant");
try {
List<Consultant> list = ConsultantDAO.getConsultants();
mv.addObject("consultants", list);
} catch (Exception e) {
e.printStackTrace();
}
return mv;
}
in your .jsp (view) you add this directive
<%#taglib uri="http://www.springframework.org/tags" prefix="spring"%>
and simply use
<spring:url value="/new" var="url" htmlEscape="true"/>
New consultant
where
value's value should match #RequestMapping's argument in the controller action and
var's value is the name of the variable you use for href
HIH