Using Html.Action causes query string too long error - c#

I have a _LayoutView:
#{
Layout = "~/Views/Shared/_NavLayout.cshtml";
}
#section styles
{
#RenderSection("styles", required: false)
}
<div class="container" style="padding-top: 60px;">
<div class="row">
<div class="col-md-12">
#Html.Action("AccountNavigation")
</div>
</div>
#RenderSection("InlineTitle", required:false)
#RenderBody()
</div>
#section scripts {
#Scripts.Render("~/bundles/jqueryval")
#RenderSection("scripts", required: false)
}
That renders fine if I remove the
#Html.Action("AccountNavigation")
Otherwise I get:
The action method is:
[ChildActionOnly]
public ActionResult AccountNavigation()
{
var roles = UserManager.GetRoles(User.Identity.GetUserId());
ViewBag.IsAdmin = roles.Contains("Admin");
return PartialView("_AccountNavigatorPartial");
}
And Ive tried stripping it back to just:
[ChildActionOnly]
public ActionResult AccountNavigation()
{
ViewBag.IsAdmin = false;
return null;
}
But it makes no difference.
One of the child views that uses the layout is Login.
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.OidLoginFailed = false;
ViewBag.ReturnUrl = returnUrl;
return View();
}
If I put a break piont in there I can see its being called multiple times per request and building up the ReturnUrl until it fails hence the error message. This is why I stripped back the AccountNavigation ActionMethod.
I thought maybe an anon request was causing a post back via some config setting that says if Anon redirect to Login and round and round it would go but I cant see where that is being triggered.
The account _AccountNavigatorPartial is just:
<ul class="nav navbar-nav navbar-Left">
<li>#Html.ActionLink("Manage Credentials", "Credentials", "Account",
routeValues: null, htmlAttributes: new { id = "credentialsLink" })</li>
<li>#Html.ActionLink("Manage Profile", "Profile", "Account",
routeValues: null, htmlAttributes: new { id = "credentialsLink" })</li>
</ul>
So all I'm trying to do is inject some html for account navigation. I'm using ASP.Identity for membership but I cant see how that makes any difference as I'm requesting an Anon accessible page.

It's hard to tell without seeing the controller and knowing how you are handling authorization, however, since your login page is using that Layout, you may be experiencing a circular call due to failure of authorization on you child action.
Have you tried adding the attribute [AllowAnonymous] to your child action?

We were getting similar UriFormatException: Invalid URI: The Uri string is too long. - we found the solution was to pass the model in as an explicit parameter instead of just the typical approach.
Not Working
#Html.Action("MyChildAction", "Path", Model)
Working
#Html.Action("MyChildAction", "Path", new { viewModel = Model} )
This seems to be triggered by using a very large view model - this must wrap it and bypass the encoding issue UriHelper.EscapeString which overflows the buffer.

Related

MVC RedirectToAction not working - getting "The resource cannot be found"

In my UserController, I am issuing:
return RedirectToAction("SignOut", "SignIn");
but getting:
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been
removed, had its name changed, or is temporarily unavailable. Please review the following URL and
make sure that it is spelled correctly.
Requested URL: /SignIn/SignOut
The SignInController action method:
[HttpPost]
public ActionResult SignOut()
{
// Setting cache.
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetExpires(DateTime.Now.AddSeconds(-1));
Response.Cache.SetNoStore();
// Setting cookies.
// Instantiate a Cookie.
HttpCookie Cookies = new HttpCookie("Gbng");
Cookies.Value = "";
Cookies.Expires = DateTime.Now.AddHours(-1);
Response.Cookies.Add(Cookies);
HttpContext.Session.Clear();
Session.Abandon();
// Redirect to the Home controller.
return RedirectToAction("Index", "Home");
}
I have a partial view that references the same action method but has the POST method:
#if ( (string)#Session["IsAuthenticated"] == "true" )
{
using (Html.BeginForm("SignOut", "SignIn", FormMethod.Post, new { id =
"signoffForm", #class = "navbar-right" }))
{
#Html.AntiForgeryToken()
<ul class="nav navbar-nav navbar-right">
<li>
<a
href="javascript:document.getElementById('signoffForm').submit()">Sign
out</a>
</li>
</ul>
}
}
else
{
<ul class="nav navbar-nav navbar-right">
<li>#Html.ActionLink("Register", "Register", "Register",
routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
<li>#Html.ActionLink("Sign in", "SignIn", "SignIn", routeValues:
null, htmlAttributes: new { id = "signLink" })</li>
</ul>
}
RedirectToAction, is performing a HTTP GET
Your SignOut method is decorated with [HttpPost], and hence, it can not find the resource.
Since SignOut is a typical post action - i.e.; pressing a button and such, I would suggest to put the sign-out logic in a separate method and call it from where you want to use it. This means you don't need a redirect to perform the sign-off.
As from your comment; you can create a helper method to perform the task:
public class Helper
{
public static void SignOut(System.Web.SessionState.HttpSessionState session,
HttpResponse response)
{
// Setting cache.
response.Cache.SetCacheability(HttpCacheability.NoCache);
response.Cache.SetExpires(DateTime.Now.AddSeconds(-1));
response.Cache.SetNoStore();
// Setting cookies.
// Instantiate a Cookie.
HttpCookie Cookies = new HttpCookie("Gbng");
Cookies.Value = "";
Cookies.Expires = DateTime.Now.AddHours(-1);
response.Cookies.Add(Cookies);
session.Clear();
session.Abandon();
}
}
and call it in both functions, after that; you can redirect - I don't have a compiler at my disposal right now, but I think you can work out any inaccuracies.
[HttpPost]
public ActionResult SignOut()
{
Helper.SignOut(Response, Session);
return RedirectToAction("Index", "Home");
}
[HttpPost]
public ActionResult OtherAction()
{
Helper.SignOut(Response, Session);
return RedirectToAction("Index", "Home");
}

MVC, how to post data to controller and redirect to aspx page

I have an MVC view where user can set a flag and post data to controller (post because I want to hidden query string)
After the controller have done his job I want to redirect to website home page that is an aspx page (my site is mixed aspx and MVC)
Is there a way to do that?
This is my view
#model MessaggiVM
<form role="form" class="form-inline" method="post" action="Messaggi/VaiAllaHome">
<button id="btnHome">Vai alla pagina iniziale</button>
<div class="form-group">
<label for="nascondi">hiding</label>
<input id="nascondi" type="checkbox" name="nascondi" value="true" />
</div>
<input type="hidden" name="elencoPost" value="#Model.Posts" />
#*#Html.ActionLink("Messaggi", "VaiAllaHome", new { posts = Model.Posts} )*#
</form>
And this the controller
[HttpPost]
public RedirectResult VaiAllaHome(bool? nascondi = false, IEnumerable<Messaggio> elencoPost = null)
{
// do something
return Redirect(Url.Content("~/"));
}
When I run this code controller action is executed without error but redirect is not done and browser remain on the view
Other problem is that elencoPost parameter is empty in the action but I'm investigating it
EDIT
Honestly I'm thinking to post data on input change and switch button for a simply link
EDIT 2:
found the reason: in default.aspx i have a auto-redirect to Message page :(
Try
return Redirect("~/home.aspx");
or
return Redirect(Url.Content("~/home.aspx")
You should be able to use Redirect with a relative url:
[HttpPost]
public RedirectResult VaiAllaHome(bool? nascondi = false, IEnumerable<Messaggio> elencoPost = null)
{
// do something
return Redirect("/home.aspx");
}
Try using a #Url.Content on your form tag
<form action="#Url.Content("~/Messaggi/VaiAllaHome/")">
Then in your Controller
[HttpPost]
public RedirectResult VaiAllaHome(bool? nascondi = false, IEnumerable<Messaggio> elencoPost = null)
{
// do something
return View(Url.Content("~/"));
//return RedirectToAction("Action", "Controller", new { routeParameter = value } /*e.g. "id = 1"*/);
}

Call an action method from layout in ASP.NET MVC

I have one layout and one partial view which are in the Shared folder. Partial view presents top menu items which are not static. So I need to call an action method to get menu items from database. To do this, I created a controller and add an action method in it.
When I try to browse the page in web browser, this error occured:
The controller for path '/' was not found or does not implement IController.
Note:
I tried Html.RenderAction, Html.Partial methods too...
And I tried to create another view folder, and create a new partial view and new controller that named with "folder name + Controller" suffix.
Layout:
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
</head>
<body>
<div id="header">
#Html.Action("~/Views/Shared/_TopMenu.cshtml", "LayoutController", new {area =""}); //Here is the problem.
</div>
<div>
#RenderBody();
</div>
</body>
</html>
_TopMenu.cshtml:
#model IList<string>
#foreach (string item in Model)
{
<span>item</span>
}
LayoutController (in Controllers folder):
public class LayoutController : Controller
{
//
// GET: /Shared/
public ActionResult Index()
{
return View();
}
[ChildActionOnly]
[ActionName("_TopMenu")]
public ActionResult TopMenu()
{
IList<string> menuModel = GetFromDb();
return PartialView("_TopMenu", menuModel);
}
}
What happens if you put this in your view?
#{ Html.RenderAction("TopMenu", "Layout"); }
(And comment this out until everything works: //[ChildActionOnly])
Change this line,
#Html.Action("~/Views/Shared/_TopMenu.cshtml", "LayoutController", new {area =""});
to,
#Html.Action("_TopMenu", "Layout", new {area =""});
and check.
exist differents ways, for this case I like use html.action in layout, and in control I will create a string Menu, the string contains the html code I need, the controller end with return Content(menu);
for example
Layout:
<body>
<nav>
#Html.Action("_TopMenu", "Layout")
</nav>
the controller
public class LayoutController : Controller
{
public ActionResult _TopMenu()
{
IList<string> menuModel = GetFromDb();
string menu = "<ul>";
foreach(string x in menuModel)
{
menu +="<li><a href='"+x+"'>+x+"</a></li>";
}
menu+="</ul>";
return Content(menu);
}
}
I like that because I can use many options to create menus dinamics more complexes.
other way use ajax to recovered the data and use handlebars or other template for the code
You are using the wrong overload of the Action-Method. The 2nd parameter in the variation is not the controllername but the actionname.
You can check the correct Method overloads on this page
Also: If you specify Controllers in the Html.Action Method (which you can do for example with this variation of the Method), you dont need to write the suffix "Controller" even if thats your Classname. So Instead of using the string "LayoutController" you would write simply "Layout".
At this point the framework is convention-based.
This is how I did it:
Layout
#Html.Action("GetAdminMenu", "AdminMenu")
Admin Menu Controller
public PartialViewResult GetAdminMenu()
{
var model = new AdminMenuViewModel();
return PartialView(model);
}
GetAdminMenu.cshtml
#model ReportingPortal.Models.AdminMenuViewModel
<div class="form-group">
<label class="col-md-4 control-label" for="selectbasic">School Name</label>
<div class="col-md-8">
#Html.DropDownListFor(model => model.SelectedID, new SelectList(Model.DataList, "Value", "Text", Model.SelectedID), "", new { #class = "form-control", #required = "*" })
</div>
</div>

<$G+$> Strange characters appearing in ASP.NET MVC5 Helper

My helper in the view, which is intended to display the full name of a user who is registered in the application, and the username if logged in via 3rd party authentication.
#using MyApp.Models;
#helper GetUserName()
{
if (User.Identity.AuthenticationType == "Application")
{
using (var db = new MyAppDbContext())
{
#db.Users.Find(User.Identity.GetUserId()).FullName
}
}
else
{
#User.Identity.GetUserName()
}
}
Then I use this helper:
#if (Request.IsAuthenticated)
{
using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", #class = "navbar-form pull-right" }))
{
#Html.AntiForgeryToken()
<ul class="nav">
<li>
#Html.ActionLink("Hello " + GetUserName() + "!", "Manage", "Account", routeValues: null, htmlAttributes: new { title = "Manage" })
</li>
<li>Log off</li>
</ul>
}
}
The name of my user is Proba234, and it displays like this:
Why are those strange characters (<$G+$>) appear, and how to get rid of them?
It is probably some kind of feature or bug related with usage of helpers within Visual Studio Page Inspector, you probably won't see those tags under external browser. I reproduced it easily in VS 2013. A thread about it can be found for example on ASP.NET forum
It seems like those funny characters are generated by helper. The probleem seems to be that the output of the helper is not meant to be consumed as regular string. Apparently it generates some control characters, which are meant to be there for Razor, but if we try to use the output as regular string (as #Html.ActionLink() expects its argument) they become visible.
To get rid of them, I shouldn't use the GetUserName() helper inside the #Html.ActionLink(), but get the UserName in the controller, and pass it via a property of the viewmodel. I shouldn't have that kind of logic in my view anyway.

partial view login on home page

This question has been asked many times but I don't think the way I need it.
I'm trying to implement a login form on the home page but this form is located in a section that pops up, like you have on this site: http://myanimelist.net.
I've created a partial view for my login form:
#model ArtWebShop.Models.customers
#section Validation {
#Scripts.Render("~/bundles/jqueryval")
}
<section id="login">
#using (Html.BeginForm("LoginValidate", "Login", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
#Html.ValidationSummary()
<fieldset>
<legend>Login</legend>
#Html.LabelFor(model => model.email)
#Html.TextBoxFor(m => m.email)
#Html.LabelFor(m => m.password)
#Html.PasswordFor(m => m.password)
<input type="submit" value="Login" class="button" />
</fieldset>
}
</section>
This is shown on the home page (index.cshtml):
<section class="shown">
#Html.Partial("_LoginPartial")
#Html.ValidationSummary(true)
#Html.ValidationSummary()
</section>
The partial view is shown correctly.
But now comes the part that doesn't work.
When you press login if you haven't filled in the fields, the validation is done in my LoginController as it should but I can't seem the send the errors to my home page view when I redirect.
[HttpPost]
public ActionResult LoginValidate(string redirect)
{
if (_unitOfWork.CustomersRepository.CostumerIsValid(Request.Form["email"], Request.Form["password"]))
{
if (!String.IsNullOrEmpty(redirect) || String.Compare(redirect, "none", StringComparison.OrdinalIgnoreCase) == 0)
{
if (redirect != null) Response.Redirect(redirect, true);
}
else
{
return RedirectToAction("index", "Home");
}
}
ModelState.AddModelError("email", "You entered an incorrect email address");
ModelState.AddModelError("password", "You entered an invalid password");
return RedirectToAction("index", "Home");
}
That's my loginValidation. Since nothing is filled in the errors are added to the ModelState and then it redirects to the home page. This however doesn't shows me the errors.I'm guessing it's exactly because I redirect but how can I solve this?
You can use TempDataDictionary to store the ModelStateDictionary between redirects.
TempDataDictionary Class
Represents a set of data that persists only from one request to the next.
In your LoginValidate action you would store the ModelState like so:
public ActionResult LoginValidate(string redirect)
{
/* Your other code here (omitted for better readability) */
ModelState.AddModelError("email", "You entered an incorrect email address");
ModelState.AddModelError("password", "You entered an invalid password");
// Add the ModelState dictionary to TempData here.
TempData["ModelState"] = ModelState;
return RedirectToAction("index", "Home");
}
And in your HomeController, Index action you would check if the TempData has a ModelState:
public ActionResult Index()
{
var modelState = TempData["ModelState"] as ModelStateDictionary;
if (modelState != null)
{
ModelState.Merge(modelState);
}
return View();
}
You could make this a little bit cleaner by using custom action filters; see this blog, number 13.
You can achieve this by using jQueryUI Dialogs and AjaxForms. Please check this demo: http://demo.ricardocovo.com/EditDialogsAndFormRazor/Cars.
You can implement a similar behaviour for your login form as for the Edit functionality in the link provided. You'll find the idea explained here: http://ricardocovo.com/2012/04/06/asp-mvc3-editing-records-with-jqueryui-dialogs-and-ajaxforms-razor-version/

Categories