I'm using 51 degrees on my MVC site as an adaptive approach to serving my pages. All is working well.
I have recently added output caching and I use the VaryByCustom to check whether it is mobile or desktop:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
// this is for the output cache
if (context != null)
{
switch (custom)
{
case "Mobile":
return GetMobileCustomString(context);
}
}
return base.GetVaryByCustomString(context, custom);
}
private static string GetMobileCustomString(HttpContext context)
{
if (context.Request.Browser.IsMobileDevice)
{
return "IsMobile";
}
else
{
return "IsDesktop";
}
}
However I have run into a problem that if the first mobile user to browse the site has requested the desktop version, this will be cached for all mobile users.
I need to change the GetMobileCustomString to include a check for if it is a mobile requesting a desktop site. Is there any way to do this?
Update
As a bounty has been opened on this, I thought I would offer an update:
Firstly, it was not the first load causing the desktop page to be cached as I had initially thought, so having done a lot of searching, research and testing on this, I feel the desktop page should never be cached for the mobile version (if you are on MVC 5). I have stepped through the code when doing a mobile request and when it gets to the vary by custom, it shows context.Request.Browser.IsMobileDevice as false.
Not sure what is causing the desktop site to be cached for the mobile site - perhaps it is a hangover from the bug in MVC 4. It just seems to be random (ie, one day it will be fine and then another day it will be serving the desktop site for some reason) and recycling the app pool will always fix it.
I also found that I could get the overriden browser by using:
using System.Web.Wepages;
context.Request.RequestContext.HttpContext.GetOverriddenBrowser();
But it didn't seem to be much use
It seems to me like what you are doing should work, provided you are storing the cache at the client side.
You should be using the OutputCache attribute on your controller actions in the following manner:
[OutputCache(Duration = 5, VaryByCustom = "Mobile", Location = OutputCacheLocation.Client)]
(The duration is up to you)
That being said, browser detection is based on HTTP headers so nothing is going to help you if the requesting browser is sending headers for a different agent.
The other option is to use feature detection instead.
I hope that helps.
Within the 51degrees.config there is a setting
<redirect devicesFile="" timeout="20" firstRequestOnly="true"
This firstrequestonly may be confusing your caching system so treating the first mobile device as the first request, and all other mobiles as the same session of the original mobile device. Try setting this to false and see if that helps solve your issue.
Related
I have a Windows Service that is calling a Web Page via the ShDocVw object (IE8) with a URL. It then checks the page and if it gets a certain result, it reads the data and then returns a result.
When I run this in debug and as my ordinary domain user, it all works happily. When I run it as an ordinary domain user as a Windows Service, it gives me back a completely different web page. I have checked the calling URL and the response URL from the web page and in debug or in production and they are exactly the same! Strangely, the web page being sent back in debug is different to the one being sent back in production. The one in debug gives me the information that I am looking for, but the production version (running as a Windows Service) responds with an error.
The original URL seems to be redirecting to another web page, which is why I am using ShDocVw and IE for the process (unless someone tells me otherwise). I did try using a different object, but I cannot remember what that was now.
What is really weird is that the process works perfectly for 3 different URLs in debug and in the Windows Service, but the fourth URL varies it's returned web page (but has the same URL)!
The code is something like:
InternetExplorer objIE = new InternetExplorer();
objIE.Navigate(sService, ref objEmpty, ref objEmpty, ref objEmpty, ref objEmpty);
while (objIE.Busy || (objIE.ReadyState.ToString() != "READYSTATE_COMPLETE"))
{
System.Threading.Thread.Sleep(1000);
if (i == I_TIMEOUT)
{
break;
}
i++;
}
mshtml.HTMLDocument objDocument = (mshtml.HTMLDocument)objIE.Document;
Does anyone know how to find out what the problem is or know what I might be doing wrong?
The answer to the problem was that the USER that the Windows Service was running under had never been logged on, so it did not have an IE profile. Once I logged onto the computer as the user and fire up and close IE, the Windows Service started to work and the correct request then resulted in the correct response for the previously errant request.
Thanks for your answers.
I have created an MVC 4 Internet Application project for both Mobile and Desktop devices.
Now I want to just display the Mobile site globally for all browsers.
I've been trying to use the code HttpContext.SetOverriddenBrowser(BrowserOverride.Mobile) to do this, but it doesn't seem to work correctly no matter where I put it.
Currently I can switch from the desktop site to the mobile site using ViewSwitcher but this is impractical as the desktop site isn't yet functional.
public RedirectResult SwitchView(bool mobile, string returnUrl) {
if (Request.Browser.IsMobileDevice == mobile)
HttpContext.ClearOverriddenBrowser();
else
HttpContext.SetOverriddenBrowser(mobile ? BrowserOverride.Mobile : BrowserOverride.Desktop);
return Redirect(returnUrl);
}
All of my mobile views are in VIEWNAME.Mobile.cshtml format. Any help would be greatly appreciated, thank-you.
I'm maybe a bit late to the party, but I had the same problem like the OP and didn't like Tieson's solution. So I came up with an alternative, that worked great for me.
Add the following code to your projects Global.asax.cs:
protected void Application_BeginRequest()
{
Request.RequestContext.HttpContext.SetOverriddenBrowser(BrowserOverride.Mobile);
}
This tells ASP.NET on every request, that it's a request of a mobile browser.
I suppose a different tack to try would be to manually specify the mobile views when you return the result from the controller action. View() has quite a few overloads (see http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.view%28v=vs.100%29.aspx), one of which lets you specify the view to render: return View("index.mobile", model) should work. Once the rest of the app is complete a simple Find+Replace would let you remove the "hack".
I have been working on a legacy project (although C#) and trying to solve a session problem that have been encovered for years. It hapens on IE8 and prior versions. On IE9, Google Chrome, Firefox and Safari works fine.
In other words, we have a management software that works fine on all browsers. But there is a specific page that makes tons of Ajax requests, and in some point it loses the session data.
I have checked for cookie problems with Fiddle but they are always sent and the same.
These clues make us think that the problem is within the application. But if we remember the problem occurs just in IE8 and prior versions we think the issue is probably in the browsers.
We also use a legacy Ajax library. And the problem mustn't be there as many of our aplications
use it and they doesn't have the same problem.
We are using IIS7 with State Server
I'm almost out of ideas. I hope you have some.
I got it!
Using Fiddler, I saw a very suspect request for "/". There was something requesting for the site base URL. And I remembered that the default page of this particular web application kills the session data, in other words calling the login page also means to log the user off.
After some hours of debugging and sniffing I found what was making such request.
There is a javascript function that creates some image tags. Some times those tag were created with an empty address, in other words the src property of the img tag was a string with 0 legth.
It must be an IE8 and older versions bug, as they request the website root instead of not requesting anything. Maybe it's not a bug, but this behavior is certainly unexpected.
Phew! I still can't believe I found it.
Losing session state can be result of the application error. But if you claim that this happens only on IE8 and older versions, this could not be the case...
So I would suggest you to use page ViewState instead of session state. Let me know if did the trick for you?
Here is sample how to create propety based on page viewstate, just make sure you have enabled viewstate on page level:
public string MyProperty
{
get
{
return ViewState["MyProperty"] as string;
}
set
{
ViewState["MyProperty"] = value;
}
}
I hope the question is self-describing.
I'm currently developing an asp.net website which uses a MS SqlServer database in the data layer.
And I was thinking what are my options to get a mobile version (most importantly supports BlackBerry and iPhone and hopefully every mobile device!) and when used on blackberry I want to be able to let it run at the BB's background.
I was thinking about asp.net mobile controls but the projects page seems like a dead/not-updated framework and not sure exactly if supports only windows mobiles or what!
Edit
Thank you for your questions, but they all covered my problem from only one respective .. I mean how this is going to let me use the BlackBerry Appliction options like letting my website run at the device background or sending notifications to my users!
This is mostly going to be a product of styling. Mobile websites work just like regular websites these days, except you want to use CSS and images that work well on a mobile device. You can use a product like 51 Degrees that will give you a bunch of information on what type of device is connected, so you can customize your output based on resolution or any number of other things if you so desire.
You could also try a book on mobile design, such as "Mobile Web Design" by Cameron Moll.
If you use ASP.Net MVC to create your app and create regular and mobile views. You can use jQuery Mobile to help with the mobile views too.
This question covers how to change your view based on the device type,
If you use WebForms, you can change your MasterPage depending on the browser thus giving you the ability to swap to mobile versions more easily:
protected void Page_PreInit(object sender, EventArgs e)
{
if (Request.Browser.IsMobileDevice)
MasterPageFile = "~/Mobile.Master";
}
Or use a Global.asax to redirect mobile requests completely:
void Session_Start(object sender, EventArgs e)
{
// Redirect mobile users to the mobile home page
HttpRequest httpRequest = HttpContext.Current.Request;
if (httpRequest.Browser.IsMobileDevice)
{
string path = httpRequest.Url.PathAndQuery;
bool isOnMobilePage = path.StartsWith("/Mobile/",
StringComparison.OrdinalIgnoreCase);
if (!isOnMobilePage)
{
string redirectTo = "~/Mobile/";
// Could also add special logic to redirect from certain
// recognized pages to the mobile equivalents of those
// pages (where they exist). For example,
// if (HttpContext.Current.Handler is UserRegistration)
// redirectTo = "~/Mobile/Register.aspx";
HttpContext.Current.Response.Redirect(redirectTo);
}
}
}
Either way read this article: http://www.asp.net/learn/whitepapers/add-mobile-pages-to-your-aspnet-web-forms-mvc-application
You don't really need to do anything special; Just create an alternative stylesheet that is optimized for 320px width viewport. You can serve this stylesheet through a separate stylesheet using the "media" attribute of the LINK element, or you can use CSS Media Queries within your mater stylesheet. Some relevant info:
http://googlewebmastercentral.blogspot.com/2011/02/making-websites-mobile-friendly.html
http://www.css3.info/preview/media-queries/
If you are using asp.net MVC be sure to check out
Web Application Toolkit for Mobile Web Applications
I came across a weird behavior today w/ my web application. When I navigate from a page to another, I lose one particular session variable data.
I'm able to launch the app in firefox and able to see that the session data is not lost.
I use Response.Redirect(page2, false) to redirect to another page.
Below code was used to track session variables
System.IO.StreamWriter sw = new System.IO.StreamWriter(#"c:\test.txt", true);
for (int i = 0; i < Session.Count; i++)
{
sw.WriteLine(Session.Keys[i] + " " + Session.Contents[i]);
}
sw.Close();
Can anyone help me in this? Any help is appreciated.
I was having exactly the same problem and in my case I found the cause of this behavior. It turned out to be that when I was invoking the Response.Redirect() method I was using the full url instead of just the page name. So when I was in localhost/myapp/page1.aspx I redirected to MYMACHINENAME/myapp/page2.aspx and that's why the sessions were different for each page. I corrected this in my code using only "page2.aspx" and then the final url on any browser (IE, firefox) was localhost/myapp/page2.aspx.Don't know if you're playing with the urls the way I was doing it but maybe this answer can give you a clue. Thanks and good coding
Are you developing in a web farm / web garden environment?
Try using the state server mode. Depending on how your application pool is configured and your deployments the default in-process mode can be unpredictable.
My problem was as follows :-
Problem: When we have moved the ASP.NET application to an another server (Windows Server 2008 R2) with IIS 7.5, the application cannot move session values between the pages. e.g. the session value was set in first page but it could not move to next page. In next page, value for same session variable was coming NULL.
Session values was moving to next page in case of Google Chrome and Firefox but not in Internet Explorer.
Resolution: We have created URL name with "_" (underscore) e.g. http://MySite_test.com. After removing "_", it works as required e.g. http://MySitetest.com
Other Possible Solution:
Use Response.Redirect with having second parameter as "false" to avoid execution of page and thus to avoid lose session token. You have to use URL as follows. Response.Redirect("NextPage.aspx",false)
If the application pool of the site is configured as a web farm or a web garden (by setting the maximum number of worker processes to more than one), and if you're not using the session service or SQL sessions, incoming requests will unpredictably go to one of the worker processes, and if it's not the one the session was created on, it's lost. The solutions to this problem is either not to use a web garden if you don't need the performance boost, or use one of the out of process session providers.