Runtime Error using Redis Cache Session State Provider - asp.net-mvc

So I have an MVC application in which I am trying to use Azure's Redis Cache for my Session State Provider. With everything coded and configured and all, when I publish it, the index page loads fine. The only button to hit is 'Next', which is supposed to add a session state variable with a value, and then move on to the appropriate page. But when I click 'Next' I get a runtime error. If I simply comment out the sessionState block in Web.config and publish it like that, I can move on to the 'next' page just fine. So I'm wondering what is wrong with my use of the provider and why it's not working?
Web.Config block:
<system.web>
<compilation debug="false" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" />
<sessionState mode="Custom" customProvider="MySessionStateStore">
<providers>
<add
type="Microsoft.Web.Redis.RedisSessionStateProvider"
name="MySessionStateStore"
host = "[Host name from Azure]"
port = "[Port # from Azure]"
accessKey = "[Key from Azure]"
ssl = "false"
throwOnError = "true"
retryTimeoutInMilliseconds = "5000"
databaseId = "0"
applicationName = ""
connectionTimeoutInMilliseconds = "5000"
operationTimeoutInMilliseconds = "1000"
/>
</providers>
</sessionState>
</system.web>
POST function when I hit the 'Next' button:
<HttpPost()>
<ValidateAntiForgeryToken()>
Async Function Index(ByVal obj As Type) As Task(Of ActionResult)
If ModelState.IsValid Then
Session("VarName") = obj
Return RedirectToAction("nextPage", "[controller]")
End If
Return View()
End Function
Note I am not using any cookies, nor am I trying to use the Redis Cache for anything else. The non-SSL port IS Enabled in Azure (yes, bad, I know - that will change).
I hope that's enough to go on to be able to help - if not, let me know. Thank you!

OK, well, figures that after posting this I'd find the answer!
So there is this very small note at the bottom of one of the articles I could find on Redis Session State Provider: https://msdn.microsoft.com/en-us/library/azure/dn690522.aspx
"Note that data stored in the cache must be serializable, unlike the data that can be stored in the default in-memory ASP.NET Session State Provider. When the Session State Provider for Redis is used, be sure that the data types that are being stored in session state are serializable."
The Type that I was trying to put into the session variable was a custom type. I had to add the "Serializable" attribute to my class!
Once I published it as serializable, then voila!

Related

ASP.NET Output Cache Provider for Redis doesn't store

I am not sure how to troubleshoot it but I am trying to implement ASP.NET Output Cache via Redis Output cache provider.
We have Redis server (non-azure) set up and I can store cache for general usage.
However, when I try to setup ASP.NET output cache, it doesn't seem to save anything to cache!
I have installed Microsoft.Web.RedisOutputCacheProvider via Nuget.
Web.Config is set up with following:
<caching>
<outputCache defaultProvider="MyRedisOutputCache">
<providers>
<add name="MyRedisOutputCache" type="Microsoft.Web.Redis.RedisOutputCacheProvider" host="ServerName" port="6464" accessKey="PasswordToRedis" />
</providers>
</outputCache>
</caching>
The MVC controller is setup with OutputCache attribute:
[OutputCache(Duration = 3600, VaryByParam = "*", Location = OutputCacheLocation.ServerAndClient)]
public JsonResult GetLookupData()
When I check the Redis, I don't see any OutputCache being stored.
Am I missing something? Is there a way to debug why it is not storing anything in cache?
Ok this was really silly.
When you install RedisOutputCacheProvider via Nuget, you will get this small doco in your app/web.config:
<!-- For more details check https://github.com/Azure/aspnet-redis-providers/wiki --><!-- Either use 'connectionString' OR 'settingsClassName' and 'settingsMethodName' OR use 'host','port','accessKey','ssl','connectionTimeoutInMilliseconds' and 'operationTimeoutInMilliseconds'. --><!-- 'databaseId' and 'applicationName' can be used with both options. --><!--
<add name="MyRedisOutputCache"
host = "127.0.0.1" [String]
port = "" [number]
accessKey = "" [String]
ssl = "false" [true|false]
databaseId = "0" [number]
applicationName = "" [String]
connectionTimeoutInMilliseconds = "5000" [number]
operationTimeoutInMilliseconds = "1000" [number]
connectionString = "<Valid StackExchange.Redis connection string>" [String]
settingsClassName = "<Assembly qualified class name that contains settings method specified below. Which basically return 'connectionString' value>" [String]
settingsMethodName = "<Settings method should be defined in settingsClass. It should be public, static, does not take any parameters and should have a return type of 'String', which is basically 'connectionString' value.>" [String]
loggingClassName = "<Assembly qualified class name that contains logging method specified below>" [String]
loggingMethodName = "<Logging method should be defined in loggingClass. It should be public, static, does not take any parameters and should have a return type of System.IO.TextWriter.>" [String]
redisSerializerType = "<Assembly qualified class name that implements Microsoft.Web.Redis.ISerializer>" [String]
/>
It indicates the default value for "ssl" would be false.
However, reading through the code itself, it is actually defaulted to true.
So explicitly setting ssl to false have fixed it.
EDIT
Oh and I had to downgrade RedisOutputCacheProvider to 1.7.5.
3.0.1 didn't work at all for me.
I have mine working on local host without the SSL setting. In production I require it, but on mine it is part of the connectionstring (that I was given by my Redis hosting service).
The reason it was not working and you had to downgrade RedisOutputCacheProvider to 1.7.5 is because you are using Exchange.Redis.Strongname.dll (version 1.2.6)
As per this issue, Redis no longer requires a strongname because the base version is now strong named.
https://github.com/Azure/aspnet-redis-providers/issues/107
So to use RedisOutputCacheProvider v3.0.144 you need to uninstall Exchange.Redis.Strongname.dll (version 1.2.6) and install Exchange.Redis.dll (version 2.0.601) via Nuget

Can't create Session in Asp MVC

I have an ASP.NET MVC Application which is published on 2 IIS web servers (one for debug and one for release).
In this application, I use a Session variable to keep the user Login, but in the release server this Session definition didn't work, returning the error:
object reference not set to an instance of an object
I believe that it can only be IIS configurations, because the same code works fine on the debug server and in localhost, that is why I can not debug the application.
I have never made a IIS configuration before, but in my search about it, I found that there is a config for the Sessions State (see this link here), which, for default, is set as true, and if I try to set false, nothing different happens.
Here's the code:
// POST: Auth/Login/{login}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(DTOViewModel login)
{
try
{
this.Autenticar(login.Usuario, login.Password);
Session["user"] = login.Usuario; // <---- Here is the problem
return Json(new { url = Url.Action("Index", "User/Home") });
}
catch (Exception ex)
{
return Json(new { erro = ex.Message });
}
}
Solution 1:
Check the maximum worker process associated with the application pool. It should be 1.
Steps to check the maximum worker process:
Go to the application pool from left panel in IIS
Select application pool which is associated with your website.
Go to the advance setting of that application pool
Set the Process Model --> "maximum worker process" to 1
Solution 2:
Change the below setting in web.config file:
<configuration>
<system.webServer>
<modules>
<remove name="Session" />
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>
</modules>
</system.webServer>
</configuration>

Can not set Session variables in MVC 3

I know that my question is basic one yet i need some responses because i have tried many solutions on the net and i still get the some error.
I have a gridPanel in the first view. If i click a button in this view, the selected rows will be displayed in another view. I need to send information with these rows to the server so i can load some extra data in the action proper to the click button.
To perform that, i should use Session instead of TempData or ViewBag/ViewData because i don't know when the user will click the button. Please correct me if i'm mistaken.
My code is like that: In the client side with AJAX i call an action method to set the session variables:
Ext.Ajax.request({ url: 'Examples/SetSelectedStations', params: { selectedStations: stationsStr} });
in the SetSelectedStations controller i realised that Session["slectedStations"] is always null and acts like have never been set. this is my controller action:
public ViewResult SetSelectedStations(string selectedStations)
{
Session["slectedStations"] = selectedStations;
string ss = Session["slectedStations"] as string;
// Here ss is null !!!!!!
return View();
}
Should i define Session["slectedStations"] in other place? Is there a special configuration in the web.confg file?
Please notice that the sessionState in my web.config is like that:
<sessionState mode="Custom" customProvider="PgSessionStateStoreProvider">
<providers>
<clear />
<add name="PgSessionStateStoreProvider" type="NauckIT.PostgreSQLProvider.PgSessionStateStoreProvider" enableExpiredSessionAutoDeletion="true" expiredSessionAutoDeletionInterval="1800000" enableSessionExpireCallback="false" connectionStringName="AspSQLProvider" applicationName="WebSite1" />
</providers>
</sessionState>

Why is the HttpContext.Cache count always zero?

I set up a few pages with OutputCache profiles and confirmed that they are being cached by using multiple browsers and requests to retrieve the page with a timestamp which matched across all requests. When I try to enumerate the HttpContect.Cache it is always empty.
Any ideas what is going on here or where I should be going for this information instead?
Update:
It's not client cache because multiple browsers are seeing the same response. Here is a bit of code to explain what's happening.
Web.Config caching settings
<system.web>
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<clear/>
<add name="StaticContent" duration="1200" varyByParam="none"/>
<add name="VaryByParam" duration="1200" varyByParam="*"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
...
</system.web>
**Action Method With Caching
[OutputCache(CacheProfile = "StaticContent")]
public ActionResult Index()
{
return View(new CollaborateModel());
}
Code to enumerate the cache, yep it's rough, an this is defined in a controller action method
var sb = new StringBuilder();
foreach (KeyValuePair<string, object> item in HttpContext.Cache)
{
sb.AppendFormat("{0} : {1}<br />", item.Key, item.Value.ToString());
}
ViewData.Add("CacheContents", sb.ToString());
The HttpContext.Cache is where the count is always null, even though the cache seems to be working fine.
That's probably because the page has been cached downstream on the client browser and not on the server.
Instead of using the HttpCache I ended up rolling my own caching model for holding datasets in my Data Access layer. If I was looking up the AD profile of a given username and converting it to a DTO then I just put that profile in a rolling collection of profile DTOs that I would check before polling AD for the information.

MVC RedirectToAction calls Session_Start() in global.asax

I am calling RedirectToAction method to call action method from another controller but it clears all session data
I debugged in global.asax and found out that when ever i call RedirectToAction it calls Session_Start() method.
I don't know how session start is called.
Here is my web config code for form and session tag
for session tag
<sessionState mode="InProc" customProvider="DefaultSessionProvider">
<providers>
<add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" />
</providers>
</sessionState>
and for form tag
<authentication mode="Forms">
<forms loginUrl="~/ControllerName/ActionName" timeout="2880" />
</authentication>
this "~/ControllerName/ActionName" is same method from wher i am calling "RedirecToAction"
just for info what i am trying is if i found cookies for user he will be redirected to home page from login page directly
both action methods are in different controller and in different Areas.
here is code which uses "RedirecToAction" method
public class LoginController : Controller{
public ActionResult Index()
{
if (Request.Cookies["UserName"] != null && Request.Cookies["Password"] != null)
{
FillLoginSession();//Fills Session with user data ex. Session["User_Id"] = 1;
return RedirectToAction("Index", "Home", new { area = "Home" });
}
}}
and here is action method in another controller to which i am redirecting.
public class HomeController : Controller{
public ActionResult Index()
{
return View();
}}
ok i got solution to this problem.
i was calling this
Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId", ""));
before initializing session from my method.
In my IIS this key "ASP.NET_SessionId" was used to store session in cookies.
as it was cleared it reinitialize everything when ever I redirect to new page.
Forms Authentication and Session State are 2 different and unrelated things.
Although you haven't shown the method that calls RedirectToAction, I suspect that you are not storing anything in session state beforehand. If you don't actually store something in Session State, you will get a new session on every request..
When using cookie-based session state, ASP.NET does not allocate storage for session data until the Session object is used. As a result, a new session ID is generated for each page request until the session object is accessed. If your application requires a static session ID for the entire session, you can either implement the Session_Start method in the application's Global.asax file and store data in the Session object to fix the session ID, or you can use code in another part of your application to explicitly store data in the Session object.
So to reiterate, to eliminate the call to Session_Start, you need to put something in session state before redirecting.
Session["TheKey"] = "TheValue";
return RedirectToAction("TheAction");

Resources