I've been working on a relatively simple application in ASP.NET Core that displays the status of various nodes in a network. It displays their latest status, and some other information.
For this, I've made a controller which has an action that takes a node's name, performs a lookup in the node manager, and returns the detail view for that specific node. This controller action is implemented like so:
public IActionResult Detail(string name)
{
// Maybe redirect this to the node detail overview once it's done?
if (string.IsNullOrEmpty(name))
return View("PageNotFound");
var viewModel =
Current.NodeManager.Statuses.FirstOrDefault(s => s.Node.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
if (viewModel == null)
return View("PageNotFound");
return View(viewModel);
}
I'm linking to this action from my overview page. The HTML I'm using to do this is:
<a asp-area="" asp-controller="Node" asp-action="Detail" asp-route-id="#status.Node.Name">#status.Node.DisplayName</a>
For one of my nodes, this produces the following link:
http://example.com/Node/Detail/Temeria
And from what I understand from the ASP.NET Core documentation, the controller should capture "Temeria" here as the argument for the Detail action of NodeController, but it reliably refuses to do so. name here is always null.
I've also messed around with the routing in Startup.Configure, by adding the following route to the controller:
routes.MapRoute(
name: "Node Detail",
template: "{controller=Node}/{action=Detail}/{name}");
But unfortunately, to no avail. Every time I invoke the action, be it via clicking the link I've outlined above, or visiting the detail action manually by typing in the URL in my browser, ASP.NET Core spits out the following log line:
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method Aegis.Controllers.NodeController.Detail (Aegis) with arguments () - ModelState is Valid
I'm at a loss here - am I missing something really obvious here, or does ASP.NET Core not work with primitive types and should I resort to the "model binding" I've been seeing in the guides (which seems to be a bit overkill for an action as simple as this one)?
I've seen various other questions similar to this one, but none of them were for ASP.NET Core. I've done similar projects in classic ASP.NET, and never had this issue with that framework.
Any help would be greatly appreciated. Thanks for your time!
The key is in this line:
<a asp-area="" asp-controller="Node" asp-action="Detail" asp-route-id="#status.Node.Name">#status.Node.DisplayName</a>
I've changed asp-route-id to asp-route-name and everything works fine. So the answer is:
<a asp-area="" asp-controller="Node" asp-action="Detail" asp-route-name="#status.Node.Name">#status.Node.DisplayName</a>
Related
here is the code from my cshtml file
<button type="button" class="button js-book-class" onclick="#Url.Action("BookTheClass", "MemberArea", new { ClassID = Aclass.ClassID })">Book Now</button>
and here my function inside MemberAreaController.cs
[HttpPost]
public ContentResult BookTheClass(int ClassID)
{
Class selectedClass= _context.classes.Find(ClassID);
selectedClass.spaceUsed++;
_context.SaveChanges();
return Content(ClassID.ToString());//just for testing
}
This is because you have conflict.
Url.Action generates a href link, which in click, will execute a browser navigation, which means GET request.
While your server BookTheClass action is expected to be called when executing a POST.
The easy fix which in this case is also the not so good solution, is to change your method to [HttpGet] (which i believe is the default) and it will be resolved.
The more accurate solution, will be to create a form element and making the button submit the data, this will acquire you a change only in HTML and not server side.
The reason i think you should stick to Post, is because i believe in the notion that GET should be consider as a query like, and that identical requests should have the same response.
Whereas Post should have the role of Actions which result in side-effects. which in Rest, means Creation. But as general rule of changing a state in the server as a result.
I'm getting the error
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /ClientEdit/ClientEdit/1104
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.272
when I add HttpPost attribute to a controller. I've looked into this and corrected my code with posted(no pun intended) answers but nothing I've tried works. Here's my controller header:
[HttpPost]
public ActionResult ClientEdit(int id,FormCollection formCollection)
I added HttpPost so I can populate my FormCollection object. As with other SO posts, this causes the error. Removing it solves the issue but my FormCollection doesn't populate any key/value pairs.
My view has its form tag's method set to POST which solved other dev's issues but it doesn't solve mine. I tried adding 'name=' properties to my textbox controls as well as 'id=' but that doesn't work either.
<body>
<form method="post" action="1104" id="form1">
I don't know what else to try.
You need to provide you view that renders the <form> as well. The action on what you show as your HTML looks wrong to me. I would think it would be something like action="/Controller/ClientEdit".
you have given wrong value in the attribute action="1104".
Either you can specify proper route in action attribute or leave it if the route is same as of get.
This should work if GET and POST route are same
<form method="post" id="form1">
.....
</form>
use this:
#using(Html.BeginForm()){
<!--Your form field-->
}
Basically what is happening is that your action attribute is just pointing to the Id you have and not the url to post to.
You can do it manually like this:
<form action="ClientEdit/ClientEdit/1104>
<!--form fields-->
</form>
Yes, you are all correct. I was passing a userid as the action. This was legacy code that 'worked' for another feature but doesn't conform to the MVC pattern. I did some other research (as I'm not too familiar with MVC either) and started again from scratch using MVC as it should be. Thanks everyone.
I'm having a little problem i hope someone can help me with.
on ASP.net MVC 4 (C#) i need to be able to edit the parameters of my route from my controller.
example the request url is
MyController/MyAction/param1/param2
now from MyAction I need to edit the returned url so that it displays
MyController/MyAction/Modifiedparam1/Modifiedparam2
The purpose of this is to translate the parameters that i retrieve from my database from language changes.
Please use redirect result for this (in MyAction on some condition):
return RedirectToAction("MyAction", { param1Name = Modifiedparam1, param2Name = Modifiedparam2 };
Basically you cannot modify url in controller. Urls is something send by the browser to invoke some action. You may just say browser to redirect user to another url.
Don't fight with framework. It will fight back sooner or later. Instead follow mvc principles, redirect from controller action or filters/interceptors to do so.
So I saw this question here on SO, but it hasn't really solved this problem for me.
I have an ASP.NET MVC 3 + Razor app running on IIS5 on my dev pc, and then IIS6 for my dev web server. Everything worked great until I deployed it. I am bin deploying everything, with no problems on that front (that I can tell).
Now I am getting this Child actions are not allowed to perform redirect actions error on my page. I am not sure how to pinpoint where it is failing.
I'm using #Html.Action to pull in some drop down boxes with data:
public ActionResult Hierarchy()
{
List<Store> storeList = DBService.getStores();
if (DBService.Error != null)
return RedirectToError(DBService.Error);
List<Department> deptList = DBService.getDepts();
if (DBService.Error != null)
return RedirectToError(DBService.Error);
VM_Hierarchy hierarchy = new VM_Hierarchy(storeList, deptList);
return View(hierarchy);
}
If I remove the #Html.Action line, the page will render. It will then break if I do an AJAX request to a controller action such as this:
[HttpPost]
public ActionResult InventoryList(string fromDate, string toDate)
{
List<Inventory> inventories = DBService.getInventories(fromDate, toDate);
if (DBService.Error != null)
return RedirectToAction("Error");
return View(inventories);
}
If this isn't correct, how am I supposed to redirect to an error page or dictate what view gets returned on a post? Any help is appreciated. Thanks.
It's probably because you're getting errors from your DB service when it's deployed, which you aren't getting locally. This is causing it to try and redirect from a child action, which you can't do.
You might want to try getting the drop-down data in your main action, and put it all in a ViewModel, so you aren't using child actions. If this fails, you can redirect to your heart's content. For the AJAX, you'll need to handle the errors on the client and do something sensible, you can't just return a redirection from an AJAX call.
This question has some further info:
Why are Redirect Results not allowed in Child Actions in Asp.net MVC 2
if you put in the child action
(ControllerContext.ParentActionViewContext.Controller as System.Web.Mvc.Controller).Response.Redirect(Url.Action("Action", "Controller")); it will redirect from the childaction.
I had a similar problem but for the life of me, I couldn't figure out where the redirection was coming from. Once I figured it out, I thought I'd post an answer in case it happens to anyone else.
If the source of the redirection is not apparent from the imperative code, e.g.:
[AuthoriseThis]
public ActionResult Details(SomethingModel something)
{
return PartialView(something);
}
Look at the declarative code!
In my case, it was an authorisation problem, so the attribute was causing the redirection, and my eyes were filtering out the existence of the attribute.
I have an existing site that I'd like to convert to use routing, and after reading Scott Guthrie's post here, I built a working sample that works for most circumstances. However, since not all of the pages on the existing site match a particular pattern, I'll need to check against a database to determine which route (destination .aspx page) to use.
For example, most pages are like this:
http://www.mysite.com/people/person.html
This is fine - I can easily route these to the view_person.aspx page because of the 'people' directory.
But some pages are like this:
http://www.mysite.com/category_page.html
http://www.mysite.com/product_page.html
This necessitates checking the database to see whether to route to the view_category.aspx page or the view_product.aspx page. And this is where I'm stuck. Do I create an IRouteHandler that checks the database and returns the route? Or is there a better way? The only code I've found that kind of fits is the answer to this question.
Thanks in advance.
If you don't mind doing so, the cleanest solution is to:
http://www.mysite.com/pages/category_page.html
In ASP.NET MVC, this situation would be handled a little differently, by specifying a default controller and action method on the root route.
Your route handler doesn't check the database. It sends all the requests to a handler .aspx script. It's that script that checks the database.
My register route looks like...
private static void RegisterRoutes()
{
Route currRoute = new Route("{resource}.axd/{*pathInfo}",
new StopRoutingHandler());
RouteTable.Routes.Add( "IgnoreHandlers", currRoute);
currRoute = new Route("{urlname}",
new EPCRouteHandler("~/Default.aspx"));
currRoute.Defaults = new RouteValueDictionary {{"urlname", "index.html"}};
RouteTable.Routes.Add( "Default", currRoute);
}
The custom handler, which shouldn't be needed in ASP.Net 4.0, simply passes the urlname parameter to the responding script as a URL variable.
Now how often the responding script checks the database depends on how often the data in the database is changed. You can easily cache paths and invalidate the cache when the data is suppose to have changed for instance.
For anyone stuck in the same situation, I ended up adapting the code from this answer to check against a database and return the proper ASPX page.