Weird behaviour of RedirectToAction - asp.net-mvc-3

I'm developing portal in MVC 3. Have controller (MyController) with three methods Add (get and post verssion) and Index and part of add method looks like:
[HttpPost]
public virtual RedirectToRouteResult AddItem(Item item)
{
(...)
return RedirectToAction("Index");
}
Simple? Not fot me:)
Item is added properly and when redirecting comes url looks like:
MyController/Index
and not:
mySite/MyController/Index
and of course that is bad news. This situation happens only in one case in one place in the whole portal. What's wrong?

What you get as a return is a relative path, relative to your current path.

Problem solved-i had to change order of routemaps in global.asax -request was catched by wrong map.

Related

.net core mvc routing and controllers

So I am brand new to .net. I am learning .net core right now. I am trying to figure out routing. I can not seem to get the routing to look in any folder except Home and Shared. I have looked all over the internet and tried many things. There seems to be something I am missing. Here is what I got
app.UseMvc(routes =>
{
routes.MapRoute(
name: "test",
template: "Register/test",
defaults: new { controller = "Register", action = "test"}
);
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
I have a Register folder with a test.cshtml file in just to try t figure this routing out. And this is is in my HomeController.cs file
public IActionResult test()
{
return View();
}
on my _Layout page I have this link
<li><a asp-area="" asp-controller="Register" asp-action="test">Test</a></li>
It works fine when I put it in the home folder, but I want to keep things separate. I know there is something I am missing. I've poured through all kinds on articles online including Stack Overflow, and I just don't understand what I am missing. From what I read its suppose to be like the Parent folder/File/ then and id that may be attached to that like a user name I have tried other formats for the routing with no luck, this was just my most recent attempt. I just can't help but think I need some bit of code somewhere else.
From your question it looks like you have the following code in your HomeController.
public IActionResult test()
{
return View();
}
That actually belongs in your RegisterController because the route template you defined is an explicit capture with defaults to the "Register" controller and the "test" action.
The view called "test.cshtml" - which should be named as such because of the default convention - should reside in your \Views\Register folder, next door to \Views\Home.
There are a couple of reasons why this may have worked in some fashion. First, the view is discoverable for any controller if it's in shared. Without knowing more about the requests you tried, it's difficult to determine if routing kicked in on the first route or second, but if that method was truly on HomeController requests to /home/test would have worked.
It looks to me like you're exploring routing. That is great - I 100% encourage the experimentation - so long as you know that routing isn't necessarily the lowest hanging fruit to learn. It's also something that you shouldn't have to touch 93.7% of the time. For example, the route you have defined about wouldn't be required for the controller and action you're adding with RegisterController and test.
Cheers.

Returning a View in MVC3 when the Name of the cshtml is a Number?

I am new to MVC3 and so far I think its awesome. Very different however.
In one directory there is hundreds of .cshtml names in a format of: 01-01-01.cshtml. I cant return this view from the controller because the format of the named .cshtml is not recognised.
This link: How to get current page URL in MVC 3
It has a similar problem but is not the same.
What would be the best, fastest way to handle this problem without renaming all my files? (I don't want to do this)
The credit here is PSL's I have used that information to solve this problem. Also Credit to: stackoverflow.com/a/4969381/1183804 for initially posting this answer.
My cshtml Name:
01-01-01.cshtml
In the Controller:
[ActionName("01-01-01")]
public ActionResult U010101()
{
return View();
}
and to call this View:
#Html.ActionLink("<LinkName>", "01-01-01", "<ControllerName>")
Again this credit needs to go to PSL from the comments above.
Hope this helps others.

ApiController within an area

I want to have BlaController : ApiController, with BlaController located in /Areas/XXX/ ( or namespace MySolution.Areas.XXX.Controllers )
The problem is that when I browse to http://localhost:1935/XXX/Bla/SomeAction I get 404.
Normal controllers (: Controller) do not throw 404.
Note: SomeAction would be for example "public string SomeAction() { return "hi"; }", within BlaController
*Note 2: Tried* http://localhost:1935/api/Bla/SomeAction and didn't work either
Based on this SO question, looks like you need to build your own HttpControllerFactory in order to support Areas with WebAPI.
The question references an article on how to do this: http://netmvc.blogspot.com/2012/03/aspnet-mvc-4-webapi-support-areas-in.html
Hope this helps.
UPDATE:
Thanks to Bertrand who pointed to an updated article about WebApi support for Areas (which is still doesn't have by default). The updated link is http://netmvc.blogspot.be/2012/06/aspnet-mvc-4-webapi-support-areas-in.html

Routing document-relative static urls in MVC3

I'm integrating a JavaScript library into an ASP.NET MVC3 web app. The library assumes it will be installed next to the page that references it, and so it uses document-relative URLs to find its components.
For example, the default directory layout looks like
container-page.html
jslibrary/
library.js
images/
icon.png
extensions/
extension.js
extension-icon.png
However, I want to reference the library from the view in /Home/edit. I install the library in the default Scripts\jslibrary\ When I reference the library in the view in Views\Home\edit.cshtml, the library's document-relative links like
images/icon.png
end up as requests to
http://localhost/Home/images/icon.png
which results in a File Not Found (404) error. How do I construct a route to look for
{anyControllerName}/images/{anyRemainingPathInfo}
and serve up
http://localhost/Scripts/jslibrary/images/{anyRemainingPathInfo}
?
(full disclosure: I'm still on IIS 6 in Production, and not much chance of going to IIS7 any time soon, so if this is better done at the IIS level, please account for IIS6. Thanks!)
You could create a controller for handling you redirect logic - for example an "Images"controller. Register a global route in your Global.asax file, using the pattern (more on this type of pattern here:
routes.MapRoute(
"Images", // Route name
"{xyz}/{controller}/{path}", // URL with parameters
new {controller = "Images", action = "Index", path= UrlParameter.Optional} // Parameter defaults);
In your controller:
public ActionResult Index(string path)
{
//format path, parse request segments, or do other work needed to Id file to return...
return base.File(path, "image/jpeg"); //once you have the path pointing to the right place...
}
Not sure if this solution will work for you, wish I could come up with something more elegant. Best of Luck!
Short of rewriting the library and having it check for the appropriate directory the only solution I can think of is to include the views, library and supporting files in a directory structure that the library can access. This of course would break MVC's convention over configuration way of finding views, so you would have to write a custom override of the way Razor looks for views, which is not too complex to do, but you might be making life more difficult for yourself down the road depending on your application. Your call which is the lesser of the two evils :) (I'd go for fixing the library)
Make a help function
#functions{
public string AbsoluteUrl(string relativeContentPath)
{
Uri contextUri = HttpContext.Current.Request.Url;
var baseUri = string.Format("{0}://{1}{2}", contextUri.Scheme,
contextUri.Host, contextUri.Port == 80 ? string.Empty : ":" + contextUri.Port);
return string.Format("{0}{1}", baseUri, VirtualPathUtility.ToAbsolute(relativeContentPath));
}
}
Calling
#AbsoluteUrl("~/Images/myImage.jpg") <!-- gives the full path like: http://localhost:54334/Images/myImage.jpg -->
This example are from
https://dejanvasic.wordpress.com/2013/03/26/generating-full-content-url-in-mvc/

How to change a single querystring parameter, possibly via a control action?

In the last three days I've struggled trying to find a way to accomplish what I though was supposed to be a simple thing. Doing this on my own or searching for a solution in the web, didn't help. Maybe because I'm not even sure what to look for, when I do my researches.
I'll try to explain as much as I can here: maybe someone will be able to help me.
I won't say how I'm doing it, because I've tried to do it in many ways and none of them worked for different reasons: I prefer to see a fresh advice from you.
In most of the pages of web application, I have two links (but they could be more) like that:
Option A
Option B
This is partial view, retured by a controller action.
User can select or both (all) values, but they can't never select none of them: meaning that at least one must be always selected.
These links must che accessible in almost all pages and they are not supposed to redirect to a different page, but only to store this information somewhere, to be reused when action needs to filter returned contents: a place always accessible, regarding the current controller, action or user (including non authenticated users) (session? cookie?).
This information is used to filter displayed contents in the whole web application.
So, the problem is not how to create the business logi of that, but how (and where) to store this information:
without messing with the querystring (means: keeps the querystring as empty/clean as possible)
without redirecting to other pages (user must get the current page, just with different contents)
allow this information to persists between all views, until user click again to change the option(s)
My aim is to have this information stored in a model that will contains all options and their selection status (on/off), so the appropriates PartialView will know how to display them.
Also, I could send this model to the "thing" that will handle option changes.
Thanks.
UPDATE
Following Paul's advice, I've took the Session way:
private List<OptionSelectionModel> _userOptionPreferences;
protected List<OptionSelectionModel> UserOptionPreferences
{
get
{
if (Session["UserOptionPreferences"] == null)
{
_userOptionPreferences= Lib.Options.GetOptionSelectionModelList();
}
else
{
_userOptionPreferences= Session["UserOptionPreferences"].ToString().Deserialize<List<OptionSelectionModel>>();
}
if (_userOptionPreferences.Where(g => g.Selected).Count() == 0)
{
foreach (var userOptionPreferencesin _userOptionPreferences)
{
userOptionPreferences.Selected = true;
}
}
UserOptionPreferences= _userOptionPreferences;
return _userOptionPreferences;
}
private set
{
_userOptionPreferences= value;
Session["UserOptionPreferences"] = _userOptionPreferences.SerializeObject();
}
}
Following this, I've overridden (not sure is the right conjugation of "to override" :) OnActionExecuting():
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
GetOptionSelections();
base.OnActionExecuting(filterContext);
}
GetOptionSelections()...
private void GetOptionSelections()
{
if (String.IsNullOrEmpty(Request["optionCode"])) return;
var newOptionCode = Request["optionCode "];
foreach (var userOptionPreferencesin UserOptionPreferences)
{
if (userOptionPreferences.OptionCode == newOptionCode )
userOptionPreferences.Selected = !userOptionPreferences.Selected;
}
}
This code I think can be better, but right now I just want to make it work and it doesn't.
Maybe there are also other issues there (quite sure, actually), but I believe the main issue is that OnActionExecuting is called by each action in a controller that inherit from BaseController, therefore it keeps toggling userOptionPreferences.Selected on/off, but I don't know how to make GetOptionSelections() being called only once in each View: something like the old Page_Load, but for MVC.
Last update AKA solution
Ok, using the session way, I've managed to store this information.
The other issue wasn't really on topic with this question and I've managed to solve it creating a new action that take cares of handling the option's change, then redirects to the caller URL (using the usual returnUrl parameter, but as action parameter).
This way, the option change is done only once per call.
The only thing I don't really like is that I can't simply work with the UserOptionPreferences property, as it doesn't change the session value, but only the value in memory, so I have to set the property with the new object's status each time: not a big deal, but not nice either.
This is a place to use session.
The session will keep your setting between requests while keeping it out of the url querystring. It seems that you have probably tried this already, but try it again and if you have problems ask again. I think it will be the best way for you to solve this problem.

Resources