Nerd dinner error on Ajax call to Register action method
I'm new to MVC and I'm implementing the Nerd Dinner MVC sample app in MS MVC2. I'm on step 10, "Ajax enabling RSVPs accepts"开发者_开发问答. I've added the new RSVP controller and added the Register action method like so:
public class RSVPController : Controller
{
DinnerRepository dinnerRepository = new DinnerRepository();
//
// AJAX: /Dinners/RSVPForEvent/1
[Authorize, AcceptVerbs(HttpVerbs.Post)]
public ActionResult Register(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
if (!dinner.IsUserRegistered(User.Identity.Name)) {
RSVP rsvp = new RSVP();
rsvp.AttendeeName = User.Identity.Name;
dinner.RSVPs.Add(rsvp);
dinnerRepository.Save();
}
return Content("Thanks - we'll see you there!");
}
}
I added the references to both Ajax script libraries and added the code below to the Details view as described in the article:
<div id="rsvpmsg">
<% if(Request.IsAuthenticated) { %>
<% if(Model.IsUserRegistered(Context.User.Identity.Name)) { %>
<p>You are registred for this event!</p>
<% } else { %>
<%= Ajax.ActionLink( "RSVP for this event",
"Register", "RSVP",
new { id=Model.DinnerID },
new AjaxOptions { UpdateTargetId="rsvpmsg"}) %>
<% } %>
<% } else { %>
<a href="/Account/Logon">Logon</a> to RSVP for this event.
<% } %>
</div>
When I click the "RSVP for this event" link I get a 404 eror saying the resource cannot be found:
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: /NerdDinner/RSVP/Register/24
Version Information: Microsoft .NET Framework Version:2.0.50727.4200; ASP.NET Version:2.0.50727.4205
When I step into the code it is finding the Register action method correctly. After playing around with it I removed the "AcceptVerbs(HttpVerbs.Post)" from the constraint on the Register method, and it then worked. However it didn't reload the page it just displayed the "Thanks - we'll see you there" message on a new blank page. Looking at the html in the details page there is no Form submit taking place, so I'm wondering does the Ajax code need something more to make the call a Post? Is there a known issue with this part of the Nerd Dinner app? I think the app was written in MVC1 and I'm using MVC2 - does this make a diference?
TIA,
Ciaran
The PDF tutorial (versus the online HTML version) has typographic ANSI quote characters (0x94) rather than ASCII (0x22) in the HTML block of script elements. The correct block is shown below with all of the quote characters replaced.
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
Visual Studio will mark the JavaScript source files with the Warning green squiggles ("File not found") but not the type attributes so you may notice and correct the problem only for the source files. However, the type
attributes will still be malformed and this will cause the scripts not to be loaded correctly in the browser.
Using the Chrome developer tools, I noticed that the scripts were not listed as Resources for the Details HTML page. Correcting the quote characters for the type
attributes allowed the Register action to work as documented in the tutorial with no changes.
This portion of your action explains why you just get the "see you there" message:
return Content("Thanks - we'll see you there!");
That's all that's being returned.
The reason you were getting a 404 to begin with is the use of an actionlink:
Ajax.ActionLink(...
That will create a URL link, a GET not a POST, and the AcceptVerbs(HttpVerbs.Post)
would have forced no match. You should submit a form to do a post:
using (Ajax.BeginForm("Controller", "Action", new AjaxOptions { UpdateTargetId = "f1" } )) { %>
<div id="f1">
<!-- form fields here -->
<input type="submit" />
</div>
<% } %>
As an additional comment to debugging issues with this problem, being a Java/JSF developer, I ran into a hard lesson that
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript" />
and
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
are processed differently. The first not working at all and the second working correctly.
This is the Details.cshtml used in MVC3. The problem with redirecting using GET, and not POST is similar.
<div id="rsvpmsg">
@if (Request.IsAuthenticated)
{
if (Model.IsUserRegistered(Context.User.Identity.Name))
{
<p>
You are registered for this event</p>
}
else
{
@Ajax.ActionLink("RSVP for this event",
"Register",
"RSVP",
new { id = Model.DinnerID },
new AjaxOptions { UpdateTargetId = "rsvpmsg", HttpMethod = "Post" })
}
}
else
{
<p>
<a href="/Account/Logon">Logon</a> to RSVP for this event.</p>
}
</div>
@section JavaScript
{
<script src="@Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript"></script>;
<script src="@Url.Content("~/Scripts/MicrosoftMvcAjax.js")" type="text/javascript"></script>;
}
Ok, so previously i have mentioned that i had the same problem, and it comes from the fact that MVC 3 uses unobtrusive JavaScript.
To make this work, you have 2 solutions, one is to disable Unobtrusive Javascript in your webconfig file:
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
Just set it to false, and during page build, javascript generated for the Action link will be normal inline javascript, that works fine, and results with something like this in HTML:
<a onclick="Sys.Mvc.AsyncHyperlink.handleClick(this, new Sys.UI.DomEvent(event),
{ insertionMode: Sys.Mvc.InsertionMode.replace, httpMethod: 'Post', updateTargetId: 'rsvpmsg' });" href="/RSVP/Register/13">RSVP for this event</a>
Second solution is more to my liking and it is just as simple. You just have to include additional javascript source file in your header:
<head>
<title>@ViewBag.Title</title>
<link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
@RenderSection("JavaScript",required:false)
</head>
The resulting javascript generated is unobtrusive, and results with this in HTML:
RSVP for this event
In both cases the resulting functionality is the same, and the second solution is "more in spirit" of new MVC 3.
Just in case it helps someone else, i had the problem using MVC 3 and it was because I had linked to the MS AJAX libraries and MVC 3 actually uses jQuery by default so I just needed to uncomment the links in my master page and it was fine.
To make an http post with Ajax.ActionLink
, you'd have to do e.g. new AjaxOptions { UpdateTargetId="rsvpmsg",HttpMethod="POST"}
if you include those two in your site.master
, it should be fine
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
I was trying to convert to MVC3/Razor as I worked through this example. I've been stuck on this exact same issue for at least 24 hours now...exact same symptoms. I tried everything on this page that I could understand or thought was relevant.
I didn't have the unobtrusive javascript mention in my web.config and was considering adding it with the "false" value thinking "true" might be the default. However, I was thinking it might screw something else up (among who knows what else).
I found the following tid-bit over on the wrox forum. If I add the following line of code to the second line of my RSVPStatus.cshtml partial view:
<script src="/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
Everything works as intended. I know Zak mentioned that line of code above (and a bunch of other stuff that lead me in the right direction), but I was using the partial view and haven't seen a head tag since I started messing with MVC. I know it's probably there somewhere, but all the smoke and mirrors of what is MS programming now, makes it harder to dissect and I probably would have gone down Zak's path at some point. So, +1 for him.
Anyway, hope this helps someone save a day.
精彩评论