I'm developing a web application with C# MVC and using Session to persist data between multiple requests.
Sometimes the session timed out so I looked for way to keep it alive and found some solutions here in stackoverflow. Being reluctant to simply copy-paste code into my project I attempted to rewrite the code to fit my needs and understand it better.
At first I attempted to keep the session alive using the following code:
JS + jQuery - client side:
function keepAliveFunc(){
setTimeout("keepAlive()", 300000);
};
function keepAlive() {
$.get("/Account/KeepAlive", null, function () { keepAliveFunc(); });
};
$(keepAliveFunc());
C# - server side:
[HttpGet]
public bool KeepAlive()
{
return true;
}
This however did not seem to keep my session alive, it expired normally.
After a while of fiddling around I changed the code to:
JS + jQuery - client side:
function keepAliveFunc(){
setTimeout("keepAlive()", 10000);
};
function keepAlive() {
$.post("/Account/KeepAlive", null, function () { keepAliveFunc(); });
};
$(keepAliveFunc());
C# - server side:
[HttpPost]
public JsonResult KeepAlive()
{
return new JsonResult { Data = "Success" };
}
The latter worked well which has me conclude, with some uncertainty, that the Session is kept alive because of the POST request instead of the GET. Which raises the question: Why do I need to use POST when trying to keep my Session alive? What's the difference? Am I making some other mistake which I do not comprehend?
I've looked for answers but I cannot seem to find any on this matter, merely solutions without much explanation. Reading up on Session on MSDN also didn't help me much. This makes me conclude that there are some "words" related to Session and this perticular problem that I haven't encountered yet which makes me unable to google effectively.
With either GET or POST, the browser does send the SessionId cookie with the request. So for keep-alive purposes it doesn't matter which one you use. Most likely you are seeing the difference in behavior because of the different interval you and "pinging" the server.
With the GET request you did it at an interval of 300000 ms, while with the POST request you did it at an interval of 10000 ms.
Most likely, your server's session lifespan is somewhere between the two values.
You could, however, configure the session lifespan to fit your needs (as in increasing it), but keep in mind that expiring sessions is a security feature so try to find a small value that is big enough to let your application work ok, but still allow the session to expire in a safe interval of time.
Related
I'm working on a fairly complex Xamarin.Forms application. We make a lot of REST requests. It's been reported that our application isn't respecting DNS failover for load balancing in a timely manner, so I started investigating. I'm running dnsmasq so I can look at when the app makes DNS requests. The code is currently using HttpWebRequest, and I noticed it's making DNS queries at least 10 minutes apart.
I understand part of this is because most .NET networking bits use a keepalive connection. I certainly see a higher rate of DNS queries if I force the headers to not use keepalive, but that adds network overhead so it's not a desirable solution. But I didn't initially see a clear way to control how HttpWebRequest makes DNS queries.
It looked promising that I could get its ServicePoint property and set the ConnectionLeaseTimeout on that. Unfortunately, that throws NotImplementedException in Xamarin so it's not going to be part of any solution.
I thought that perhaps HttpClient would be more configurable. I see a lot of discussion about how to use it properly, and that if you do it that way you need to set ServicePointManager.DnsRefreshTimeout to a smaller value for use cases where you want to expect DNS to update frequently. But this is usually done in conjunction with getting the ServicePoint for the deisred endpoint and also modifying ConnectionLeaseTimeout, which isn't possible.
I've been testing with a very simple app that reuses an HttpClient and makes the same request any time I push a button. Slap this ViewModel behind some Xaml with a button:
using System;
using Xamarin.Forms;
using System.Net.Http;
using System.Net;
namespace TestDns {
public class MainPageViewModel {
private const string _URL = "http://www.example.com";
private HttpClient _httpClient;
private ServicePoint _sp;
public MainPageViewModel() {
var sp = ServicePointManager.FindServicePoint(new Uri(_URL));
_sp = sp;
//_sp.ConnectionLeaseTimeout = 100; // throws NIE
_httpClient = new HttpClient();
ServicePointManager.DnsRefreshTimeout = 100;
}
public Command WhenButtonIsClicked {
get {
return new Command(() => SendRequest());
}
}
private async void SendRequest() {
Console.WriteLine($"{_sp.CurrentConnections}");
var url = "http://www.example.com";
var response = await _httpClient.GetAsync(url);
Console.WriteLine($"{response.Content}");
}
}
}
I didn't expect ConnectionLeaseTimeout to throw. I expected this code to only cache DNS requests for 100ms, I was going to choose a more reasonable timeframe like 2-3 minutes in more production-oriented tests. But since I can't get this simple example to function like I want, it seems moot to increase the delays.
Surely someone else has had this problem in a Xamarin app? Is my only solution going to be to look deeper and try to use native networking constructs?
If you're doing this on Android, DNS is cached for 10 minutes, and I don't believe you have any access to the expiration/refresh time from inside of your app. There are a number of ways to force a refresh but they all involve user actions like going into Network Connections and flipping from Static to DHCP and back, etc.
The only way I can think of to be sure of getting a fresh DNS lookup from inside your app is to have 10+ minutes worth of DNS entries that all alias to your server, and cycle your app through them, so every time you ask for a DNS lookup, it's a new name and not in the cache.
For example, look for 1.server.example.com 2.server.example.com, etc. Each new name will force a new lookup and won't be pulled from the cache because it's not there.
It seems that Java has decided the solution to "some people implement DNS improperly and ignore TTL" is to make the problem worse by ensuring devices that use Java implement DNS improperly. There is a single TTL used for all DNS entries in the cache. There's some philosophical debate and what led me to the answer in this question which I adapted for the answer.
In terms of Xamarin projects, add this somewhere (I chose early in MainActivity):
Java.Security.Security.SetProperty("networkaddress.cache.ttl", "<integer seconds>");
Replace "<integer seconds>" with your desired TTL for all DNS entries. Be aware lower values might mean you make more DNS queries than you used to, if you're seriously trying to save networking bytes this could be an issue.
I'm leaving Terry Carmen's answer selected as "the answer".
We are building an MVC application, where there is huge static data to be loaded when the user first time logs in.
Luckily most of the data that has to be loaded during login is all master data and doesn't change for anyusers
But since the size of the master data is huge, we felt it is best to implement caching server side as the browser might not be able to hold the data
I have read an codeproject post on OutputCache by an Microsoft MVP, he clearly explained what cache does and what are the things to keep in mind while using caching.
So i implemented all that he suggested in my controller by just adding the line
[OutputCache(Duration = 10, VaryByParam = "none",
Location=OutputCacheLocation, NoStore=true)]
above my ActionMethod.
But i could not debug whether the data is loading from cache or there is another server hit happening.
So my first question is how do i debug whether Output cache is working or not?
And then, in our previous MVC applications we used httpcontext.current.cache which worked absolutely fine.
So, here is my second question, which is why should i prefer OuputCache over httpcontext.current.cache and why not vice versa?
What difference do they offer to caching an application?
EDIT:1
This is the method in my login view controller,
public ActionResult GetRegions(string Ids)
{
objRegionsResult = GetRegionsList();
if (!string.IsNullOrEmpty(Ids))
objRegionsResult = objRegionsResult.Where(x => Ids.Split(',').Contains(x.Type.ToString())).ToList();
return Json(objRegionsResult, JsonRequestBehavior.AllowGet);
}
private List<MORegionMaster> GetRegionsList()
{
RequestUri = "Home/GetRegions";
HttpResponseMessage response = ConnectAPI(RequestUri);
if (response.IsSuccessStatusCode)
{
objRegionsResult = response.Content.ReadAsAsync<List<MORegionMaster>>().Result;
}
}
return objRegionsResult;
}
So the above method is where i hit the api controller, which inturn hits the businesslogic class and subsequently the database and returns the datatable.
We use OutputCache when we want to cache the result of an action (not static files but cache the business logic result). We use this when we want to serve the data for all users for a particular duration.
We use httpcontext.current.cache when we want to cache some data that can be used multiple times within the same request like caching "Current logged in user object" to avoid multiple db hits.
Also, lifetime of Output Cache is not limited to current http request only but the lifetime of httpcontext.current.cache is up to current http request only.
I have the following controller:
public class PingController : ApiController
{
[Route("api/ping")]
[HttpGet]
public IHttpActionResult Ping()
{
var log = HostLogger.Get(typeof(PingController));
log.Info("Ping called.");
return Ok("Ping succeeded # " + DateTime.UtcNow);
}
[Route("api/long-ping")]
[HttpGet]
public async Task<IHttpActionResult> LongPing(CancellationToken cancelToken)
{
await Task.Delay(30 * 1000);
return Ok("Ping succeeded # " + DateTime.UtcNow);
}
}
If I execute LongPing, followed by Ping in different browser tabs, the Ping will execute and return before LongPing does -- which is exactly what I'm looking for. The problem is when I execute two LongPing calls the second one takes around 60s to complete (not 30 seconds). Chrome reports the second call has a latency of 58s (60s minus the time it took me to start the second request). It seems to me that both LongPing calls should execute in around 30s if I had this working correctly.
I also should mention that I'm hosting this in an OWIN hosting environment, not IIS. But I didn't think that made any difference but maybe someone will prove me wrong.
How do I make LongPing behave truly like an async request?
It's quite likely that your session state is causing your problems. There's a long-winded explanation for this behaviour, but the short version is that a particular user session can only do one request at a time because the session state locks to ensure consistent state. If you want to speed this up, disable your cookies to test the session state hypothesis (you'll get 1 session state per request that way), or disable session state in the application. Your code is otherwise a-ok async wise.
It turns out this is Chrome's behavior when calling the same URL. I always forget this when testing with Chrome. Normally I test with Fiddler, but this VM doesn't have Fiddler.
See this SO Q&A:
Chrome treating smart url and causing concurrent requests pend for each other
When the user makes selection and clicks a button, I call to:
public ActionResult Storage(String data)
{
Session["Stuff"] = data;
return null;
}
Then, I redirect them to another page where the data is accessed by
#Session["Stuff"]
This far, I'm happy. What I do next is that upon a click on a button on the new page, I perform a call to:
public ActionResult Pdfy()
{
Client client = new Client();
byte[] pdf = client.GetPdf("http://localhost:1234/Controller/SecondPage");
client.Close();
return File(pdf, "application/pdf", "File.pdf");
}
Please note that the PDFization itself works perfectly well. The problem is that when I access the second page a second time (it's beeing seen by the user and looks great both in original and on reload), it turns out that Session["Stuff"] suddenly is null!
Have I started a new session by the recall?
How do I persistently retain data stored in Session["Stuff"] before?
If you're simply storing string data (as would be indicated by your method signature) in an MVC application, don't.
It's far easier to pass the data as a query parameter to each method that needs it. It's far easier to manage and doesn't rely on Session sticky-ness.
To generate the appropriate links, you can pass data to your views and use Html.ActionLink to generate your links with the appropriate parameter data.
Here's several reasons why the session variable could return null:
null is passed into Storage
Some other code sets Session["Stuff"] to null
The session times out
Something calls Session.Clear() (or Session.Abandon())
The underlying AppPool is restarted on the server
Your web server is farmed and session state is not distributed properly
The first two can be discovered by debugging.
How the ilusion of causing site to change content from server side is done? Let the example be gmail chat or chat on facebook. Or even new message sign on stack overflow.
Is it done by http://en.wikipedia.org/wiki/Comet_(programming)) ?
Thanks for help
That sort of things is usually done with a block of JavaScript firing again and again according to a timer. It will check the state of the things in the database and adjust something in the markup. For instance, change the CSS class of some element to introduce a different color or a bold font, replace a picture with the one done in a brighter color etc. Quite simple really. No magic involved.
The client side has to 'poll' the server for changes. i.e. a timer based Ajax call that checks the server every 15 seconds for new data, and takes action based on the result.
very loose example:
setTimeout('checkMessages()',15000);
function checkMessages() {
//using jquery
$.get( .......... , function (data) { if (data == "newmsg") { $('#newmsgind').blink(); });
setTimeout('checkMessages()',15000);
}
Web browsers don't really maintain a connection to the server. You pull a page and that's it. Ajax allows continuous asynchronous communication, but it's always the client that initiates.
If you really don't like the javascript approach, you can write a Java applet that works the way you seem to prefer, maintaining an open connection to the server. But that's a heavyweight solution to what is usually a lightweight problem.