How to link from View in Area to the root controller? - asp.net-mvc-4

I'm new to MVC, still learning ins and outs by converting .NET App to MVC.
I have trouble linking to another Action in my controller from the page inside of the "Area" section.
I created Areas and still have the default route set up.
The Area has the following structure:
Area
- Admin
- Controller
UserController.cs
-Model
-Views
User
Index.cshtml
Index.cshtml has a link that should call "Index" action in AccountController to open "Default" view:
<div class="pagenavigator">#Html.ActionLink("Main Menu", "Index", new { area = "", controller="Account" })</div>
The default structure of the application is the following:
- Controller
AccountController.cs
- Views
- Account
Default.cshtml
Login.cshtml
My default structure has also controller folder that has a controller with Login (default) action set in RouteConfig.cs:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Account", action = "Login", id = UrlParameter.Optional }
);
Here is Account Controller:
public class AccountController : Controller
{
public ActionResult Login(string returnUrl)
{
StringBuilder sb = new StringBuilder();
sb.Append("Web Security Administration Portal<br/><br/>");
ViewBag.ReturnUrl = returnUrl;
ViewBag.Message = sb.ToString();
return View();
}
public ActionResult Index()
{
return View("Default");
}
public ActionResult Login(LoginModel model)
{
if (ModelState.IsValid)
{
bool authenticated = Security.AuthenticateLANUser(model.UserName, model.Password);
if (!authenticated)
{
Session["authenticated"] = false;
System.Text.StringBuilder errorMsg = new System.Text.StringBuilder();
errorMsg.Append("Invalid Login/Password entered.");
errorMsg.Append("We were not able to authenticate you in in Active Directory based on the information entered, ");
errorMsg.Append("but we recorded your attempt for audit purposes.");
ModelState.AddModelError("", errorMsg.ToString());
return View(model);
}
else
{
return View("Default");
}
}
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
}
What should I do if I need to link to "Default" view defined under default application route, from Index.cshtml defined under Area, so when I click the link, my "AccountController" gets called with the correct "Index" action?
In short, I need to find out the way to link from "Area" section to a controller's action in default application section, so the another correct Action gets called, which is not specified in default route mapping
Right now, the link is broken.
When I view the link in the source, I see the following: <a href="/Account/Index">, but when I click on the link, I'm getting the error saying: The resource cannot be found with Requested URL: /login.aspx
Here is AdminAreaRegistration:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}

Related

mvc url.action returning null or url as get

I am using mvc Url.Action as this
<a href="#Url.Action("Index", "Product", new { area = "Product", search = UrlParameter.Optional, categoryId = category.IdCategory })">
I have my routing as:-
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Product_default",
"Product/{controller}/{action}/{id}/{categoryId}",
defaults: new { controller = "Product", action = "Index", search = UrlParameter.Optional, categoryId = #"\d+" },
namespaces: new[] { "IBuyFrontEnd.Areas.Product.Controllers" }
);
}
I cannot get the url to map to this route. I am getting it as
However if i change the action to
#Url.Action("Index", "Product")
I get this as Url
http://localhost/iteric/?action=Index&controller=Product
I cannot figure the why so of this behavior. Just started using .net mvc. Please help me with this.
Ok So figured out that to get Url.Action to generate the url requires the that action to be present in the controller, and also the parameters should be in place. So i just changed my controller action to
public ActionResult Index( int? categoryId,string search)
{
return View();
}

Where is value of "returnUrl" set in MVC 5? It always takes me to /Home/Index

It is null everywhere I find it during runtime.
I've got all the bells and whistles that halfway come with MVC 5 Template VS 2013.
I figured out all the extra Indentity and DataAnnotations stuff and it all works. (40 files and 5 tables later sheez).
But when signing in it all follows through but the registered user gets redirected to a "Home/Index" page, the default page that comes with template. I want them to get somewhere else, like "PickLocation".
Now nowhere in my code can I find "/Home/Index" referenced by searching the entire solution. In Web.config the authentication mode is set to "none".
Here is my Register link in _LoginPartial.cshtml:
<li>#Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink", style = "color:white;" })</li>
Somehow it heads for the HomeController.
Here is the Home Controller ActionResult that I can put a breakpoint to prove it was hit:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Notice = "This is coming from Home Controller";
return View();
}
In my AccountController the Login ActionResult returns "null" for the "returnURL" parameter. On Success (which is what happens) it goes to "return RedirectToLocal(returnUrl);" Where is this set? Nowhere can I find value of returnURL or where it is set and I don't want to continue to end up on the MS default Home/Index page that comes with the template. Log Out also goes to Home/Index page. I set IIS default page to "PickLocation.cshtml" but no luck
Here is the Login Action code here:
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
Edit:
I just remembered someone is going to ask if this is set in RouteConfig.cs. .. .no it's not.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//routes.MapRoute(
// name: "Default",
// url: "{controller}/{action}/{id}",
// defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
//);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Stores", action = "PickLocation", id = UrlParameter.Optional }
);
}
Here is the AccountController Login GET "method"
// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
But the question still stands: "where in the heck is the project/solution getting the "/home/index" that it sends me back to after registering or logging off? No where does the "/home/index" show up in a search.
Oh my gosh, if it was a snake it would have bit me.
I was searching for "Home/Index". I didn't think that it would be separate as in "Action, Controller". sheez.
This StackOverFlow question/answer showed me the light. I searched in my project for "private ActionResult RedirectToLocal" and I got this Action and down at the bottom was "return RedirectToAction("Index", "Home");" Pretty sure I can change it there. I hope my misery will help some other newby like me.
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Home");
}

ASP.NET Help Pages default home page?

I want to go to http://myserver and be able to get Help Pages as the default home page, so the first thing a guest to http://myserver should see is the Help Page.
I have a default route set up like this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Then I have my Help Page Area registration set up like this:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"HelpPage_Default",
"doc/{action}/{apiId}",
new { controller = "Help", action = "Index", apiId = UrlParameter.Optional });
HelpPageConfig.Register(GlobalConfiguration.Configuration);
}
When I change RouteConfig's controller to "Help" I get:
The view 'Index' or its master was not found or no view engine
supports the searched locations
When I change Help Page route to "{controller}/{action}/{apiId}" my AttributeRoutes stop working.
Is there some easy way to make ASP.NET Help Pages default home page?
I accomplished this with the following RouteConfig. I am also using ASP.Net Help Pages to auto-generate my documentation from the inline XML comments:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// By default route the user to the Help area if accessing the base URI.
routes.MapRoute(
"Help Area",
"",
new { controller = "Help", action = "Index" }
).DataTokens = new RouteValueDictionary(new { area = "HelpPage" });
}
}
I should also mention that I don't have any other routing in this class since I am using Attribute Routing on API methods individually.
For those who search where to add the route, with the current version of the WebApi and of the NuGet package you have to search for the file named "HelpPageAreaRegistration" in the Area folder added by NuGet.
Here is mine once it was coded to have the help page with WebApi has default web page.
public class HelpPageAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "HelpPage";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"HelpPage_Default",
"Help/{action}/{apiId}",
new { controller = "Help", action = "Index", apiId = UrlParameter.Optional });
context.MapRoute(
"Help Area",
"",
new { controller = "Help", action = "Index" }
);
HelpPageConfig.Register(GlobalConfiguration.Configuration);
}
}

Create a route with an additional url parameter without creating an area

I'm building a site for a client using .Net MVC 4. The entire site uses the default MVC 4 route and all the pages work fine
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
)
There is a page on the site called 'Teachers'. For this page, there are several links that take you to new pages that are subsets of the 'Teachers' page. The client wants the url structure to appear like this
www.{mysite}.com/School/Teachers/Apply
www.{mysite}.com/School/Teachers/Benefits
I thought I could simple add the Apply and Benefits pages as an ActionResult in my SchoolController then use the routing feature in MVC to map the url to the correct ActionResult method in the SchoolController.
This is my controller:
public class SchoolController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Administration()
{
return View();
}
public ActionResult Teachers()
{
return View();
}
public ActionResult Apply()
{
return View();
}
public ActionResult Benefits()
{
return View();
}
}
This is the custom route that I tried.
routes.MapRoute(
"Teachers",
"{controller}/{page}/{action}",
new { controller = "School", page = "Teachers", action = "Index" }
)
I placed this route before the default route but this adds 'teachers' to every url on the site like this:
www.{mysite}.com/{controller}/teachers/{action}
SUMMARY
All the pages on my site use this url structure:
www.{mysite}.com/{controller}/{action}
This one page, however, has the following structure:
www.{mysite}.com/{controller}/teachers/{action}
How can I do this with routes?
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "TeachersActions",
url: "School/Teachers/{action}",
defaults: new { controller = "School" },
constraints: new { action = "Apply|Benefits" } // actions under Teachers
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index",
id = UrlParameter.Optional }
);
}
Any actions you want to be under Teachers should be added to the route. It is actually not necessary to specify defaults for action or page for this route to work (unless you do have some need for a page route value to be captured). The catch here is that a user can still target the actions under Teachers by entering the URL School/{action} because it is caught by the default route. Now this may or may not be a concern for you. Personally I would not consider it such a big issue since the users should just be using the site's navigation instead of entering the URLs manually.

Have Microsoft changed how ASP.NET MVC deals with duplicate action method names?

I might be missing something here, but in ASP.NET MVC 4, I can't get the following to work.
Given the following controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string order1, string order2)
{
return null;
}
}
and it's view:
#{
ViewBag.Title = "Home";
}
#using (Html.BeginForm())
{
#Html.TextBox("order1")<br />
#Html.TextBox("order2")
<input type="submit" value="Save"/>
}
When start the app, all I get is this:
The current request for action 'Index' on controller type
'HomeController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Index() on type
ViewData.Controllers.HomeController System.Web.Mvc.ActionResult
Index(System.String, System.String) on type
ViewData.Controllers.HomeController
Now, in ASP.NET MVC 3 the above works fine, I just tried it, so what's changed in ASP.NET MVC 4 to break this?
OK there could be a chance that I'm doing something silly here, and not noticing it.
EDIT:
I notice that in the MVC 4 app, the Global.asax.cs file did not contain this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
which the MVC 3 app does, by default. So I added the above to the MVC 4 app but it fails with the same error. Note that the MVC 3 app does work fine with the above route. I'm passing the "order" data via the Request.Form.
EDIT:
In the file RouteConfig.cs I can see RegisterRoutes is executed, with the following default route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
I still get the original error, regards ambiguity between which Index() method to call.
Because MVC4 ships with ASP.Net Web.API you can potentially reference two HttpPostAttribute (the same applies to the other attributes like HttpGet, etc.):
System.Web.Mvc.HttpPostAttribute is used by ASP.Net MVC so you need to use it on actions inside Controller derived controllers
System.Web.Http.HttpPostAttribute is used by ASP.Net Web.API so you need to use it on actions inside
ApiController derived controllers
You have acidentally referenced System.Web.Http.HttpPostAttribute in your code. Change it to use the right attribute and it should work correctly:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[System.Web.Mvc.HttpPost]
public ActionResult Index(string order1, string order2)
{
return null;
}
}