Re-direct loop when checking if value is null C# - c#

I am getting results based on an ID which is passed into the controller via the URL, for example Site/View/12 - this will bring back all results that match 12.
However, if there are no results, I want to re-direct back to the Index page which also has the search field.
public new ActionResult View(string ID = "")
{
XDocument xml = XDocument.Load(xmlPath);
var bikes = (xml).ToList();
if (!bikes.Any())
{
return RedirectToAction("Index", "Home");
}
else
{
return View(bikes);
}
}
However, whilst trying to view any page (/Add, /Index etc) I get a "This webpage has a redirect loop" error.
I'm not quite sure what's going on, because as far as I can tell viewing these pages shouldn't even trigger anything inside ActionResult View(). Also, the RedirectToAction is going to Index - so I cannot figure out where the loop is.
If I remove the line return RedirectToAction("Index", "Home"); the application functions normally.
Any advice would be very welcome, thank you.
(edit) Here's the Index controller:
public ActionResult Index()
{
return View();
}
And here's the RouteConfig.cs file:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}

The controller has a View method to return the view, but your Action method is also named View, and that's where it gets stuck. Change your action to be:
[ActionName("View")]
public new ActionResult ViewItem(string ID = "")
And everything should work OK.

Your action is named View. When you do
public ActionResult Index()
{
return View();
}
it's defaulting to your method (the optional parameter makes it valid):
public new ActionResult View(string ID = "")
If you mouseover return View() intellisense will tell you which View() its calling. Rename your View action and you'll see that the intellisense changes which View() is referenced, and it should work fine. Using an attribute to keep your action as View seems like its just going to cause another confusing headache later.

Related

How do I get ASP.NET to route a controller properly?

I have this in my controller:
public ActionResult Details(int? id)
{
if(id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Sales saleRecord = new Sales();
var result = saleRecord.GetSalesOrderHeader((int)id);
return View(result);
}
However if I browse to /ControllerName/Details/5 I get this error:
"Server Error in '/' Application. - The view 'details' or its master was not found or no view engine supports the searched locations."
The strange thing is that if I use ASP.NET Scaffolding to generate a view, the Details part of that works fine. It's basically the same code I have above as well.
Here's my RouteConfig.cs, if that's relevant:
public class RouteConfig
{
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 }
);
}
}
So why is that the scaffolding controller works fine, without having anything specific added to RouteConfig, yet my controller Details method is not working?
There should be more detail in error that what locations have been searched. Did you put break point in controller and checked if its being hit?
try
return View((object)result);
instead of
return View(result)
cause its calling overload View(string viewName)
If this doesn't work, try to specify viewName explicitly like this:
return View("ViewName", name);
Additionally, check your folder structure. MVC looks for views (like Index) under the views folder but they also have to be under a folder named after their controller (except partial views).

Route is matching on parameter, not action name / View isn't returning properly

I want to create a url like that below:
www.mywebapp.com/Users/Profile/john
I have the UsersController controller and the Profile action, which returns a ViewResult to the Profile page.
I've created a route to manage it:
routes.MapRoute(
name: "ProfileRoute",
url: "Users/Profile/{username}",
defaults: new { controller = "Users", action = "Profile", username = UrlParameter.Optional }
);
The first question is: If i change {username} by {id}, it works. When I put {username} like parameter, the action gets NULL in the parameter. Why this?
Here's my action called Profile:
[HttpGet]
public ActionResult Profile(string id) {
if (UsersRepository.GetUserByUsername(id) == null) {
return PartialView("~/Views/Partials/_UsernameNotFound.cshtml", id);
}
return View(id);
}
I've added a View page to show the user profile. However, when the method ends its execution, I got another error:
The view 'john' or its master was not found or no view engine supports the searched locations.
The following locations were searched:
~/Views/Users/john.aspx
~/Views/Users/john.ascx
...
The second question is: The page I have to show is Profile, not a page with the username's name. Why is it happening?
You are getting this error because you are passing a string (id) to the View function, this overload searches for a view with the name passed in the string (in this case the username).
if you are simply trying to pass the username directly to the view you can use something like a ViewBag, so your code should look like this:
public ActionResult Profile(string id) {
if (UsersRepository.GetUserByUsername(id) == null) {
return PartialView("~/Views/Partials/_UsernameNotFound.cshtml", id);
}
ViewBag.Username=id;
return View();
}
I might be reading this incorrectly, but if you change the name of the required parameter from
id to username, it shouldn't return null
[HttpGet]
public ActionResult Profile(string username) {
if (UsersRepository.GetUserByUsername(username) == null) {
return PartialView("~/Views/Partials/_UsernameNotFound.cshtml", id);
}
return View(username);
}

Possible to trigger action depending on given params for MVC Controller?

Say I have a controller called User, and I have a Index ActionResult, and then a secondary ActionResult called SetUserInfo. Example below:
public ActionResult Index(int id)
{
var enviorment = Zen.Components.Environment.GetEnvironmentByID(id);
return View(settingsViewModal);
}
//Second action
public ActionResult SetSite(int id, int siteID)
{
var enviorment =
Zen.Components.Environment.GetEnvironmentByID(
new EnviornmentQuery() {EnviormentID = id, SiteID = siteID);
return View(enviorment.Site);
}
Since the url "Settings?id=1" fires the ActionResult "Index", can I get "Settings?id=1&siteID=133" to then let the controller know it has to trigger ActionResult "SetSite" based on the params it was given, or do I have to make them optional in the first ActionResult, OR am I thinking of this all wrong. The route mapping is what is taking me a minute to fully get. I know it can be called as follows "Settings/SetSite?id=1&siteID=133", but wondering if I can do my prior example? If so, is it a bad way to handle it, or not?
You can map a route for it:
routes.MapRoute(
name: "SetSiteRoute",
url: "{controller}/{action}/{id}/{siteID}",
defaults: new { controller = "Settings", action = "SetSite" }
// Important part ^^^^^^^
);
Make sure you put it above your default route so that it takes precedence (routes are processed in order).
This will allow: www.site.com/Settings/1/500 where 1 is the id, and 500 is the siteID.
Although not exactly the answer you may be looking for..
First off, you cant map your route that way. The route cannot contain the ? character, so although you could use an alternative way to call your route using something like
/Settings/{id}/{siteId}
Using the following
/Settings?id={id}&siteID={siteId}
Cant be mapped as a route. However you could easily add the site id property to your Index action such as.
public ActionResult Index(int id, int? siteID)
{
if (siteID.HasValue)
return SetSite(id, siteID);
return null;
}
//Second action
public ActionResult SetSite(int id, int siteID)
{
return null;
}
I know this isnt exactly what you are looking for but will achieve the same result without having to mess around with your routes and urls. (Note i am just returning null so it compiles).
Cheers.

Must the first view must always be called index.aspx?

I have created a controller called loginController.cs and i have created a view called login.aspx
How do I call that view from loginController.cs?
The ActionResult is always set to index and for neatness, I want to specify what view the controller uses when called rather than it always calling its default index?
Hope that makes sense.
You can customize pretty much everything in MVC routing - there is no particular restriction on how routes look like (only ordering is important), you can name actions differently from method names (via ActionName attribute), your can name views whatever you want (i.e. by returning particular view by name).
return View("login");
In the interest of actually answering the question.. you can add a route ABOVE your default route in Global.asax:
routes.MapRoute(
"SpecialLoginRoute",
"login/",
new { controller = "Login", action = "Login", id = UrlParameter.Optional }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
..although, without properly thinking through what you're trying to achieve (that being.. changing what MVC does by default) you're bound to end up with lots and lots of messy routes.
Your return the view from your controller via your Action methods.
public class LoginController:Controller
{
public ActionResult Index()
{
return View();
//this method will return `~/Views/Login/Index.csthml/aspx` file
}
public ActionResult RecoverPassword()
{
return View();
//this method will return `~/Views/Login/RecoverPassword.csthml/aspx` file
}
}
If you need to return a different view (other than the action method name, you can explicitly mention it
public ActionResult FakeLogin()
{
return View("Login");
//this method will return `~/Views/Login/Login.csthml/aspx` file
}
If you want to return a view which exist in another controller folder, in ~/Views, you can use the full path
public ActionResult FakeLogin2()
{
return View("~/Views/Account/Signin");
//this method will return `~/Views/Account/Signin.csthml/aspx` file
}

.NET MVC Explicit Views

Hey, one more newbie here, just playing around with .NET MVC. My main task is to have a few semi-static pages on URLs like:
/about/
/about/contacts/
/about/jobs/
I'm using a controller for that called Static and have the following route attached:
routes.MapRoute(
"About",
"about/{id}",
new { controller = "Static", action = "Index", id = UrlParameter.Optional }
);
It seems to work fine as I have the Static controller with the Index method which uses a switch statement to identify which page has to be viewed. I use the RedirectToAction() function to call other actions of the Static controller in order to display pages with other views. My views are:
/Static/About.aspx
/Static/Contacts.aspx
/Static/Jobs.aspx
This method seems to work fine, but what I don't like about it is the redirect, so browsing to /about/contacts I get a redirect to /Static/Contacts which is not what I'd really like to see in the URL.
So my question is - what is the correct way of doing this? And is there a way to explicitly call a certain view from my Index action?
Thanks,
~ K.
Don't do the redirect. Instead of using a switch statement within the Index action, have a separate action for each page (ie. About, Contacts, Job) each with their own view.
Your Static controller could look something like this:
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
return View();
}
public ActionResult Contacts()
{
return View();
}
public ActionResult Jobs()
{
return View();
}
And if you needed to do any processing specific to Contacts or Jobs, it can be done within their respective actions.
To explicitly call a certain view:
return View("ViewName");
There are seven overloads for the View() method. A number of which allow you to pass the Model:
return View("ViewName", Model);
I'd recommend moving away from Static, and have an About controller. Within that controller, one method per page.
public ActionResult About()
{
return View ("About");
}
//Jobs() and Contacts() follow the same pattern
3 routes to match:
routes.MapRoute(
"Jobs",
"about/jobs",
new { controller = "About", action = "Jobs" }
);
routes.MapRoute(
"Contact",
"about/contact",
new { controller = "About", action = "Contact" }
);
routes.MapRoute(
"About",
"about/",
new { controller = "About", action = "About" }
);
you cant return views from a different controller and have the first controller in the URL.
the only way is use your about controller.
so place your logic in your about controller.
i have the same for myself in my Admin controller. it's just a page with some static links, and some extra pages.
in the index.aspx i have
<ul>
<li>
<%= Html.ActionLink("Evaluaties", "Evaluaties", "Admin")%></li>
<li>
<%= Html.ActionLink("ONAS aanbieders", "Index", "ONASAanbieder")%></li>
<li>
<%= Html.ActionLink("ONAS aanbod", "Index", "ONASAanbod")%></li>
<li>
<%= Html.ActionLink("Helpbox", "Index", "HelpBox")%></li>
</ul>
in the controller I have
public ActionResult Index() {
return View();
}
public ActionResult Evaluaties() {
return View();
}
this works like you described, no need to alter the routes.
obviously i have an Evaluaties.aspx in my Admin folder in the Views folder.
gives me this URL: http://localhost:50152/Admin/Evaluaties

Categories