Session across controller becomes null in MVC - asp.net-mvc

My session becomes null when I redirect to another controller's Action, what should I do?

With regards to the comment you posted me, here is what I was thinking. In the Controller where you need the session use something similar to this:
//Controller A
public class TheController : Controller
{
public ActionResult Index(){
Session["yourSession"] = "Hello World";
return View();
}
}
//Controller B
public class MyController : Controller
{
string textString;
protected override void OnActionExecuting(ActionExecutingContext ctx)
{
base.OnActionExecuting(ctx);
textString = ctx.HttpContext.Session["yourSession"].ToString();
}
public ActionResult Index(){
string currentText = textString;
return View();
}
}
I tested the suggestion from (http://stackoverflow.com/questions/889516/session-null-in-asp-net-mvc-controller-constructors), and the contents of the session were available.

You have to create a unique base controller with a session property, then all controllers within your project will inherit from that BaseController:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MonitoringCSP.Controllers
{
//[AllowAnonymous]
//[Authorize(Roles = "admin")]
public class BaseController : Controller
{
private HttpSessionStateBase _session;
protected HttpSessionStateBase CrossControllerSession
{
get
{
if (_session == null) _session = Session;
return _session;
}
set {
_session = Session;
}
}
}
}
Usage sample
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using MonitoringCSP.Models;
namespace MonitoringCSP.Controllers
{
[AllowAnonymous]
public class AccountController : BaseController
{
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
/*session*/
CrossControllerSession["UserName"] = User.Identity.Name;
/*end session*/
return RedirectToAction("someAction");
}
}
}

I realized that I was clearing and destroying all sessions prior to setting the new session on login like this
Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
Session.Abandon();
Session.Clear();
When I removed these lines, everything started working like #Clayton said, so I removed these lines and replaced it with Session.Remove('sessionvariablename'), I am still not sure what issue were the above lines causing, but my code started working.

Make sure your controller does not have this attribute set on it:
[SessionState(SessionStateBehavior.Disabled)]

Related

Why does RedirectToActionResult ControllerName return NULL?

I have a Xunit test class for a MVC:
using System;
using Xunit;
using Home.Controllers;
using Microsoft.AspNetCore.Mvc;
using Tester.Models;
using Xunit.Abstractions;
namespace ClassLibrary1
{
public class Class1
{
[Fact]
public void CreateinController()
{
HomeController c = new HomeController();
var result = c.Create();
//result moet een view zijn
var viewResult = Assert.IsType<ViewResult>(result);
//Juiste redirection
var result2 = c.Create(null);
var redirectToActionResult =
Assert.IsType<RedirectToActionResult>(result2);
Assert.Equal("Home", redirectToActionResult.ControllerName);
Assert.Equal("BoekingVerwerken", redirectToActionResult.ActionName);
}
}
}
Whenever I run the test the ActionName passes the test because it actually contains the value. But the ControllerName seems to be NULL valued, why is this?
When the Action has a value why wouldn't the Controller have one? Should I put the controller in the RTA?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Tester.Models;
namespace Home.Controllers
{
public class HomeController : Controller
{
[HttpGet]
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create(HotelBoeking boeking)
{
return RedirectToAction("BoekingVerwerken", boeking);
}
[HttpGet]
public IActionResult BoekingVerwerken(HotelBoeking boeking)
{
return View(boeking);
}
}
}
If you take a look at the Controller.cs source code, you will see that RedirectToAction returns a RedirectToRouteResult type, not a RedirectToActionResult type.
As you can see from the source code of RedirectToRouteResult.cs, you can get the controller name from the RouteValues property. There is no ControllerName property on this type.
var redirectToRouteResult =
Assert.IsType<RedirectToRouteResult>(result2);
Assert.Equal("Home", redirectToRouteResult.RouteValues["controller"]);
I am not entirely sure the syntax for XUnit is correct, as I don't work with it much, but you should take away from this that because MVC is open source that questions like this one can be easily answered by inspecting the source code.

Prevent execution within Action Filter

I wish to create an Action Filter that checks that the user created some content. If they don't, then I'd like to prevent the action from being executed and return an error.
This is what I have so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using uQuiz.Domain.Abstract;
using uQuiz.WebUI.Helpers;
using Microsoft.AspNet.Identity;
using System.Net.Http;
using System.Net;
namespace uQuiz.WebUI.Controllers.Filters
{
/// <summary>
/// Determines whether the current logged in user has permission to edit the quiz requested
/// </summary>
public class CanEditQuiz : ActionFilterAttribute
{
IQuizEntities Context;
public CanEditQuiz()
{
}
public CanEditQuiz(IQuizEntities context)
{
this.Context = context;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
// Get the URL ID from the request
string urlId = actionContext.ModelState["urlId"].Value.ToString();
int userId = HttpContext.Current.User.Identity.GetUserId<int>();
if (!QuizHelper.IsQuizOwner(this.Context, urlId, userId))
{
// Prevent action executing
}
base.OnActionExecuting(actionContext);
}
}
}
I've seen other questions mentioning to set Result to null, but when I overrode the OnActionExecuting method it has HttpActionContext and not ActionExecutingContext for some reason?
How do I prevent the action from executing?
You need to use
System.Web.Mvc.ActionFilterAttribute
not
System.Web.Http.Filters.ActionFilterAttribute

asp.net mvc authorization problem

I am trying to add authorization to my controllers and it's not working...
I am not sure where to look in my program, but adding the
[Authorize]
filter in my controller is not working, let alone anything like
[Authorize(Roles = "Manager")]
I have been able to get this working in the default application that is provided when creating a new MVC project (i.e., I am able to make the "about" tab redirect to the login screen if I'm not logged in), so I assume I have mucked things up along the way as I've built my app. Does anyone know where I should be looking to fix this? I have users and they have roles; I'm using the ASP.net schema that is auto-created; I've examined my web.config file up and down and although I'm pretty new to this, nothing seems to be out of place. I have no clue why my authorization filters aren't working.?.
I wrote a custom attribute to solve this problem. You can attribute your controller methods as follows:
[RequiresRole(Role="Admin")]
public ActionResult Index()
{
int i = 5 + 5;
return View();
}
The code for the attribute is as follows....
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
namespace Web.Controllers
{
public class RequiresRoleAttribute : ActionFilterAttribute
{
public string Role { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (string.IsNullOrEmpty(Role))
{
throw new InvalidOperationException("No role specified.");
}
string redirectOnSuccess = filterContext.HttpContext.Request.Url.AbsolutePath;
string redirectUrl = string.Format("?returnUrl={0}", redirectOnSuccess);
string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.HttpContext.Response.Redirect(loginUrl, true);
}
else
{
bool isAuthorised = filterContext.HttpContext.User.IsInRole(this.Role);
if (!isAuthorised)
{
filterContext.HttpContext.Response.Redirect(loginUrl, true);
}
}
}
}
}

asp.net MVC confused by custom attributes creation

hi i am trying to create a custom attribute for my MVC application so that i can call [CheckLogin] this is to check my cookie as i am not using forms authentification.
i have created a class CheckLogin and this is in my App_Code folder and the code is as follows:
using System.Web.Mvc;
using System.Attributes;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Web;
using System;
namespace corian_MVC.Controllers
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class CheckLoginAttribute : FilterAttribute, IAuthorizationFilter
{
public CheckLoginAttribute() {}
public void OnAuthorization(AuthorizationContext filterContext)
{
// TODO: perform your cookie checks
if (!userIsAuthenticated)
{
filterContext.Result = new RedirectResult(string.Format(
"/Admin/Login",
filterContext.HttpContext.Request.Url.AbsoluteUri));
}
}
}
}
what it does is not important here, the problem is i cant get my code to recognise this attribute if it is one in the first place, also how do i redirect to action if the login is failed ????
many thanks
my admin class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace corian_MVC.Controllers
{
[HandleError]
public class AdminController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index()
{
//check login is not banned
if ((int)Session["LoginCount"] >= 3) RedirectToAction("TooMany");
return View();
}
public ActionResult Fraud()
{
Session["LoginCount"] = 3;
return View();
}
public ActionResult TooMany()
{
return View();
}
[CheckLogin]
public ActionResult Welcome()
{
return View();
}
private void Createcookie()
{
}
}
}
This scenario is best handled by implementing an IAuthorizationFilter.
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=true)]
public class CheckLoginAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
// TODO: perform your cookie checks
if (!userIsAuthenticated)
{
filterContext.Result = new RedirectResult(string.Format(
"/loginUrl?ReturnUrl={0}",
filterContext.HttpContext.Request.Url.AbsoluteUri));
}
}
}
Then you can apply this attribute either at the controller level or at some particular actions.
By the way do you have any particular reason for not using the built-in FormsAuthentication?
Include .cs file with your attribute to the solution. Just placing it "near default.aspx" is not enough.

Base controller class

I have a base controller class and I would like to pass a Message from the Base class to all controllers and for that message to be available to all views.
I've created a basic version below...
Section Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Website.Controllers
{
public class SectionController : Controller
{
//
// GET: /Section/
public ActionResult Section()
{
ViewData["Message"] = "THIS IS A TEST";
return View();
}
}
}
Home Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Website.Controllers
{
public class HomeController : SectionController
{
public ActionResult Index()
{
return View();
}
}
}
View
<%= Html.Encode(ViewData["Message"]) %>
I know I can do this in the home controller but I'm just testing at the mo.
I'm not getting any errors with the above but I'm also not displaying the message on my view?
I'm using this tutorial http://www.asp.net/LEARN/mvc/tutorial-13-cs.aspx The Good Solution part, if that helps.
Think I've got it working now used the code below on my sectionController...
namespace Website.Controllers
{
public class SectionController : Controller
{
//
// GET: /Section/
public SectionController()
{
ViewData["Message"] = "THIS IS A TEST";
//return View();
}
}
}
Is this an ok solution?
You're setting your ViewData in the Section action method of your base controller, do you actually want to be setting it in the constructor of your base controller?
public SectionController()
{
ViewData["Message"] = "THIS IS A TEST";
}
HomeController.Index isn't calling SectionController.Section.
Because none of the requests are mapped to action "Section" in SectionController. If you mapped a request like domain/Section/Section, you would see your message in your view (Assuming that you are using default routing and have a view named "Section").
What you need to do is, placing your message into the viewdata on a method that runs every time an action is run. You can do it in OnActionExecuting like:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
ViewData["Message"] = "THIS IS A TEST";
base.OnActionExecuting(filterContext);
}
in the SectionController.

Resources