Action method not found in controller - asp.net

I am using 'Pro ASP.NET MVC 5' book by Adam Freeman, working on the Sports Store Web Application that he is using. I tried to redo that example into Computer Store instead and everything was working fine up to the moment when I needed to add extra functionality to the cart ('Summary' partial view).
The 'Summary' PartialView is defined in the Cart Controller:
public PartialViewResult Summary(Cart cart)
{
return PartialView(cart);
}
The Summary View:
#model ComputerStore.Domain.Entities.Cart
#{
ViewBag.Title = "Summary";
}
<div class="navbar-right">
#Html.ActionLink("Checkout", "Index", "Cart",
new { returnUrl = Request.Url.PathAndQuery},
new { #class = "btn btn-default navbar-btn"})
</div>
<div class="navbar-text navbar-right">
<b>Your cart:</b>
#Model.Lines.Sum(x => x.Quantity) item(s),
#Model.CaluclateTotalValue().ToString("c")
</div>
And of course, in the _Layout.cshtml file, I call the Action Method:
#Html.Action("Summary", "Cart")
When I start the Web Application, I get the following error:
-A public action method 'Summary' was not found on controller 'ComputerStore.WebUI.Controllers.CartController'.
Now, before we mention HttpPost and HttpGet, let me inform you that the Sports Store example works fine using the same code as above. I have tried numerous ways to fix this, and I know that this has been answered multiple times here, but I just don't understand why it doesn't work. Moreover, all packages are updates.

You are you requiring a parameter for your Summary.
Try this instead:
[HttpGet]
public PartialViewResult Summary()
{
var cart = new Cart();
//Do something with cart to load the data.
return PartialView(cart);
}
If you want to pass a param to Summary you could do:
#Html.Action("Summary", "Cart", new {cart = someExistingCartObject})

Related

Calling method from razor page

I have a asp.net core mvc project.
In my layout file, I want to display the name of the currently logged in user, such that the username is displayed in the header. For this, I want to be able to call a function in my homecontroller that does this.
So, I made a simple function taht looks like this in the home controller:
public String GetLoggedInuser()
{
return "garse garsebro";
}
And then I have tried every method I have been able to find. The first couple of methods here are just function suggested around the web, that are simply not available to me:
#HtmlHelper.Action("GetLoggedInuser");
#Html.RenderAction("GetLoggedInuser");
To name a few. Then there is this one, which I can find:
#Html.ActionLink("GetLoggedInuser")
But for this one, my function "GetLoggedInuser" can't be found anywhere.
How do you, in a razor page call a controller function that you can get returned a string from that function and display it?
If you are using Microsoft.AspNet.Identity then below line will do the work post login.
#Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
You can try to use ajax to call action to get the username,and add it to html:
<div id="username">
</div>
#section scripts
{
<script>
$(function () {
$.ajax({
type: "GET",
url: 'GetLoggedInuser',
}).done(function (result) {
$("#username").html(result);
});
})
</script>
}

How to post parameter value to some actionlink

In my view i have 10 link every link associated with some unique value. Now i want that associated value at my controller action and from that action i want to redirect the flow to some other action based on that value.
But the condition is i dont want to display it on url.
How can i acheive this?
I tried ajax.post/#Ajax.ActionLink but doing this will not facilitate redirect to another action.
Is there anything with route i need to do?
View
<ul>#foreach (var item in Model)
{<li>
#Ajax.ActionLink(item.pk_name, "Index","Candidate", new { para1= item.para1 }
, new AjaxOptions { HttpMethod = "POST" })</li>
}</ul>
Action
[HttPost]
public ActionResult(int para1)
{
return RedirectToAction(para1,"anotherController");
}
I am getting value at para1 with ajax post(that is what i primarily needed) but here also want to redirect my application flow base on para1 value which is action name.
Confision : here i am not sure is this is the right way to do this thing. So i am asking you guys should i go for route map of working with ajax post will solve my objective.
If you only need to redirect the user based on what he clicks on without showing him the link, I believe the best way to achieve this is by client-side coding.
In my opinion there is no need to take any request through the server in order to change the page for such a low-complexity redirect.
View
// HTML
// Might be broken, been awhile since I worked with MVC
// Can't really remember if that's how you put variables in HTML
<ul id="button-list">
#foreach(var item in Model)
{
<li class="buttonish" data-para1="#item.para1">#item.pk_name</li>
}
</ul>
// JS
// I wouldn't do any server related work
$('#button-list li.buttonish').click(function(){
// Your controller and action just seem to redirect to another controller and send in the parameter
window.location.href = "/controller/method/" + $(this).data('para1');
});
I think you should make one jQuery function that is call when clicked and pass unique parameter.In that function you can use AJAX and post it on appropriate controller method.
Example:
<input type="button" id="#item.pk_name" onclick="getbuttonvalue(#item.para1);" />
In script
<script type="text/javascript">
$(document).ready(function () {
function getbuttonvalue(para1) {
$.ajax({
cache: false,
type: "POST",
dataType: 'json',
url: "/controller/method/" + para1,
success: function (data) {
}
});
}
});
</script>

MVC3 Routing Working 1 Direction Only

I am working on an ASP.NET mvc 3 site that contains several project entities, and then each project has several associated subpages, each that works with a component of the project.
So for instance, I could have a project with several photos, milestones, user info, etc. I have a Project Index view, as well as a Project Home which links to several component pages. Most of the components have two views, Index, and Edit/View.
So I set up a route for the edits and views. Note that my route is in an AREA called ProjectManagement
context.MapRoute(
"ProjectManagement_ProjectPageSingle",
"ProjectManagement/{controller}/{action}/{projectNumber}/{projectChildId}",
new { controller = "Project", action = "Home" }
);
and my controller actions all look similar to this:
public ActionResult Edit(string projectNumber, string projectChildId)
This works well and good when I type in the URL directly in the browser. For instance:
~/ProjectManagement/Milestone/Edit/39999P110175/1
however, when I generate an action link using:
<a href="#Url.Action("Edit", new { projectNumber = Model.Project.ProjectNumber, projectChildId = entry.Id})">
the action URL ends up looking like this:
~/ProjectManagement/Milestone/Edit/39999P110175?projectChildId=1
So the route sorta works...but the action link generator doesn't? Not sure where to go from here. Any advice would be much appreciated.
Note that the same thing occurs while using #Html.ActionLink instead of #Url.Action.
Thanks!
You don't seem to have specified the area name:
#Url.Action(
"Edit",
new {
projectNumber = Model.Project.ProjectNumber,
projectChildId = entry.Id,
area = "ProjectManagement"
}
)
Also make sure that there aren't any other routes that might conflict with this one in your area registration which should look like this:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"ProjectManagement_default",
"ProjectManagement/{controller}/{action}/{projectNumber}/{projectChildId}",
new { controller = "Project", action = "Home" }
);
}
Thanks to Michael for the response. Here's the answer for others.
I had:
context.MapRoute(
"ProjectManagement_ProjectPage",
"ProjectManagement/{controller}/{action}/{projectNumber}",
new { controller = "Project", action = "Home"}
);
///more routes
context.MapRoute(
"ProjectManagement_ProjectPageSingle",
"ProjectManagement/{controller}/{action}/{projectNumber}/{projectChildId}",
new { controller = "Project", action = "Home" }
);
The URL matched the ProjectPage route as well, so it took that one first. Had to flip the order, so the more specific route came first.
Thanks.

Returning data to a partial view

I have a blog that has a sidebar with a partial view in it that enables users to sign up for my e-mail newsfeed. What I'm trying to do is returning the user to the page they came from after posting some data, and displaying any validation or return messages in the form's partial view.
The problem is that my partial view opens in a new window (without the lay-out). How can I fix this so it returns to my blog, with the return data in de sidebar?
This is my view:
#using Blog.Models.Entities
#model Subscriber
<header>
<h2>Subscribe</h2>
</header>
<p>Subscribe to my e-mail newsfeed.</p>
#using (Html.BeginForm("Form", "Subscription"))
{
<div class="editor-label">#Html.LabelFor(subscriber => subscriber.Email)</div>
<div class="editor-field ">#Html.EditorFor(subscriber => subscriber.Email)</div>
#Html.ValidationMessageFor(subscriber => subscriber.Email)
<input type="submit" value="Subscribe" />
<p>#ViewBag.Result</p>
}
And the relevant pieces of controller that are processing the data:
public ActionResult Form()
{
return PartialView("_Form");
}
[HttpPost]
public ActionResult Form(Subscriber subscriber)
{
if (ModelState.IsValid)
{
Subscriber foundSubscriber = _repository.Subscribers.Where(s => s.Email.Equals(subscriber.Email)).FirstOrDefault();
if (foundSubscriber != null)
{
ModelState.AddModelError("Email", "This e-mail address has already been added.");
return PartialView("_Form", subscriber);
}
_repository.SaveSubscriber(subscriber);
ViewBag.Result = "Succesfully subscribed to the newsletter.";
return PartialView("_Form");
}
ModelState.AddModelError("Email", "Please provide a valid e-mail address.");
return PartialView("_Form", subscriber);
}
When submitting a form, the browser sends an HTTP Post request to the server. The browser then displays the Response's payload. Your post Controller Action is returning a PartialView, which the browser is happily rendering (even though it doesn't have the html, head, or body tags necessary to make it truly valid HTML).
It sounds like you want the browser to keep most of your page loaded and rendered, post the form, then take the resulting HTML and only replace a portion of the loaded page. Simply put, the browser isn't smart enough to do that.
What you probably want to do is something like this:
User fills in some form data and clicks save/submit/go/whatever.
However, you don't want the browser to submit the form, because it won't preserve most of the current page the way you want.
Instead, you want the "submit" button to call some local javascript.
That local JS should bundle up the user-entered form data, craft a POST with that data as the payload, and submit the POST using Ajax. This will keep the current page loaded, while the ajax request hits your Controller Action
You controller action stays the way it is, and returns a partial view.
Your JS function that launched the Ajax call must also define a "success" function which will get called when the operation completes.
Within that success function, your javascript will grab the HTML from the response, and use it to replace the area of the page that held the original form.
I highly recommend jQuery - it will make it MUCH easier to craft the Ajax request, handle the success callback, and replace just a section of the currently-loaded page with the result. My understanding is that MS's 'unobtrubsive javascript' may also help implement this, however I don't have any direct experience with it.
Obviously, all of this will only work if the browser has javascript enabled.
I finally found the solution to the problem. I implemented it with AJAX and ended up with the following code:
_Index.cshtml
<header>
<h2>Subscribe</h2>
</header>
<p>Subscribe to my e-mail newsfeed.</p>
<div id="subscription-form">
#{Html.RenderPartial("_Form");}
</div>
_Form.cshtml
#using Blog.Models.Entities
#model Subscriber
#{
AjaxOptions ajaxOptions = new AjaxOptions
{
LoadingElementId = "loading",
LoadingElementDuration = 2000,
HttpMethod = "Post",
UpdateTargetId = "subscription-form"
};
}
<div id="loading" style="display: none;">
<p>Processing request...</p>
</div>
#using (Ajax.BeginForm("Index", "Subscription", ajaxOptions))
{
<div class="editor-label">#Html.LabelFor(subscriber => subscriber.Email)</div>
<div class="editor-field ">#Html.EditorFor(subscriber => subscriber.Email)</div>
#Html.ValidationMessageFor(subscriber => subscriber.Email)
<input type="submit" value="Subscribe" />
}
_Succes.cshtml
#using Blog.Models.Entities
#model Subscriber
<p id="subscription-result">#ViewBag.Result</p>
And the following controller action methods:
public ActionResult Index()
{
return PartialView("_Index");
}
[HttpPost]
public PartialViewResult Index(Subscriber subscriber)
{
if (ModelState.IsValid)
{
Subscriber foundSubscriber = _repository.Subscribers.Where(s => s.Email.Equals(subscriber.Email)).FirstOrDefault();
if (foundSubscriber != null)
{
ModelState.AddModelError("Email", "This e-mail address has already been added.");
return PartialView("_Form", subscriber);
}
_repository.SaveSubscriber(subscriber);
ViewBag.Result = "Succesfully subscribed to the newsletter.";
return PartialView("_Succes", subscriber);
}
ModelState.AddModelError("Email", "Please provide a valid e-mail address.");
return PartialView("_Form", subscriber);
}
I hope this will help anyone trying to achieve the same in the future. BTW, I found the solution on this blog: http://xhalent.wordpress.com/2011/02/05/using-unobtrusive-ajax-forms-in-asp-net-mvc3/.

ASP.NET MVC 2 Areas 404

Has anyone been able to get the Areas in ASP.NET MVC 2 to work?
I created a new Area called "Secure" and placed a new controller in it named HomeController. I then Created a new Home/Index.aspx view. However, when I browse to http://localhost/myapp/Secure/ it gives a 404 resource cannot be found. http://localhost/myapp/Secure/Home gives the same error.
My area registration looks like this:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Secure_default",
"Secure/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
I also tried this:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Secure_default",
"Secure/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Thanks,
Justin
I am pretty sure it was because your area registration class was in a different namespace that the project it was hosted in. It would explain why your solution worked - you registered it with the overload that takes in the namespace. I had a similar issue and it was fixed by correcting the namespace.
Sure, i've got Areas working with ASP.NET MVC 2.
Its hard for people to debug routes over SO, the easiest way is for you to use Phil Haacks Route Debugger. It'll tell you what routes (and areas) are being resolved for a particular URL. Extremely handy.
However ill take a stab, try changing your route to this:
context.MapRoute(
"Secure_default",
"Secure",
new { action = "Index", controller = "Home", id = UrlParameter.Optional }
);
The url (<yourhost>/Secure) will find your area Secure but not know which controller you hand the request to, as you have not specified a default value for controller in your areas route.
Here's my setup:
Areas
Albums
Controllers
AlbumsController.cs (namespace Web.Areas.Albums.Controllers)
Models
Views
Albums
Index.aspxx
AlbumsAreaRegistration.cs
context.MapRoute(
"Albums_Default",
"Albums",
new { controller = "Albums", action = "Index", id = UrlParameter.Optional)
The URL: http://localhost/Albums triggers the "Index" action of my "AlbumsController" in my "Albums" area.
What does you structure look like?
I got it working, the answer was to change the area registration class to this:
context.MapRoute(
"Secure_Default", // Route name
"Secure/{controller}/{action}/{id}", // URL with parameters
new { area="Secure", controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new[] { typeof(Controllers.HomeController).Namespace }
);
I have no idea why it worked for another developer and not for me, also I feel like it should "just work" out of the box when you create a new Area, you shouldn't have to fiddle with the route mapping.
Anyway, thanks all for the help and I'm giving the answer to RPM for all his hard work.
Are you calling AreaRegistration.RegisterAllAreas() in your global.asax?
Sub Application_Start()
AreaRegistration.RegisterAllAreas()
RegisterRoutes(RouteTable.Routes)
End Sub
Have you tried using http://localhost/myapp/Secure/Home/index ? I find so many times that when I use index as the view name and don't specify it in the path it never works. It should work but it never works for me.
I don't like calling my views index anyways so not a big deal for me.

Resources