How to detect mobile(not tablet) requests? - asp.net-mvc

How can I detect mobile devices(but not tablets) requests in ASP.NET MVC application?

In ASP.NET, you can easily detect the mobile device request using Request.Browser.IsMobileDevice property and Request.UserAgent.
The following code checks the IsMobileDevice property and redirects to the mobile specific page:
protected void Page_Load(object sender, EventArgs e)
{
if (Request.Browser.IsMobileDevice)
{
Response.Redirec("~/default_mobile.aspx");
}
}
If you request "default.aspx" from mobile browser, it will redirect to default_mobile.aspx page
Read here where they explain in detail
Some times this may not work for some tablets
For that you have to use Request.Browser.ScreenPixelsWidth and validate against values of various screen sizes to achieve this . I think that will be the only way left to do it in the server side
If you want to trust client side javascript . There are varous scripts available to do that .
Check this Detect Mobile Browsers which may also help you .

As the other bloke said, you can use Request.Browser.IsMobileDevice
Either in your controller or in your layout page
Razor. You can do this in the layout page and it'll change depending on device e.g.
#if (Request.Browser.IsMobileDevice) {
}
Controller for an individual View e.g.
public ActionResult Index()
{
if (Request.Browser.IsMobileDevice)
return View("Index.Mobile");
else
return View();
}
An alternative is to use this API called 51Degrees.mobi. I personally haven't used it, but it looks pretty good and very complete: http://51degrees.codeplex.com/wikipage?title=MVC
Also, this has some more information on the subject of mobile detection. http://www.asp.net/whitepapers/add-mobile-pages-to-your-aspnet-web-forms-mvc-application

Related

Owin AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie) not working for live id? workaround

I created a default MVC application using VS 2013 and using Owin authentication with live id as my external login provider, but sadly it doesn't work the way it should when it comes to signing out user from live id. I checked many solutions like using
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
instead of
AuthenticationManager.SignOut();
but nothing works at all. I stumbled across this part where I am redirecting user to live id specific URL in my LogOff action method.
(I just have live id authentication as my external login provider and no other, but if you are going with this approach with multiple login providers then you need to check if it is live id provider before redirecting)
// POST: /Account/LogOff
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
return Redirect("https://login.live.com/oauth20_logout.srf?client_id=[your_client_id]&scope=wl.basic&response_type=code&redirect_uri=http://www.yourdomain.com/signin-microsoft&state=");
}
But when you actually run this and hit the logoff link, it will redirect you back to your app to "http://www.yourdomain.com/signin-microsoft&lc=2057" URL which shows a blank page and doesn't redirect to your home page. Now to fix this part, I wrote below code inside Global.asax
protected void Application_BeginRequest(object sender, EventArgs e)
{
var url = Request.Url;
if(url.AbsoluteUri.Contains("signin-microsoft") && Request.QueryString["lc"] != null)
{
Response.Redirect(url.GetLeftPart(UriPartial.Authority));
}
}
I don't know if this is the only way for now.. Can anyone share if there is any better way to do this?

MVC3: Session_Start Fires twice when testing for Roles

I need to do some authentication for a web app with MVC3. The customer would like there to be a generic page to show if they do not have any of the role groups in windows AD that are allowed to use the app. I found a pretty simple way to do it, but just curious if it is a valid way or if there is something better out there.
Basically in the Session_Start in the global I am checking for User.IsInRole() and if that returns false then I do a Response.Redirect(). This question is: after it his the code in the IF statement and hits the Response.Redirect() code then it hits the session one more time before it goes to the AccessDenied page in the root of the app. Is this okay? Will it cause any issues If they are valid and does not enter the If to do the response.redirect?
//if (!User.IsInRole("test_user"))
//{
// Response.Redirect("~/AccessDenied.aspx", true);
//}
I would recommend you to write your Authorization filter for MVC3 and do this type of logic there:
public class RoleFilter: AuthorizeAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext filterContext)
{
if (!User.IsInRole("test_user"))
{
filterContext.HttpContext.Response.StatusCode = 302;
filterContext.Result = new RedirectResult("~/AcessDenied.aspx");
}
}
}
Also I wouldn't recommend you to use Response.Redirect because it aborts current thread.

Take an MVC web site offline and back online

I'm searching for a method to take a website offline with a message. I know about app_offline.htm, but I would like to do it programmatically.
Taking it offline is easy. I can generate app-offline.htm on root, but when I want web site to be back online it is not possible programmatically, because all services are down including images.
My project uses MVC (C#). For now I'm storing the site status in an SQL server database in a bit field.
I find a method to doing it with global.asax but I would like to see other solutions...
void Application_BeginRequest(object sender, EventArgs e)
{
if ((bool) Application["SiteOpenService"] == false)
{
if (!Request.IsLocal)
{
HttpContext.Current.RewritePath("/Site_Maintenance.htm");
}
}
}
ref:
http://www.codeproject.com/Tips/219637/Put-the-website-in-Maintanance-Mode-Under-Construc

Struts2 how to create multiple views for mobile and desktop

I am creating a site which will be accessible via mobile and desktop devices. So I want to create 2 views of my application. My action code and everything else in the backend (manageers, DAOs) is same. Just JSP changes for both.
How I can do this via Struts 2?
In struts there are many way to obtain the same thing.
In this case, the one I prefer is:
You could write an interceptor that changes the return code based on the user-agent of
the client, such that there would be versions for PC and mobile of each jsp.
In your configuration you need to have all the result codes for all jsp (or you could simply define the result through the wildcard mapping).
For example: change the result code from "success" to "mobile_success". In case you want map both results in the same jsp you can map, as I said before, in this way
<result name="*success">
not sure whether there is library for automating such task for struts 2. but if there is, using such libraries might be better
anyway, here is the theory. every browser has its own "signature" written in the request header, called "User-Agent". different browser (supposedly) has different user agent. for example, my firefox user agent is as following:
Mozilla/5.0 (Windows NT 6.0; rv:5.0) Gecko/20100101 Firefox/5.0 FirePHP/0.5
basically, by detecting the user agent, you can know what browser is used to access your site. the list of mobile browser user agents can be found in http://www.zytrax.com/tech/web/mobile_ids.html
if i'm not wrong, you can retrieve the user agent in server by httpServletRequest.getHeader("User-Agent"); (correct me if i'm wrong)
you can then create an interceptor which will decide whether a client is from mobile or from desktop. that interceptor can return different result for different client type. for example, if the client is desktop, you can return "successDesktop" and if the client is mobile, you can return "successMobile".
well, hopefully someone else can come up with (far) easier solution
I am currently trying to solve this very same problem. A framework would be nice, and I'm all ears if anyone has tested and approved one. That said, I can't find anything mature enough for me to be justify moving from Struts for the mobile view.
My best solution currently is to create actions for each of the parts of my full page which will be displayed on full browsers. Then to reuse those actions to display page segments on the mobile side.
I found trying to make one page look right for a desktop browser and a mobile browser simultaneously was not a sustainable approach.
jQuery mobile looks like a very promising library for styling the elements retrieved by struts.
So while it is surely possible to cram both versions of the site into one action I think taking the time to create small reusable actions that result in jsp snippits will pay off as your app scales.
Here are some possibilities for the near future:
(I can't add these as links as I don't have enough reputation...you'll have to add the 'http://www.')
Struts2 jQuery Mobile Project homepage: http://code.google.com/p/struts2-jquery/
Struts2 jQuery Mobile project: code.google.com/p/struts2-jquery/downloads/detail?name=struts2-jquery-mobile-showcase-3.1.1.war
an example of struts2 jQuery Mobile: weinfreund.de/struts2-jquery-mobile-showcase/index.action
#fajrian - using 'user agent' to determine a browser type could become a real pain as more and more mobile and desktop browsers are released. A better approach would be to determine whether to display a mobile version or full version based on the window's dimensions. A perfect example.
edit - Check out CSS3 media queries.
As Maurizio said you could use interceptors. Here is what I found.... http://www.benmccann.com/blog/struts-2-tutorial-interceptors/
This works for me and should basically get round the problem. You do need to know at least part of the user agent strings though:
public class MobileInterceptor extends AbstractInterceptor {
private static final String RESULT_CODE_SUFFIX_MOBILE = "mobile";
private static final String REQUEST_HEADER_ACCEPT = "Accept";
private static final String[] MOBILE_BROWSER_UAS = {"iPhone OS","Android","BlackBerry","Windows Phone"};
public String intercept(ActionInvocation invocation) throws Exception {
invocation.addPreResultListener(new PreResultListener() {
public void beforeResult(ActionInvocation invocation, String resultCode) {
// check if a wireless version of the page exists
// by looking for a wireless action mapping in the struts.xml
Map results = invocation.getProxy().getConfig().getResults();
System.out.println("Results:"+results.toString());
if(!results.containsKey(resultCode + RESULT_CODE_SUFFIX_MOBILE)) {
return;
}
// send to mobile version if mobile browser is used
final String acceptHeader = ServletActionContext.getRequest().getHeader(REQUEST_HEADER_ACCEPT);
//Get User Agent String
String userAgent = ServletActionContext.getRequest().getHeader("User-Agent");
System.out.println("UA: "+userAgent);
//Boolean to indicate whether to show mobile version
boolean showMobileVersion = false;
//Run through each entry in the list of browsers
for(String ua : MOBILE_BROWSER_UAS){
if(userAgent.toLowerCase().matches(".*"+ua.toLowerCase()+".*")){
showMobileVersion = true;
}
}
if(showMobileVersion) {
invocation.setResultCode(resultCode + RESULT_CODE_SUFFIX_MOBILE);
}
}
});
return invocation.invoke();
}

Implementing a WAP site using ASP.NET-MVC

We plan on implementing a WAP site using ASP.NET-MVC.
Has anyone any experiance of this? Are there any Gotchas?
We will also be implementing a "standard" web site for browsers. Would it be possible to have a single set of Models and Controllers, and just have seperate views for each site?
It is possible to have for the most part a single set of models and controllers.
The way to do it will be via implementing the following Theming/Templating engine.
[Theming Support][1]
I piggy backed my solution on top of a Theming/Templating engine.
The major deviation from the article source is in the Global.asax.cs file where you need to add the following lines of code:
protected void Application_BeginRequest(Object Sender, EventArgs e)
{
SetTheme();
}
//this will set the responses Content Type to xhtml and is necessary as C# sends the WML response header
protected void Application_PreSendRequestHeaders(Object Sender, EventArgs e)
{
if (this.Context.Items["themeName"].ToString() == "xhtml")
{
this.Context.Response.ContentType = "application/vnd.wap.xhtml+xml";
}
}
private void SetTheme()
{
//set the content type for the ViewEngine to utilize.
HttpContext context = this.Context;
MobileCapabilities currentCapabilities = (MobileCapabilities)context.Request.Browser;
String prefMime = currentCapabilities.PreferredRenderingMime;
string accept = context.Request.ServerVariables["HTTP_ACCEPT"];
context.Items.Remove("theme");
context.Items.Remove("themeName");
if (accept.Contains("application/vnd.wap.xhtml+xml"))
{
context.Items.Add("themeName", "xhtml");
}
else if (prefMime == "text/vnd.wap.wml")
{
context.Items.Add("themeName", "WAP");
}
if (!context.Items.Contains("themeName"))
{
context.Items.Add("themeName", "Default");
}
}
I know I had to make a couple of code changes to make it MVC 1 compatible, but I can't remember the exact changes.
The other major problem I had was debugging the output. For this I used firefox with an extension ([User Agent Switcher][2]) that I've changed to add Accept Types to it.
For WAP2/XHTML1.2 the Accept Types are: text/html,application/vnd.wap.xhtml+xml,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Obviously you need your masterpage and content pages to adhere to WML or XHTML1.2
[1]: http://frugalcoder.us/post/2008/11/13/ASPNet-MVC-Theming.aspx Theming Support
[2]: http://chrispederick.com/work/user-agent-switcher/ User Agent Switcher

Resources