Issue with multiple views on single view - asp.net-mvc

I have create one simple page in MVC, which is given in startup project of MVC by .net framework with slight modification in that.
I have created two models
Login
Register
Create two controllers.
LoginController
RegisterController.
Then i have use both of them to display in my home page (like facebook just an example)
Model code:
Login Model:
public class Login
{
private string email;
[Required]
public string Email
{
get { return email; }
set { email = value; }
}
private string password;
[Required]
public string Password
{
get { return password; }
set { password = value; }
}
}
Register Model
public class Register
{
private string email;
[Required]
public string Email
{
get { return email; }
set { email = value; }
}
private string password;
[Required]
public string Password
{
get { return password; }
set { password = value; }
}
private string name;
[Required]
public string Name
{
get { return name; }
set { name = value; }
}
}
View of Login and Register both is created using "Create" Option.
Both contains
<input type="submit" value="Create" />
Now, both views are on my other page, home page.
#Html.Action("Index", "Login")
#Html.Action("Index", "Register")
Both display okay, but when i click on any of the "create" button of any of the view, it also gets fire the event in controller for the other one.
My controller code....Logincontroller.
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(Login lgobj)
{
System.Threading.Thread.Sleep(2000);
string email = lgobj.Email;
string password = lgobj.Password;
return View();
}
RegisterController:
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(Register model)
{
return View();
}
Can anyone please specify the reason, or what is missing in my code?
If not clear, please let me know, i will be describe more.

Try changing your Home View to this:
#using (Html.BeginForm())
{
#Html.Action("Index", "Login")
}
#using (Html.BeginForm())
{
#Html.Action("Index", "Register")
}
What I think is happening is that your submit is calling a POST to the wrong controller, as there is no distinct difference of forms.

Ok so you have a page (a View) that displays two ActionLinks. Once clicked, these two ActionLinks brings you to the LoginController or the RegisterController (depending on the link you’ve clicked). In both cases, you end up inside the Index() ActionResult of the appropriate Controller…so far so good!
Now…once inside the Index() you simply call return View() but I don’t see any code showing that these Views are strongly typed! Try the following:
LoginController:
public ActionResult Index()
{
var model = new Login();
return View(model);
}
RegisterController:
public ActionResult Index()
{
var model = new Register();
return View(model);
}
Assuming you’ve created two strongly typed views (Index.cshtml inside the Login folder and Index.cshtml inside the Register folder) make sure each view has an appropriate form and a submit button.

Little change to what mentioned by #Shark,
We need to mention the action and controller to which indivisual form will post data, If we will not specify both the form will post to the page url.
#using (Html.BeginForm("Index","Login"))
{
#Html.Action("Index", "Login")
}
#using (Html.BeginForm("Index","Register"))
{
#Html.Action("Index", "Register")
}

In this scenario, ( as commented in my first answer)
We need to use a Dynamic view page. (More Information)
Follow following steps:
Create DynamicViewPage type:
public class DynamicViewPage : ViewPage
{
public new dynamic Model { get; private set; }
protected override void SetViewData(ViewDataDictionary viewData)
{
base.SetViewData(viewData);
Model = ViewData.Model;
}
}
Your Controller will look like
public ActionResult Account(string returnUrl)
{
LoginModel loginmodel = null;//Initialize Model;
RegistrationModel registrationModel = null ;//Initialize Model;
.
.
.
.
.
return View("Account", new
{
Login = loginmodel,
Register = registrationModel
});
your View should Inherit from
Inherits="DynamicViewPage"
Now #Model.Login will give you Loginmodel
#Model.Register will give you RegisterModel
It should work as you expected.........

Related

How To call An Action In Umbraco Controller?

I created an Umbraco DocumentType with the alias Personal and created a controller that inherits
Umbraco.Web.Mvc.RenderMvcController
I added two Actions, one is the default action and the other is called Test.
How can I fire the Test Action from the Personal controller?
public class PersonalController : Umbraco.Web.Mvc.RenderMvcController
{
// GET: Personal
public override ActionResult Index(RenderModel model)
{
return base.Index(model);
}
public String Test(RenderModel model)
{
return "fff";
}
}
When I put the url like this: localHost/personal/test it shows:
No umbraco document matches the url '/test'.
Which is right, so how can I call it?
I would do it like this
[HttpPost]
public ActionResult SubmitSearchForm(SearchViewModel model)
{
if (ModelState.IsValid)
{
if (!string.IsNullOrEmpty(model.SearchTerm))
{
model.SearchTerm = model.SearchTerm;
model.SearchGroups = GetSearchGroups(model);
model.SearchResults = _searchHelper.GetSearchResults(model, Request.Form.AllKeys);
}
return RenderSearchResults(model.SearchResults);
}
return null;
}
public ActionResult RenderSearchResults(SearchResultsModel model)
{
return PartialView(PartialViewPath("_SearchResults"), model);
}
See this blog post for the full context behind where this code snippet came from.
http://www.codeshare.co.uk/blog/how-to-search-by-document-type-and-property-in-umbraco/

ASP MVC Button Click

I would like to click on button and use Next method in Controller, but i dont want go to another view! I want stay here in VIEW and my property should be change. This idea doesnt work :(( How can i do it??
Its my controller
public class VisitsController : Controller
{
Terminarz terminarz = new Terminarz();
Daty data = new Daty();
public VisitsController()
{
terminarz.aktualnaData = DateTime.Now.Date;
terminarz.pierwszyDzienTyg = data.pierwszyDzienTygodnia(terminarz.aktualnaData);
terminarz.ostatniDzienTyg = data.ostatniDzienTygodnia(terminarz.aktualnaData);
}
[ActionName("index")]
public ActionResult Index()
{
ViewBag.data = terminarz.aktualnaData;
ViewBag.pierwszyDzien = terminarz.pierwszyDzienTyg.ToString("dd/MM/yyyy ");
ViewBag.ostatniDzien = terminarz.ostatniDzienTyg.ToString("dd/MM/yyyy ");
ViewBag.wtf = terminarz.pierwszyDzienTyg.AddDays(7).ToString("dd/MM/yyyy ");
return View();
}
[NonAction]
public ActionResult Next()
{
terminarz.pierwszyDzienTyg = terminarz.pierwszyDzienTyg.AddDays(7);
terminarz.ostatniDzienTyg = terminarz.ostatniDzienTyg.AddDays(-7);
return View("index");
}
}
my model
public partial class Terminarz
{
public DateTime aktualnaData { get; set; }
public DateTime pierwszyDzienTyg { get; set; }
public DateTime ostatniDzienTyg { get; set; }
public string nazwa { get; set; }
}
my view
#ViewBag.pierwszyDzien<br />
#ViewBag.ostatniDzien<br />
#ViewBag.wtf
#using (Html.BeginForm(FormMethod.Post))
{
#Html.ActionLink("dalej","Next", "Visits")
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
By default, all public methods in a controller can be called from an HTTP request. NonAction prevents the public method from being called from your form post. Remove the NonAction attribute from the Next method, and it should execute as expected.
You may also have to update your return to match a relative path something like this:
return View("~/Views/Index.cshtml");
Your form is also not being submitted. You are using a link inside of the form. Try this:
#using (Html.BeginForm("Next", "VisitsController", FormMethod.Post))
{
<button type="submit">Next</button>
}

Reusing Controller Action based on ViewModel

I will have a registration form on my website which will firstly show the boardrules / legal. Once accepted it will then show the main registration form. Using a ViewModel as below:
public class MyViewModel
{
public int Readrules { get; set; }
public int Coppa { get; set; }
}
public ActionResult Register(MyViewModel model)
{
... at this stage model.Readrules and model.Coppa will contain the values passed
as query string parameters tat you could use here
}
The idea is if I go to /register it will show the rules and then /register?readrules=1 it will then show the registration form. This is how it was done in PHP but now I am migrating to ASP.NET..
What is the best way of doing this? Can I redirect to the same action and just parse the value of model.ReadRules or must I use more than one action? I would prefer to keep this in one action and just check if model.ReadRules == 1 and either display the boardrules or registration form.
Thanks
Instead of re-using the Register action, you could have different controller actions for displaying the rules, registering and processing the registration, like so:
Controller Actions:
public ActionResult BoardRules()
{
return View();
}
public ActionResult Register(MyViewModel model)
{
if (model.ReadRules != 1)
return RedirectToAction("BoardRules");
return View();
}
public ActionResult Registration(MyViewModel model)
{
if (model.ReadRules != 1)
return RedirectToAction("BoardRules");
//Process the registration
return View();
}
Views:
BoardRules.cshtml:
#* HTML Displaying Rules *#
Accept Rules
Register.cshtml:
#using (Html.BeginForm("Registration", "[Controller Name]", new { ReadRules = 1 }))
{
#* Form Fields *#
<input type="submit" value="Process Registration" />
}
Registration.cshtml
<h2>Congratz on Registering!</h2>
public ActionResult Register()
{
return View("boardrules"); //Default
}
public ActionResult Register(MyViewModel model)
{
if (model.ReadRules == 1)
{
model.ReadRules++; //Next time it won't be 1 but step 2
return View("registration",model);
}
else
{
//Do IF or Case for other step
}
return View("boardrules"); //Default
}

asp.net mvc Razor TextBox

How do you check the value that has been entered in an ASP.NET MVC #Html.TextBox and compare it with a value in the database? I want to make an easy login, and want to see if the value that has been entered in the textbox is the same as that in the database
<tr><td>Username</td><td>:</td><td>#Html.TextBox("username", new { #value = ViewBag.username })</td></tr>
I tried things like creating a viewbag and then taking it to the controller, but it didnt seem to work.
Create a viewmodel(a simple class) for this specific UI
public class LoginViewModel
{
[Required]
public string UserName { set;get;}
[Required]
[DataType(DataType.Password)]
public string Password { set;get;}
}
Now in your GET action, create an object of this class and send to your view.
public ActionResult Login()
{
var vm=new LoginViewMode();
return View(vm);
}
Now in our login view(Login.cshtml)which is strongly typed to our LoginViewModel, we will use the TextBoxFor html helper method to render the textboxes for our UserName and Password fields.
#model LoginViewModel
#using(Html.Beginform())
{
UserName
#Html.TextBoxFor(x=>x.UserName);
Password
#Html.TextBoxFor(x=>x.Password)
<input type="submit" />
}
This will render a form which has action attribute value set to /YourCotnroller/Login. now we need to have an HttpPost action method to handle the form posting
[HttpPost]
public ActionResult Login(LoginViewModel model)
{
if(ModelState.IsValid)
{
string uName=model.UserName;
string pass=model.Password.
//Now you can use the above variables to check it against your dbrecords.
// If the username & password matches, you can redirect the user to
// another page using RedirecToAction method
// return RedirecToAction("UserDashboard")
}
return View(model);
}
public ActionResult UserDashboard()
{
//make sure you check whether user is logged in or not
// to deny direct access without login
return View();
}
Try like this:
Define model property in your Model class:
public class Login{
[Required]
[Remote("IsUserNameAvaliable", "Home")]
public string username{get;set;}
[Required]
public string password{get;set;}
}
The Remote attribute that is placed will find the Method/Action with IsUserNameAvaliable in the controller name Home.
The remote attribute servers for this purpose in MVC.
public JsonResult IsUserNameAvaliable(string username)
{
//Check if there are any matching records for the username name provided
if (_dbEntity.Users.Any(c => c.UserName == username))
{
//If there are any matching records found
return Json(true, JsonRequestBehavior.AllowGet);
}
else
{
string userID = String.Format(CultureInfo.InvariantCulture,
"{0} is not available.", username);
return Json(userID, JsonRequestBehavior.AllowGet);
}
}
Now in your view strongly type the textbox
#model Application.Models.Login
#Html.TextBoxFor(m=>m.username)
#Html.ValidationMessageFor(m=>m.username)
Donot forget to include jquery validation scripts.
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")

MVC Authorization - multiple login pages

I have a the following methods in an MVC Controller which redirect to the login page when a user is not logged in.
[Authorize]
public ActionResult Search() {
return View();
}
[Authorize]
public ActionResult Edit() {
return View();
}
Is there a quick/easy/standard way to redirect the second action to a different login page other than the page defined in the web.config file?
Or do I have to do something like
public ActionResult Edit() {
if (IsUserLoggedIn)
return View();
else
return ReturnRedirect("/Login2");
}
I think it is possible by creating a custom authorization filter:
public class CustomAuthorization : AuthorizeAttribute
{
public string LoginPage { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.HttpContext.Response.Redirect(LoginPage);
}
base.OnAuthorization(filterContext);
}
}
In your action:
[CustomAuthorization(LoginPage="~/Home/Login1")]
public ActionResult Search()
{
return View();
}
[CustomAuthorization(LoginPage="~/Home/Login2")]
public ActionResult Edit()
{
return View();
}
Web.config based forms authentication does not have such a functionality built-in (this applies to both WinForms and MVC). You have to handle it yourself (either through an HttpModule or ActionFilter, the method you mentioned or any other method)
I implemented the accepted answer by user434917 and even though I was being redirected correctly, I was also receiving the error "Server cannot set status after HTTP headers have been sent." in the server log. After searching, I found this post (answer by Mattias Jakobsson) that solved the problem. I combined the answers to get this solution.
Create a custom authorization filter:
using System.Web.Mvc;
using System.Web.Routing;
namespace SomeNamespace.CustomFilters
{
public class CustomAuthorization : AuthorizeAttribute
{
public string ActionValue { get; set; }
public string AreaValue { get; set; }
public string ControllerValue { get; set; }
public override void OnAuthorization(AuthorizationContext context)
{
base.OnAuthorization(context);
if (context.HttpContext.User.Identity.IsAuthenticated == false)
{
var routeValues = new RouteValueDictionary();
routeValues["area"] = AreaValue;
routeValues["controller"] = ControllerValue;
routeValues["action"] = ActionValue;
context.Result = new System.Web.Mvc.RedirectToRouteResult(routeValues);
}
}
}
}
Then on your controller, use the customer attribute.
[CustomAuthorization(ActionValue = "actionName", AreaValue = "areaName", ControllerValue = "controllerName")]
public class SomeControllerController : Controller
{
//DO WHATEVER
}
Yeah pretty easy! Lets say you have 2 different type of users. First typenormal users, the other one is administrators. You would like to make them login from different pages. You also want them to be able to access different ActionResults.
First you have add two different schemes. In these schemes you will define your different login pages and other options you want.
in startup.cs
services.AddAuthentication("UserSceheme").AddCookie("UserScheme", config =>
{
config.LoginPath = "/UsersLogin/Login/";
config.Cookie.Name = "UsersCookie";
});
services.AddAuthentication("AdminScheme").AddCookie("AdminScheme", config =>
{
config.LoginPath = "/AdminLogin/Login/";
config.Cookie.Name = "AdminsCookie";
});
Then you will define two policies. Here I called them UserAccess and AdminAccess Each policy will use the sceheme that I point.
In startup.cs just after schemes add those below.
services.AddAuthorization(options =>
{
options.AddPolicy("UserAccess", policy =>
{
policy.AuthenticationSchemes.Add("UserScheme");
policy.RequireAuthenticatedUser();
});
options.AddPolicy("AdminAccess", policy =>
{
policy.AuthenticationSchemes.Add("AdminScheme");
policy.RequireAuthenticatedUser();
});
});
The last thing we have to do is again telling the scheme we want to use when login.
var userPrincipal = new ClaimsPrincipal(new[] {
new ClaimsIdentity(loginClaims, "ServiceCenter")
});
HttpContext.SignInAsync("AdminScheme",userPrincipal);
Thats it! Now we can use these just like this; This will redirect you to the users login page.
[Authorize(Policy = "UserAccess")]
public IActionResult Index()
{
return View();
}
If you have some places that you want both user types to be able to access all you have to do;
[Authorize(Policy = "AdminAccess")]
[Authorize(Policy = "UserAccess")]
public IActionResult Index()
{
return View();
}
And finally for log-out you also have to point the scheme
public async Task<IActionResult> Logout()
{
await HttpContext.SignOutAsync("AdminScheme");
return View();
}
Thats it!

Resources