ActionResult for Layout - c#

I am trying to make a login form which is located in Layout itself therefor not in any View. Problem is I dont know how to write an ActionResult for the Layout.
If I put my code in lets say ActionResult Index() then it will only work on Index page. So is there something like ActionResult for Layout itself ?

I would do it like this:
Create a login action to return the specific partial.
public ActionResult Login()
{
if (User.Identity.IsAuthenticated)
{
return PartialView("_loggedInPartial");
}
else
{
return PartialView("_notLoggedInPartial");
}
}
Call it within your layout.cshtml like this:
#Url.Action("Login", "Account");
Update
You could also retrieve the user and return it to the _notLoggedInPartial view to display some user credentials or a welcome message like this:
...
else
{
// User retrieval code from db
return PartialView("_notLoggedInPartial", model);
}
...

People generally won't prefer doing this, but still below is the simplest way to achieve
Create a form(html/ajax) in the layout itself with login fields.
Post it from there to your "login post" action.
using (Html.BeginForm("Login", "Account")){
#Html.TextBox("Username")
#Html.TextBox("Password")
<input type="submit" value="Login">
}
AccoutController must contain an action with below structure.
[HttpPost]
Public ActionResult Login(string Username, string Password)
{
//handle appliaction logic
}

Related

How to send a text message or a link from controller to view?

I have got a submit button for a form, this controller actionresult method gets called when the button is pressed. Depending on the return of the _shortUrlProcessor.CreateShortURL method. I want to either display a message in red or a create a link under the mentioned submit button. What is the proper way of handling this in MVC? (see comments in code for more clarification as well)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ShortenURL(ShortURLModel model)
{
if(ModelState.IsValid)
{
if(_shortUrlProcessor.CreateShortURL(model.originalURL, model.shortURL))
{
ViewBag.ShortenURLSuccess(model.shortURL); //< ---- send as a localhost:port/model.shortURL link
}
else
{
ViewBag.ShortenURLSuccess("Could not create link"); //<----send as a text label (which would be shown in something like a <div/>)
}
}
return View();
}
Putting this in the view is the way to go, and here is an example using the viewbag approach:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ShortenURL(ShortURLModel model)
{
if(ModelState.IsValid)
{
if(_shortUrlProcessor.CreateShortURL(model.originalURL, model.shortURL))
{
ViewBag.ShortenURLSuccess=true;
ViewBag.ShortenURL=model.shortURL;
}
else
{
ViewBag.ShortenURLSuccess=false;
}
}
return View();
}
And then in the view:
#if (ViewBag.ShortenURLSuccess)
{
Go here
}
else
{
<div class="error">Could not create link</div>
}
If you need more information for the url or the message, you can put those in viewbag variables as well.
it is worth noting that a more popular way to do this is with model binding, but this approach works fine for what it is. You can use the submitted model and move away from the viewbag to be a bit more efficient.

How do I create a GET form with validation in MVC

I'm having a real problem trying to articulate this seemly simple problem.
I have a single view that contains a FORM with a few search fields at the top of the view and the results of that search get shown on the same view after submitting the form.
I have a single HTTPGET controller method that takes the form fields as parameters and IF it was submitted by a user it will pass the model back to the view with the results to be shown and pre-populate the search form with what they filled out.
How can I tell if the page was loaded with default parameters vs. someone actually submitted the form.
What's the best way to accomplish this?
If I am understanding your question correctly then I think you need to consider the HttpGet attribute:
https://msdn.microsoft.com/en-us/library/system.web.mvc.httpgetattribute(v=vs.118).aspx
and the HttpPost attribute:
https://msdn.microsoft.com/en-us/library/system.web.mvc.httppostattribute(v=vs.118).aspx
Lets say you have a create method. The Http method would look like this:
[HttpGet]
public ActionResult Create()
{
}
and the post method would look like this:
[HttpPost]
public ActionResult Create(Person p)
{
//Logic to insert p into database. Could call an application service/repository to do this
}
RedirectToAction solve the problem.
you can go back to the get method after submited data and populate the view with default values
[HttpGet]
public ActionResult Create()
{
// fill model to default data
return view(model);
}
[HttpPost]
public ActionResult Create(Person p)
{
//do your stuff save data
return RedirectToAction("Create");
}
or
[HttpPost]
public ActionResult Create(Person p)
{
if(...)
{
//do your stuff any logic
return RedirectToAction("Create");
}
//do your stuff
return view(...);
}

Call actionresult logoff in the index page

I have made a login page and a user can login. No I want the user to logoff.
I have this in my AccountController:
public ActionResult LogOff()
{
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Home");
}
But how can I call this actionresult in my index page?
There are a couple of different ways you can do this
From a view
#Html.ActionLink("Log Out", "LogOff", "Account")
or
Log Out
or
Log Out
I don't recommend the last one however because it doesn't take into consideration action and controller routing. I only included it here as a last resort option.
From another action
You could also call the action directly from code like you would any normal class method, should you need to do that. Like so:
class ActionController : Controller
{
// ...
public ActionResult AnotherAction()
{
// Do stuff here
return LogOff(); // You don't have to return the results if they're not needed
}
// ...
}
like this you can call this actionresult
Logout
Keep a breakpoint in your LogOff action in your Account controller and see what is happening..
its a best practice to make logoff method a Post method , so i suggest to use this form :
<form method='post'>
<button type='submit'>LogOff</button>
</form>
[HttpPost]
public ActionResult Logoff()
{
//Do LogOff Stuff.
}

model data disappears between controllers

So i have a model with two models in it so that i can render to different views on the same view, one login view and one register view.
This is my model:
public class SignUpLoginModel
{
public LoginModel loginmodel { get; set; }
public RegisterModel registermodel { get; set; }
}
And when i am trying to register a new user with this controller method:
public ActionResult Register(SignUpLoginModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.registermodel.UserName,
model.registermodel.Password,
new
{
FirstName = model.registermodel.Firstname,
LastName = model.registermodel.Lastname,
Country = model.registermodel.Country,
City = model.registermodel.City,
Birthdate = model.registermodel.Birthdate
});
WebSecurity.Login(model.registermodel.UserName, model.registermodel.Password);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
// If we got this far, something failed, redisplay form
return RedirectToAction("Register", "Home", model);
}
So the modelstate.isvalid failes as it should and it redirects to the home controller and the register method and send the model. Here everything works fine, the model contains the data. But when i redirect to another controller
public ActionResult Register(SignUpLoginModel model)
{
ViewBag.Message = "RegisterFail";
return View("Index", "Home", model);
}
my model ends up with null instead of the right data. What am i doing wrong?
I'm pretty sure it's because RedirectToAction (neither the overload you are using nor any of the other signatures) doesn't forward your model for you. It sends a 302 back to your browser which then issues a new GET request to a new url - therefore your model data is lost.
So you'd need to do something like this in the first controller
{
TempData["signupModel"]=model;
return RedirectToAction("Register", "Home", model);
}
and then this in the redirect controller:
public ActionResult Register(SignUpLoginModel model)
{
ViewBag.Message = "RegisterFail";
return View("Index", "Home", TempData["signupModel"]);
}
But what I don't understand is why you don't just directly return a view the first time around, why do you need to redirect - because from your code you seem to be just redirecting back to the same controller - or have I missed something?
Edit based on comments below
I honestly think you would be better off using Ajax for this because what you're trying to do here is maintain state across multiple controllers/views which is not really idiomatic for MVC.
If you submit the "register" popup form via Ajax, then you never actually leave the Index page, you just execute some code server-side and return some JSON to indicate if your registration was OK or not. When this response indicates an error you can just display an error message on the popup form or whatever, otherwise you can redirect to wherever on the client-side.
OR
When your Register controller decides that registration has failed, return the Home page index view e.g
ViewBag.Message = "RegisterFail";
return View("~/HomePage/HomeController/Index.cshtml", model); //or whatever the virtual path to the home page view is
However I don't like this approach as it sounds to me like you have your register form HTML being generated in-line by the the Home page view, which sounds like mixed concerns to me.

Call controller from another controller and return a view

I call an Action from a Login controller to authenticate users, once the user is authenticated I would like to call either the Cashier or the Supervisor action, depending on the user's role, and display the appropriate view.
I can break on AuthenticateUserByCard but RedirectToAction doesn't seem to be working.
I'm not sure if what I'm trying to do is deviating from the MVC architecture, if so please suggest the correct way to do this
Login controller:
public class LoginController : Controller
{
public ViewResult Index()
{
return View();
}
[HttpPost]
public ActionResult AuthenticateUserByCard(string token)
{
//Authenticate user and redirect to a specific view based on the user role
Role role = GetRoleByToken(token);
if(role.UserType == UserType.Supervisor)
return RedirectToAction("Supervisor", "Login", new { id = token });
else
return RedirectToAction("Cashier", "Login", new { id = token });
return null;
}
public ActionResult Supervisor(string id)
{
//Do some processing and display the Supervisor View
return View();
}
public ActionResult Cashier(string id)
{
//Do some processing and display the Cashier View
return View();
}
}
Java Script:
$.get("/Login/AuthenticateUserByCard",{token:token});
jQuery post and get ignore 301 browser redirects returned from the server. You would normally need to handle them yourself. This can get messy: How to manage a redirect request after a jQuery Ajax call
All you really need in this case is to return the choice of methods, but make them return explicit views (not implicit). The default would always be to return the view based on the IIS-called method i.e. "AuthenticateUserByCard" unless you specify the view.
e.g.
public class LoginController : Controller
{
public ViewResult Index()
{
return View();
}
[HttpPost]
public ActionResult AuthenticateUserByCard(string token)
{
//Authenticate user and redirect to a specific view based on the user role
Role role = GetRoleByToken(token);
if(role.UserType == UserType.Supervisor)
return Supervisor(token);
else
return Cashier(token);
return null;
}
public ActionResult Supervisor(string id)
{
//Do some processing and display the Supervisor View
return View("Supervisor");
}
public ActionResult Cashier(string id)
{
//Do some processing and display the Cashier View
return View("Cashier");
}
This will not change the URL though. If you need that too try the other answer I linked. You basically handle the redirect in jQuery and goto the new page.
Alternatively, to change the URL, put the desired URL into a hidden field of the returned views and extract that value to update the browser URL (just a thought) :)

Categories

Resources