Why is my Account Register view not working? - asp.net-mvc

I'm having problem getting my view to display. I'm creating a link
#Html.ActionLink("Add as user", "Register", "Account")
but when I click on it, I'm getting this message:
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: /Account/Register
Here's my view:
#model ContactWeb.Models.SimpleUser
#{
ViewBag.Title = "CreateUser";
}
<h2>Create User</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true);
<fieldset>
<legend>Create User</legend>
<div>
#Html.LabelFor(c=>c.Username, "User Name")
#Html.TextBoxFor(c=>c.Username)
#Html.ValidationMessageFor(c=>c.Username)
</div>
<div>
#Html.LabelFor(c=>c.Password, "Password")
#Html.TextBoxFor(c=>c.Password)
#Html.ValidationMessageFor(c=>c.Password)
</div>
<div>
#Html.LabelFor(c=>c.ConfirmPassword, "Confirm Password")
#Html.TextBoxFor(c=>c.ConfirmPassword)
#Html.ValidationMessageFor(c=>c.ConfirmPassword)
</div>
<p>
<input type="submit" value="Register" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "List")
</div>
and my controller is
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
MembershipCreateStatus createStatus;
Membership.CreateUser(model.UserName, model.Password, null, null, null, true, null, out createStatus);
if (createStatus == MembershipCreateStatus.Success)
{
FormsAuthentication.SetAuthCookie(model.UserName, false);
return RedirectToAction("List", "Contact");
}
else
{
ModelState.AddModelError("", "The username or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}

You do want an overload of the Register method for the initial GET request, but it should not have any parameters:
[HttpGet]
public ActionResult Register()
{
return View(new RegisterModel());
}
[HttpPost]
public ActionResult Register(RegisterModel model)
{
// your existing implementation here that
// checks ModelState and creates the user record
}
This will allow displaying a form with empty/default values when first loading the /Account/Register URL. This will prevent the "already defines a method with the same parameter types" and thus allow the code to compile. Also, I think you will find this advantageous to having just one Register method with no HttpPost attribute because it allows you to have a separate POST-only method to implement the postback logic, and a simpler GET-only method for the initial display. You could even customize the GET-only display to populate the model/view with certain initial values, etc.

Your register action is decorated with [HttpPost] attribute, that means that action can handle only HTTP POST requests. Ordinary links make GET requests, and as there's no handler for GET, you get 404 - not found. To fix this, create another action that will handle GET requests
[HttpGet]
public ActionResult Register()
{
return View();
}
This action will return page, with registration form on it.

Related

Two strongly types partial views in one razor view

I am using Asp.Net identity logic module for authentication process. I am using this theme for login and signup and external logins all in one view.
Here is my Login.cshtml view that contain social login, register and login partials
#using Helping.ViewModels
#{
ViewBag.Title = "Log in";
}
<div class="container">
<div class="row">
<br />
<br />
<div class="col-lg-4">
<div>
<section id="socialLoginForm">
#Html.Partial("_ExternalLoginsListPartial", new ExternalLoginListViewModel { Action = "ExternalLogin", ReturnUrl = ViewBag.ReturnUrl })
</section>
</div>
</div>
<div class="col-lg-4">
<h2><b>Sign Up</b></h2>
<hr />
#Html.Partial("Register")
</div>
<div class="col-lg-4">
<h2><b>Log In</b></h2>
<hr />
#Html.Partial("LocalLogin")
</div>
</div>
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
LocalLogin and Register are the strongly typed partial views.Problem is that when I try to Login with a user that doesnot exist it returns the model , here is the action
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindAsync(model.UserName, model.Password);
if (user != null)
{
if (!await UserManager.IsEmailConfirmedAsync(user.Id))
{
string callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Confirm your account-Resend");
ViewBag.errorMessage = "You must have a confirmed email to log on.";
return View("Error");
}
else
{
await SignInAsync(user, model.RememberMe);
return RedirectToLocal(returnUrl);
}
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
It return following error
The model item passed into the dictionary is of type 'Helping.ViewModels.LoginViewModel', but this dictionary requires a model item of type 'Helping.ViewModels.RegisterViewModel'.
My Register view expects RegisterViewModel and My LocalLogin expects LoginViewModel
#using Helping.ViewModels
#model LoginViewModel
#model HelpingHands.ViewModels.RegisterViewModel
How to provide both the models with one view need help ?
You need to combine both your LoginViewModel and RegisterViewModel into one model (ViewModel).
Like..
public class LoginRegisterModel
{
public LoginViewModel LoginModel {get;set;}
public RegisterViewModel RegisterModel {get;set;}
}
Then you can pass this viewModel to your view..
#model Helping.ViewModels.LoginRegisterModel
Which says this view will be using the class LoginRegisterModel as the model..
And inside the view for your two partial views you can use..
Html.Partial("LocalLogin", Model.LoginModel)
Html.Partial("Register", Model.RegisterModel)
The error your getting is because you are not passing any model to your Register view and by default the model passed to your main view is carried forward to the call of partial Register view.
** I m on mobile, forgive me for bad formatting. And if anyone can format the code section its greatly appreciated**

How to call a HttpPost ActionResult from a view in another controller in mvc

I want to show my login form in Home Index view,
and when user clicks the login button i want to authenticate him with an action result called (Login) in my Account controller..
this is my code in Home Index view :
#model Charity.Models.ViewModels.LoginModel
#using (Html.BeginForm("Login", "Account", FormMethod.Post))
{
<div>
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
</div>
<div>
#Html.LabelFor(m => m.Password)
#Html.PasswordFor(m => m.Password)
</div>
<input type="submit" value="Login" />
}
And this is my Login method:
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
return RedirectToAction("Index", "Admin");
}
else
{
ModelState.AddModelError("", "User or password is incorrect");
}
}
return View();
}
The problem is : when the credentials are correct , the website redirects to /Admin/Index and this is ok ..
but when the credentials are wrong , website redirects to /Account/Login . and my login form is not in this address..
how can i force login actionresult to redirect to /Home/Index when the credentils are wrong ??
Other than an extra closing </div> tag that doesn't appear to belong to any opening tag, your view seems valid.
What is most likely happening is that you decorated your AccountController with the AuthorizeAttribute:
[Authorize]
public class AccountController : Controller
{
/* your code */
}
If you do that, you have to decorate any actions that don't need authorization with the AllowAnonymousAttribute. That includes the versions that are supposed to handle the POST event:
[HttpPost]
[AllowAnonymous]
public ActionResult Login(Models.ViewModels.LoginModel model, string returnUrl = "")
{
/* your code */
}
If you don't decorate the POST version with the AllowAnonymousAttribute, the AuthorizeAttribute is going to trigger a HTTP 401 result, and you get redirected to the login action.
Thats my implemetation of the login method:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindAsync(model.UserName, model.Password);
if (user != null) // user.IsConfirmed
{
await SignInAsync(user, model.RememberMe);
return RedirectToLocal(returnUrl);
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
// If this point is reached , an error has occurred; Show form again .
return View(model);
change your return view() in login to
return View("~/Views/Home/Index.cshtml")
the view will be home/index.cshtml ,but location address not change
and if in you home controller index action ,set data for view,it will run also in login action
if you want location change,use redirect and pass some param

Model after post not change why

I have Page for Both Insert User and this work fine but after I insert new info i send new model but this not work.the info that i insert before are still in textbox without any error. why???
return View(new User());
#using (#Html.BeginForm("RegisterUser", "UserManagement", FormMethod.Post))
{
#Html.AntiForgeryToken()
<table class="Registertbl">
<tr>
<td>نام*</td>
<td> #Html.TextBoxFor(m => m.FName, new { maxlength = 20})<br />
</td>
<td>سمت*</td>
<td>#Html.TextBoxFor(m => m.Post, new { maxlength = 200})</td>
</tr>
</table>
<br />
<input type="submit" value="Insert" class="insertBtn" />
#Html.ActionLink("back", "ViewUserList", "UserManagement")
}
//Controller
[HttpGet]
public ActionResult RegisterUser()
{
return View(new User());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RegisterUser(Common.UsersManagement.Entities.User model)
{
SetUserManagement();
var Result = userManagement.RegisterUser(model);
if (Result.Mode == Common.Extensions.ActionResultMode.Successfully)
{
return View(new User());
}
// if not Successfull
return View(model);
}
maf748 is correct, you should Post-Redirect-Get. You can communicate to the GET action method using TempData that a message should be displayed, e.g.
TempData.Message = "User registered.";
return RedirectToAction( "RegisterUser" );
Then in your RegisterUser view you can check if TempData.Message has a value.
However, if after all that you still want do do it your way you could try ModelState.Clear() before returning the new View. The problem this will cause is that if the user refreshes the page in their browser it will send them back to your Post method, prompting them in the browser with that awful "do you want to resubmit your data" message and potentially creating duplicate registrations in your database.
Try redirecting back to the GET RegisterUser.
The reason is: when you submit a form to MVC, all the values in the ModelState (basically the Request values) take precedence over any model you pass to the view. The redirect will give you an empty ViewDataDictionary, so all values will be pulled from the Model you're passing (the new User())
if (Result.Mode == Common.Extensions.ActionResultMode.Successfully)
{
return RedirectToAction("RegisterUser");
}

MVC Parent Child actions page rendering?

I am learning to embed a child action inside a parent action, and render the whole page properly when a form is submitted from the child action.
ParentAction.cshtml--------------------------------------
#model Web1.Models.ParentActionModel
#{ViewBag.Title = "ParentAction";}
<h2>Parent Action</h2>
#Html.ValidationSummary(true, "Please correct parent errors and try again.")
#using (Html.BeginForm()) {
//parent forminput stuff
<input type="submit" value="Parent Button" />
}
#Html.Action("ChildAction","Home") <!-- ChildAction is included here -->
ChildAction.cshtml (included in parent.cshtml) ------------
#model Web1.Models.ChildActionModel
#{ViewBag.Title = "ChildAction";}
<h2>Child Action</h2>
#Html.ValidationSummary(true, "Please correct child errors and try again.")
#using (Html.BeginForm("ChildAction", "Home")) {
//child form input stuff
<input type="submit" value="Child Button" />
}
HomeController.cs-----------------------
public ActionResult ParentAction() {
return View();
}
[HttpPost]
public ActionResult ParentAction(ParentActionModel pmodel) {
//do model update stuff
return View(pmodel);
}
[ChildActionOnly]
public ActionResult ChildAction() {
return PartialView();
}
[HttpPost]
public ActionResult ChildAction(ChildActionModel cmodel) {
//do model update stuff
return PartialView(cmodel); // <---This is wrong, What's the correct way to do it?
}
Now, when I click the "Child Button", I will only get the view of the child action (durrr!), how do I fix it to generate full page parent+children view? It seems like a logic easy enough, but I am stuck on it for hours.
So, if I removed the [ChildActionOnly] in HttpPost Details method,
when I click submit, only the Details.cshtml partialView is returned,
not with the Master.cshtml, which is not what I want, neither.
That's because you should not return a PartialView in this case, but a full View:
[HttpPost]
public virtual ActionResult Details(DetailsModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
return RedirectToAction("Success");
}
You might also need to only conditionally render the Details action to avoid infinite loops:
#if (!IsPost)
{
#Html.Action("Details", "Home")
}
Obviously if you want to preserve the original context you were in when you invoked this POST action, you will have to use AJAX and then invoke this POST action with AJAX and replace only the corresponding part of the DOM.

How do I create a httppost getting same parameters from httpget?

I have a controller to show up a model (User) and want to create a screen just with a button to activate. I don't want fields in the form. I already have the id in the url. How can I accomplish this?
Use [ActionName] attribute - this way you can have the URLs seemingly point to the same location but perform different actions depending on the HTTP method:
[ActionName("Index"), HttpGet]
public ActionResult IndexGet(int id) { ... }
[ActionName("Index"), HttpPost]
public ActionResult IndexPost(int id) { ... }
Alternatively you can check the HTTP method in code:
public ActionResult Index(int id)
{
if (string.Equals(this.HttpContext.Request.HttpMethod, "POST", StringComparison.OrdinalIgnoreCase))
{ ... }
}
A bit late to the party on this but I found an easier solution to what I think is a fairly common use-case where you prompt on GET ("are you sure you want to blah blah blah?") and then act on POST using the same argument(s).
The solution: use optional parameters. No need for any hidden fields and such.
Note: I only tested this in MVC3.
public ActionResult ActivateUser(int id)
{
return View();
}
[HttpPost]
public ActionResult ActivateUser(int id, string unusedValue = "")
{
if (FunctionToActivateUserWorked(id))
{
RedirectToAction("NextAction");
}
return View();
}
On a final note, you can't use string.Empty in place of "" because it must be a compile-time constant. And it's a great place to put funny comments for someone else to find :)
You could use a hidden field inside the form:
<% using (Html.BeginForm()) { %>
<%= Html.HiddenFor(x => x.Id) %>
<input type="submit" value="OK" />
<% } %>
or pass it in the action of the form:
<% using (Html.BeginForm("index", "home",
new { id = RouteData.Values["id"] }, FormMethod.Post)) { %>
<input type="submit" value="OK" />
<% } %>
My approach is not to add an unused parameter as that seems like it would cause confusion, and is in general bad practice. Instead, what I do is append "Post" to my action name:
public ActionResult UpdateUser(int id)
{
return View();
}
[HttpPost]
public ActionResult UpdateUserPost(int id)
{
// Do work here
RedirectToAction("ViewCustomer", new { customerID : id });
}
The easiest way for such simple situation is to give a name to submit button and check in action if it has value or not.
If it has the value, then it Post action, if not, then it Get action :
<% using (Html.BeginForm("index", "home",
new { id = RouteData.Values["id"] }, FormMethod.Post)) { %>
<input type="submit" value="OK" name="btnActivate" />
<% } %>
For Cs you can combine get and post controller methods in one:
public ActionResult Index(int? id, string btnActivate)
{
if (!string.IsNullOrEmpty(btnActivate))
{
Activate(id.Value);
return RedirectToAction("NextAction");
}
return View();
}

Resources