Hi guys,
I have written
the code below for resetting users passwords (am using
the aspnet membership api) in an C# MVC application, and tested successfully on a sample tutorial application (MVC Music Store). Skip to
the end if you wish to read problem description first.
InactiveUsers View (Partial View)
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.Web.Security.MembershipUserCollection>" %>
<table class="normal" style="width: 100%; background-color: White;">
<tr>
<th>User Name</th>
<th>Last Activity date</th>
<th>Locked Out</th>
</tr>
<%foreach (MembershipUser user in Model){ %>
<tr>
<td><%: Html.RouteLink(user.UserName, "AdminPassword", new { username = user.UserName }) %></td>
<td><%: user.LastActivityDate %></td>
<td><%: user.IsLockedOut %></td>
</tr>
<% }%>
</table>
InactiveUsers Controller
public ActionResult InactiveUsers()
{
var users = Membership.GetAllUsers();
return View(users);
}
changeUserPassword GET and POST Controllers
public ActionResult changeUserPassword(string username)
{
ViewData["username"] = username;
return View();
}
[HttpPost]
public ActionResult changeUserPassword(ChangePasswordModel model, FormCollection values)
{
string username = values["username"];
string password = values["password"];
string confirmPassword = values["confirmPassword"];
MembershipUser mu = Membership.GetUser(username);
if (password == confirmPassword)
{
if (mu.ChangePassword(mu.ResetPassword(), password))
{
return RedirectToAction("Index", "ControlPanel");
}
else
{
ModelState.AddModelError("", "
The current password does not meet requirements");
}
}
return View();
}
I also modified
the Global.asax.cs file to cater for my route in
the InactiveUsers partial:
// Added in 10/01/11
RouteTable.Routes.MapRoute(
"AdminPassword", // routename
"ControlPanel/changeUserPassword/{username}",
new { controller = "ControlPanel", action = "changeUserPassword", username = UrlParameter.Optional }
);
// END
Now, when I tested on
the MVC Music Store, all of my usernames were just words, e.g. Administrator, User, etc. However now I am applying this code to a situation in my workplace and it's not working out quite as planned.
The usernames used in my workplace are actually email addresses and I think this is what is causing
the problem.
When I click on
the RouteLink in
the partial InactiveUsers view, it should bring me to
the reset password page with a url that looks like this:
http://localhost:83/ControlPanel/changeUserPassword/
[email protected], HOWEVER,
what happens when I click on
the RouteLink is an error is thrown to say that
the view changeUserPassword cannot be found, and
the URL looks like this:
http://localhost:83/ControlPanel/changeUserPassword/example1%40gmail.com - See how
the '@' symbol gets messed up?
I've also debugged through
the code, and in my GET changeUserPassword,
the username is populating correctly:
[email protected], so I'm thinking it's just
the URL that's messing it up?
If I type in
the URL manually,
the changeUserPassword view displays, however
the password
reset function does not work. An 'Object reference not set to an instance of an object' exception is thrown at
the if (mu.ChangePassword(mu.ResetPassword(), password)) line.
I think if I could solve
the first issue (URL '@' symbol problem) it might help me along with my second issue.
Any help would be appreciated :)
Stack Trace - as requested
Source Error:
An unhandled exception was generated during
the execution of
the current web request. Information regarding
the origin and location of
the exception can be identified using
the exception stack trace below.
Stack Trace:
[InvalidOperationException:
The view 'changeUserPassword' or its master was not found.
The following locations were searched:
~/Views/ControlPanel/changeUserPassword.aspx
~/Views/ControlPanel/changeUserPassword.ascx
~/Views/Shared/changeUserPassword.aspx
~/Views/Shared/changeUserPassword.ascx]
System.Web.Mvc.ViewResult.FindView(ControllerContext context) +495
System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) +208
System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +39
System.Web.Mvc.<>c__DisplayClass14.<InvokeActionResultWithFilters>b__11() +60
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +391
System.Web.Mvc.<>c__DisplayClass16.<InvokeActionResultWithFilters>b__13() +61
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +285
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +830
System.Web.Mvc.Controller.ExecuteCore() +136
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +111
System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +39
System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__4() +65
System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +44
System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +42
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +141
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +54
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +52
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +38
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8841105
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184