ASP.NET: Access temp data in ViewBag - asp.net

I am beginner in ASP.NET and trying to get data in ViewBagby using temp data in controller. I got it in user.Username and user.Email but not getting in ViewBag.Name and ViewBag.Email respectively. My code is given below please guide me how can i get it in ViewBag?
QuestionsContoller.cs
public class temp {
public string username { get; set; }
public string email { get; set; }
}
public ActionResult Question() {
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Question(User user) {
temp temp_user = new temp();
temp_user.email = user.Email;
temp_user.username = user.Username;
return RedirectToAction("Answers" , temp_user);
}
public ActionResult Answers(temp temp_user) {
User user = new Models.User();
user.Username = temp_user.username;
user.Email = temp_user.email;
ViewBag.Name = user.Username;
ViewBag.Email = user.Email;
return View(user);
}

You cannot redirect with a payload. A redirect is an empty-bodied response with typically a 302 status code and a Location header indicating the URL that should be requested next. The client, upon receiving this type of response, will generally then go ahead and make a new request for that URL. Importantly, the client will not know or care to pass any additional data along with this request, so you cannot enforce that something like your temp object is included.
If you need to persist that data between requests, you can add it to TempData:
TempData["temp_user"] = temp_user;
And then fetch it in the action you redirect to via:
var temp_user = TempData["temp_user"] as temp;
Alternatively (and preferably), you'd simply redirect with the user id in tow, and then simply look up the user again. The use of sessions (which TempData is) should be avoided as much as possible.
return RedirectToAction("Answers", new { userId = user.Id });

Related

How can I do that unitofwork in actionfilter shouldnt save objects is changed in action

I use unitofwork pattern and its lifecycle is scope. I have lots of method as below in my controller.I bring object change property and save it then I return that object finally afteractionfilter runs and log and save it.My problem is that unitofwork what I called in filter.It saves also user object which is in action I musn't save that object.How can I solve this problem
public IActionResult ReadUserProfileImage(string id) {
IActionResult response = BadRequest();
var user = unitOfWork.User.FirstOrtDefault(u=>u.id==id);
user.Name="New name";
return Ok(user);
}
public override void OnActionExecuted(ActionExecutedContext filterContext) {
unitOfWork.Logs.Add(new CoreHelper.Core.Domain.Log() {
User = user,
ResultType = resultType,
Time = time,
Controller = controller,
Action = action,
Request = requestJson,
Response = responseJson,
Ip = ip.ToString(),
PcName = pcName,
Url = url,
ProcessTime = processTime,
LogCaption = logCaption,
LogDetail = logDetail,
IsBefore = isBefore
});
unitOfWork.Save();
}
If you dont want any changes that you might do on the Entity, you can use the .AsNoTracking() option.
public IActionResult ReadUserProfileImage(string id) {
IActionResult response = BadRequest();
var user = unitOfWork.User.AsNoTracking().FirstOrtDefault(u=>u.id==id);
user.Name="New name";
return Ok(user);
}

How to show a successful login popup message when the successful login can go to a redirect url?

I have the following login post action in the controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
[Auditing]
public async Task<ActionResult> Login(LoginModel details, string returnUrl)
{
if (ModelState.IsValid)
{
AppUser user = await UserManager.FindAsync(details.Name,
details.Password);
if (user == null)
{
ModelState.AddModelError("", "Invalid name or password.");
}
else
{
ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user,
DefaultAuthenticationTypes.ApplicationCookie);
ident.AddClaims(LocationClaimsProvider.GetClaims(ident));
ident.AddClaims(ClaimsRoles.CreateRolesFromClaims(ident));
AuthManager.SignOut();
AuthManager.SignIn(new AuthenticationProperties
{
IsPersistent = false
}, ident);
//Persist login into DB upon successful login
Loginrecord login = new Loginrecord();
login.Username = user.UserName;
login.SessionId = HttpContext.Session.SessionID;
Session["sessionid"] = HttpContext.Session.SessionID;
login.Date = DateTime.Now;
SQLLoginrecord sqlLogin = new SQLLoginrecord();
sqlLogin.PutOrPostLogin(login);
//End addition
return Redirect(returnUrl);
}
}
ViewBag.returnUrl = returnUrl;
return View(details);
}
Since a successful login from this action can go to any authorization-requiring page the user types the URL for in the address bar of the browser, how can I show a popup message that indicates a successful login? If I were to go with the ViewBag approach and add a Success variable, do I have to access that ViewBag from every View (including some that do not have a shared Layout) of the application that requires authentication?
Redirect method is going to issue a 302 response to the browser with the new url in the location header and browser will make a totally new Http request for that url. So ViewBag is not going to help you.
You might consider using TempData (which works for the next call) to share data from your Login action method to any other action method. You can write an action filter which checks the TempData item and set the approriate ViewBag entry so that you can do whatever you want in your other views.
public class LoginMsg : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var msg=filterContext.Controller.TempData["LoginMsg"] as string;
if (!String.IsNullOrEmpty(msg))
{
filterContext.Controller.ViewBag.LoginMsg= msg;
}
base.OnActionExecuting(filterContext);
}
}
Now in your Login class, before redirecting, set the TempData
public async Task<ActionResult> Login(LoginModel details, string returnUrl)
{
// do stuff
TempData["LoginMsg"]="Logged in successfully";
return Redirect(returnUrl);
}
Now decorate your other action methods (or you can do it on controller level) with our action filter.
[LoginMsg]
public ActionResult Dashboard()
{
return View();
}
In your view or the _Layout, you can access the ViewBag item and call the code to the trigger your popup control.
<script>
var msg = "#ViewBag.Msg";
if (msg.length) {
// alert(msg);
// Call the code to fire the popup now
// yourMagicPopupPlugin.Popup(msg);
}
</script>

MVC5 ApplicationUser custom properties

I am trying to get to grips with the new Membership system introduced in ASP.NET MVC 5 and I've come across a small issue which I am pretty sure you will be able to help me with.
I am going based off this tutorial and have introduced custom properties to ApplicationUser such as Name, Surname, DOB, etc.
However, instead of creating the user, I am trying to update the currently logged in one. I am looking at the controller method which is currently used to change password.
public async Task<ActionResult> Manage(ManageUserViewModel model)
{
string userId = User.Identity.GetUserId();
bool hasLocalLogin = await IdentityManager.Logins.HasLocalLoginAsync(userId);
ViewBag.HasLocalPassword = hasLocalLogin;
ViewBag.ReturnUrl = Url.Action("Manage");
if (hasLocalLogin)
{
if (ModelState.IsValid)
{
IdentityResult result = await IdentityManager.Passwords.ChangePasswordAsync(User.Identity.GetUserName(), model.OldPassword, model.NewPassword);
if (result.Success)
{
return RedirectToAction("Manage", new { Message = "Your password has been changed." });
}
else
{
AddErrors(result);
}
}
}
else
{
// User does not have a local password so remove any validation errors caused by a missing OldPassword field
ModelState state = ModelState["OldPassword"];
if (state != null)
{
state.Errors.Clear();
}
if (ModelState.IsValid)
{
// Create the local login info and link it to the user
IdentityResult result = await IdentityManager.Logins.AddLocalLoginAsync(userId, User.Identity.GetUserName(), model.NewPassword);
if (result.Success)
{
return RedirectToAction("Manage", new { Message = "Your password has been set." });
}
else
{
AddErrors(result);
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
How exactly would I go on about updating an ApplicationUser's Surname for example? Do I need to call the DbContext or?
I hope my question is clear.
Explore IdentityManager.Store.UserManagement and IdentityManager.Store.Users.
ApplicationUser cUser = (ApplicationUser) await IdentityManager.Store.Users.FindByNameAsync(HttpContext.User.Identity.Name, new System.Threading.CancellationToken());
cUser.Surname = "New Something";
IdentityResult result1 = await IdentityManager.Store.SaveChangesAsync();
Above code is an example only. Basically you need to explore the Store property of IdentityManage.
When we used the Users object of our database context we ran into other tracking errors. In our application, we would retrieve users as such
var user = UserManager.FindById(userId);
Edit the properties:
user.StorageName = "gooblygook";
//whatever other properties you would like to use
And then we would save it with the UserManager in the controller:
UserManager.Update(user);
This is currently a working solution for us.
Mark the Person object as virtual in your ApplicationUser definition. That worked for me.
public class ApplicationUser : IdentityUser
{
public virtual Person Person { get; set; }

How to handle a POST request to a URL that contains route parameters?

I'm working on an ASP.NET MVC4 web app, and I have a controller method for handling a GET request with an id in the URL, like so ...
[PortalAuthorization]
public ActionResult View(int id)
{
// get the individual ftp log
PortalFTPLog log = PortalFTPLogs.Get(id);
if (log == null)
{
TempData["Error"] = "The provided ftp log id does not exist.";
return RedirectToAction("Index");
}
// get the available matters to tie uploads to
ViewBag.matters = PortalMatters.Get();
return View(log);
}
In my view for this controller method, I have a form so that they can update it, that I want to POST back to the same URL. A URL like foo.com\items\1. Thats what the function above handles.
How do I make a function that handles a POST request for a function that requires a parameter, though? IN previous POST handlers I create a FormsCollection param, but when I add it to the param list for this function, the id param is null.
[HttpPost]
[PortalAuthorization]
public ActionResult View(FormCollection collection, int id)
{
PortalFTPLog log = PortalFTPLogs.Get(id);
if (log == null)
{
TempData["Error"] = "The provided ftp log id does not exist.";
return RedirectToAction("Index");
}
// update the matter id and save to database
log.Matter = Convert.ToInt32(collection.Get("matter"));
log.Save();
TempData["Notice"] = "The FTP log meta data has been updated.";
return RedirectToAction("View", new { id = id });
}
You need to provide RouteValues in Html.BeginForm on your View:
#using (Html.BeginForm(new {id = someIntIdValue}))
{
// Your form code
}

RedirectToAction usage in asp.net mvc

I want to post some questions about ASP.Net MVC. I am not familiar with web developing, But I was assigned to the web part of a project. We are doing the following: first, we create get & set properties for the person data:
public class Person
{
public int personID {get;set;}
public string personName {get;set;}
public string nric {get;set;}
}
and after login, we put the data in a class Person object and we use RedirectToAction like this:
return RedirectToAction("profile","person",new { personID = Person.personID});
It's working normally, but the parameter are shown in the URL. How can I hide them and also
can I hide the action name? Guide me the right way with some examples, please.
The parameter are shown in the URL because that is what the third parameter to RedirectToAction is - the route values.
The default route is {controller}/{action}/{id}
So this code:
return RedirectToAction("profile","person",new { personID = Person.personID});
Will produce the following URL/route:
/Person/Profile/123
If you want a cleaner route, like this (for example):
/people/123
Create a new route:
routes.MapRoute("PersonCleanRoute",
"people/{id}",
new {controller = "Person", action = "Profile"});
And your URL should be clean, like the above.
Alternatively, you may not like to use ID at all, you can use some other unique identifier - like a nickname.
So the URL could be like this:
people/rpm1984
To do that, just change your route:
routes.MapRoute("PersonCleanRoute",
"people/{nickname}",
new {controller = "Person", action = "Profile"});
And your action method:
public ActionResult Profile(string nickname)
{
}
And your RedirectToAction code:
return RedirectToAction("profile","person",new { nickname = Person.nickname});
Is that what your after?
If you don't want the parameter to be shown in the address bar you will need to persist it somewhere on the server between the redirects. A good place to achieve this is TempData. Here's an example:
public ActionResult Index()
{
TempData["nickname"] = Person.nickname;
return RedirectToAction("profile", "person");
}
And now on the Profile action you are redirecting to fetch it from TempData:
public ActionResult Profile()
{
var nickname = TempData["nickname"] as string;
if (nickname == null)
{
// nickname was not found in TempData.
// this usually means that the user directly
// navigated to /person/profile without passing
// through the other action which would store
// the nickname in TempData
throw new HttpException(404);
}
return View();
}
Under the covers TempData uses Session for storage but it will be automatically evicted after the redirect, so the value could be used only once which is what you need: store, redirect, fetch.
this may be solution of problem when TempData gone after refresh the page :-
when first time you get TempData in action method set it in a ViewData & write check as below:
public ActionResult Index()
{
TempData["nickname"] = Person.nickname;
return RedirectToAction("profile", "person");
}
now on the Profile action :
public ActionResult Profile()
{
var nickname = TempData["nickname"] as string;
if(nickname !=null)
ViewData["nickname"]=nickname;
if (nickname == null && ViewData["nickname"]==null)
{
throw new HttpException(404);
}
else
{
if(nickname == null)
nickname=ViewData["nickname"];
}
return View();
}
Temp data is capable of handling single subsequent request. Hence, value gone after refresh the page. To mitigate this issue, we can use Session variable also in this case. Try below:
public ActionResult Index(Person _person)
{
Session["personNickName"] = _person.nickName;
return RedirectToAction("profile", "person");
}
And in "profile" actionmethod:
public ActionResult profile()
{
Person nickName=(Person)Session["personNickName"];
if(nickName !=null)
{
//Do the logic with the nickName
}
}

Resources