I'm using the following Razor in my page:
<a asp-action="Logs" asp-route-channel="#channel.Name">
<button class="btn btn-success btn-circle"><i class="fa fa-eye"></i></button>
</a>
channel is a string, not an integer, which is why I don't use id.
And this is how I'm routing it:
endpoints.MapControllerRoute("logs", "Dashboard/Logs/{channel}");
And in my Controller, I'm simply doing this for testing purposes:
public IActionResult Logs(string channel)
{
return Content(channel);
}
However, when the link is generated, I get something like this:
<a href="/Dashboard/Logs?channel=mychannel">
Instead of the expected:
<a href="/Dashboard/Logs/mychannel">
EDIT
Here's what I've tried:
[HttpGet("{channel}")]
public IActionResult Logs(string channel)
{
return Content(channel);
}
Which results in https://localhost:44351/mychannel
I've also tried:
[HttpGet("Dashboard/Logs/{channel}")]
public IActionResult Logs(string channel)
{
return Content(channel);
}
Which works as intended, but why should I have to include the whole path like that?
You are mapping to the default convention based route, which would most likely have {id} as a route parameter. Because it maps to the default and you included {channel} it would add that parameter as a query string instead of part of the URL.
You would need to include a custom route for that action in order to get the desired URL generation.
endpoints.MapControllerRoute(
name: "Logs",
pattern: "Dashboard/Logs/{channel}",
defaults: new { controller = "Dashboard", action = "Logs" });
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action}/{id?}",
defaults: new { controller = "Home", action = "Index" });
and the necessary route values would need to be included so that it maps to the intended route
<a asp-controller="Dashboard" asp-action="Logs" asp-route-channel="#channel.Name">
<button class="btn btn-success btn-circle"><i class="fa fa-eye"></i></button>
</a>
Related
I am new to ASP.NET Core and building a Project in .NET Core MVC.
In my Admin Area I have a controller UserRolesController and Action CreateRole (Works Alright)
In the View, I added a Hyperlink to the CreateRole Action
<a class="btn btn-primary" asp-controller="UserRoles" asp-action="CreateRole">Create Role</a>
But after running the link shows as https://localhost:44332/UserRoles/CreateRole instead of https://localhost:44332/Admin/UserRoles/CreateRole
Again link the Area to my Homepage returns https://localhost:44332/UserRoles?area=Admininstead of https://localhost:44332/Admin/UserRoles
This is how my routes are configured
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapAreaControllerRoute(
"admin",
"Admin",
"Admin/{controller=Home}/{action=Index}/{id?}");
endpoints.MapAreaControllerRoute(
"client",
"Client",
"Client/{controller=Home}/{action=Index}/{id?}");
endpoints.MapAreaControllerRoute(
"investor",
"investor",
"Investor/{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
What am I doing wrong. Thanks
I think you need add asp-area tag helper:
<a class="btn btn-primary" asp-area="Products" asp-controller="Admin" asp-action="CreateRole">Create Role</a>
OR
#Html.ActionLink("Admin/UserRoles/CreateRole", "CreateRole", "UserRoles",new { area = "Admin" })
Click Here For more information
I found a solution. You should modify the order to make the Areas route first :
endpoints.MapAreaControllerRoute(
"area",
"Admin",
"{area:exists}/{controller=Home}/{action=Index}/{id?}"
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
It worked for me
I have an ASP .Net core MVC 2.0 app where I implemented a shopping cart for an e-commerce site as outlined in this video series. In the app, user can enter search queries for items which are displayed in a table. Each item in the table can be clicked on to display another page that has additional details for that item as well as a add to cart button.
The site features for searching, displaying the item results, and the details page are all implemented as actions in one controller class while the shopping cart functionality is all implemented in a separate controller class.
For some reason, when I click on the "Add to Cart" button for an item, a url of the form http://<hostname>/<controllerName>/<controllerACtion>/<id>is requested, but the corresponding controller action isn't called. This is strange because I'm using essentially the same code to call the action for adding to shopping cart as I did for displaying details. For this reason, I think the issue is related to the setup of the routes.
Here is the route setup in startup.cs:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=resortDeals}/{action=Index}/{id?}");
routes.MapRoute(
name: "shoppingcart",
template: "{controller=ShoppingCartController}/{action=AddToShopingCart}/{id?}");
});
Here is the shopping cart controller structure:
public class ShoppingCartController : Controller
{
public ViewResult Index()
{
...
}
public RedirectToActionResult AddToShopingCart(int dealId)
{
...
}
}
Below is the code for how the action is being called once the add to cart button is clicked:
<div class="addToCart text-right">
<p class="button ">
<a class="btn btn-success" id="cartButton" asp-controller="ShoppingCartController" asp-action="AddToShoppingCart" asp-route-id="#Model.RecNo">
Add to cart
</a>
</p>
</div>
What could be preventing the controller action from being called once the button is clicked?
I had an issue after publishing on the production server, when clicking on the button there was no response and I had to submit the button using Javascript.
<div class="addToCart text-right">
<p class="button ">
<button class="btn btn-success" onclick="search(#Model.RecNo)">
Add to cart
</button>
</p>
</div>
<script>
function addToCart(recNo) {
document.getElementById('cartForm').action = "/ShoppingCart/AddToShoppingCart/" + recNo;
document.getElementById('cartForm').submit();
}
</script>
I don't think you need the following route because the default route will handle the shoppingcart routes as well.
template: "{controller=ShoppingCartController}/{action=AddToShopingCart}/{id?}");
Also, try
<a class="btn btn-success" id="cartButton" asp-controller="ShoppingCart" asp-action="AddToShoppingCart" asp-route-id="#Model.RecNo">
I have removed the Controller word from asp-controller attribute
Also, change the input parameter name of AddToShopingCart method to id instead of dealId
public RedirectToActionResult AddToShopingCart(int id)
{
...
}
I'm using Symfony , I wanna redirect the user to a specific frame in a page
So How can i translate this <a href="index.html#about"/> to twig ? I tried <a href="{{path('pl_index')}}#about"/> but it doesnt work
in twig you can use {{path('_welcome') }} and it will send you to your home index, check your route.yml and you can see what are the paths generated by symfony.
for example this is my config.yml:
//savabundle config.yml
sava_inventario_construccion:
path: /productos/construccion
defaults: { _controller: savaInventarioBundle:Inventario:construccion }
sava_inventario_index:
path: /productos/
defaults: { _controller: savaInventarioBundle:Inventario:index }
if i want to generate www.mypage.com/productos/construccion#about link, this is what my html should look like
<a href="{{path('sava_inventario_construccion') }}#about"/>
you can read more in here
http://symfony.com/doc/current/book/templating.html
This is my routing:
myapp_upgradeAccount:
path: /upgradeAccount
defaults: { _controller: myapp:UpgradeAccount:index }
myapp_checkUsernameForUpgrade:
path: /upgradeAccount/check/{username}
defaults: { _controller: myapp:UpgradeAccount:checkUsername }
methods: [GET]
and this is my form
<form method="get" action="upgradeAccount/check">
<label for="username">Insert your username:</label>
<input name="username" type="text">
<input id="chech-username-for-upgrade" class="green" type="submit" value="Check">
...
But everytime I submit the form I get this error:
No route found for "GET /upgradeAccount/check"
The problem is that when I submit the form, I get the following URL:
http://localhost/app_dev.php/upgradeAccount/check?username=123
when i think I should be getting
http://localhost/app_dev.php/upgradeAccount/check/123
If I trz the latter manually, it works allright. What am I missing?
This is the way HTML forms work.
From w3.org:
get: With the HTTP "get" method, the form data set is appended to the
URI specified by the action attribute (with a question-mark ("?") as
separator) and this new URI is sent to the processing agent.
To do what you want to do keeping the GET method, you have to define your route as:
myapp_checkUsernameForUpgrade:
path: /upgradeAccount/check
defaults: { _controller: myapp:UpgradeAccount:checkUsername }
methods: [GET]
And in your controller, you access the query string parameter with:
if(!is_null($this->getRequest()->get('username'))
{
//Do your stuff
}
EDIT:
If you want your user to be redirected to a url formatted as upgradeAccount/check/{username}, you can either do it with JavaScript (as suggested in #usoban answer) or inside the controller using Redirect:
//path: /upgradeAccount/check
public function check()
{
if(!is_null($this->get('request')->request->get('username')))
return $this->redirect($this->generateUrl('myapp_checkUsernameForUpgrade', array('username' => $this->get('request')->request->get('username'))));
//By default, return the view with your form asking the username
return $this->render('AcmeHelloBundle:Hello:index.html.twig');
}
//path: /upgradeAccount/check/{username}
public function checkUsername($username)
{
//Do some fun stuff with $username coming from the url
}
Then in your view, the form signatures becomes:
<form method="post" action="upgradeAccount/check">
<label for="username">Insert your username:</label>
<input name="username" type="text">
<!-- additionnal fields -->
<input id="chech-username-for-upgrade" class="green" type="submit" value="Check">
</form>
And your route:
myapp_check:
path: /upgradeAccount/check
defaults: { _controller: myapp:UpgradeAccount:check }
methods: [POST]
myapp_checkUsernameForUpgrade:
path: /upgradeAccount/check/{username}
defaults: { _controller: myapp:UpgradeAccount:checkUsername }
methods: [GET]
You need to generate routes that take parameters.
so you would need to do
<form method="get" action="{{path('your_route_name', {username:'usernmae'})">
However this obviously won't quite work for you since you do not know the username until they enter it. You could look into the FOSJsRoutingBundle but this will require javascript. Not the best solution, but it will work. Otherwise you will need to remove the username parameter
As #cheesemacfly mentioned, that is how forms work :)
To get it woking myself, I used some javascript. Let's assume you're using jQuery:
<form method="get" action="upgradeAccount/check/___username___" id="my_form">
...
<input name="username" type="text" id="username">
$(document).ready(function(){
$('#my_form').submit(function(evt){
var username = $('#username').val(),
action = $(this).attr('action').replace(/___username___/g, username);
if (/* empty or whatever 'validation' */) {
evt.preventDefault(); // stop the form from submitting
return false;
}
$(this).attr('action', action);
return true;
});
});
I have built an mvc 4 website, and I built it so that the main layout page doesn't refresh if a different section is loaded with jQuery. I put the navigator and jQuery script in _Layout.cshtml:
<ul id="menu" class="menu-items">
<li><a id="Item1" href="#" onclick="loadPage(this.id)">Item1</a></li>
<li><a id="Item2" href="#" onclick="loadPage(this.id)">Item2</a></li>
<li><a id="Item3" href="#" onclick="loadPage(this.id)">Item3</a></li>
<li><a id="Item4" href="#" onclick="loadPage(this.id)">Item4</a></li>
</ul>
</body>
<script>
function loadPage(action) {
$.post("/Home/" + action, function (data) {
$(content).html(data);
});
}
</script>
Then I have my controller:
namespace MyApp.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Item1()
{
if (Request.IsAjaxRequest())
{
return PartialView();
}
return View();
}
[HttpPost]
public ActionResult Item2()
{
if (Request.IsAjaxRequest())
{
return PartialView();
}
return View();
}
Etc, etc.
Everything works fine, except that I don't know how to use just one main content view (which is index.cshtml when the website loads in the browser). I'm forced to put the same content that's in index.cshtml into item1.cshtml so that when I trigger onlick for item1, it will go back to the main content. The only route config I have is for the Default, which initially set to Index:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
What I want, is to be able to use just one main content page, but have the ajax call still get me back to the main content when I click Item1. Does anyone know what I need to do? It seems to be a little overkill to have to update both views when I want to update the main content.
Also, I think other web devs will like this code. Especially if you're building a band's website like I'm doing. It allows me to put the demo song media player in the _layout.cshtml page so that it won't refresh when the user is clicking to the other sections (i.e. if it refreshes, the media player stops). With this design, the user can navigate the whole website while the songs continue to play.
I'm rather new to javascript, so I'm sure I could have made a better onclick handler rather than using anchor tags, so if anyone want to show me a better way, please do. But my main problem is the index.cshtml vs item1.cshtml dilemma.
Correct me if I'm wrong: you want to refresh part of your page when clicking on ItemX link and the controller methods ItemX are only used via Ajax (as you're building a single page app).
In this case you could do something like this:
Cshtml
<ul id="menu" class="menu-items">
<li><a id="Item1" href="#" onclick="loadPage(this.id)">Item1</a></li>
<li><a id="Item2" href="#" onclick="loadPage(this.id)">Item2</a></li>
<li><a id="Item3" href="#" onclick="loadPage(this.id)">Item3</a></li>
<li><a id="Item4" href="#" onclick="loadPage(this.id)">Item4</a></li>
</ul>
<div id="container">
</div>
</body>
<script>
function loadPage(action) {
$.post("/Home/" + action, function (data) {
$("#container").html(data);
});
}
// Will load Item1 via Ajax on page load
loadPage('Item1');
</script>
Home Controller
[HttpPost]
public ActionResult Item1()
{
return PartialView();
}
Your PartialViews should only contain the HTML specific to the current item.
Update
If you wish to avoid the Ajax call you could do this also in your cshml
...
</ul>
<div id="container">
#Html.Partial("Item1PartialView")
</div>
</body>
...