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".
Related
Thanks for your time , I have a simple question, in an asp.net MVC application, inside controllers is it possible that along with some methods returning View (ActionMethods) other could act as (or return) Json as a Web API (could be called from external apps).
Just trying to do a proper separations, hence trying to understand.
Thanks much.
You can make an action function like an API. Try something like the this.
// Controller/Action
[HttpGet]
public ActionResult IAmSpecial()
{
if (Request.IsAjaxRequest())
{
string[] objects = new string[] { "Foo", "Bar" };
return Json(objects);
}
return View();
}
This will return the IAmSpecial view if you browse to {domain}/{Controller}/IAmSpecial while it will return a JSON result if you use an AJAX Http Get request on the same url.
while it is possible to have controller methods which return Json data only, there are a number of considerations when you want to expose that data outside of the UI app.
Since you have an MVC app, I expect you have users and a way to login. Your controllers would more than likely be secured in some way, which works for the internal users of the application. Now you want to add one method which effectively becomes an API, available outside of the application and calls to it will have to be authenticated somehow.
What I would suggest is to split this up. You can create a separate project, which is a WebAPI one, in the same solution. The code which prepares the data can live in a class library you can then reference in both your MVC and WebAPI projects.
Your MVC app can call it and then return a view with that data, the WebAPI calls it and simply returns the data. You can now decide on a way of securing your API, maybe using Identity Server or some other way and you can keep adding things to it, without affecting the UI layer.
Your second option is to make the MVC app use the API when it needs to retrieve data, so both your public clients and UI use the same thing.
Whichever option you use, the idea is to not duplicate anything and at the same time provide the security layers you need.
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.
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 am working in an environment with many teams who are responsible for specific content on pages. Each team is sharing specific information (common class libraries, and master pages) that each are going deliver different types of content.
Is it possible for an MVC application to do something similar to RenderPartial and pass a model to another MVC application Controller/Action to return content?
So the code for this might look like:
(http://www.mydomain.com/Home/Index)
<% Html.RenderAction("ads.mydomain.com", "Home", "Index", AdModel) %>
Maybe this is not a good idea as another thread has to spin up to server a partial view?
No, RenderPartial/RenerAction can only load views that it can access via reflection, not via HTTP requests to external resources.
If the MVC app for 'ads.mydomain.com' is available to you at compile them then you can utilise its resources via Areas, however it won't pickup the changes if they release a new version to the 'ads.mydomain.com' website without you getting their latest assembly and re-compiling and deploying your app as well.
You can do similar stuff with AJAX where you can load a fragment from another site, however it wouldn't be done server side, and would require the client to have javascript enabled. Also the model would need to be converted to JSON and posted to the request, so its a bit of a hacky solution.
You could write an extension method (lets call it Html.RenderRemote) which does all the work for you of creating an http connection to the target and requests the URL. You'd have to serialize the model and send it as part of the request.
public static string RenderRemote(this HtmlHelper, string url, object model)
{
// send request to 'url' with serialized model as data
// get response stream and convert to string
// return it
}
You could use it as :
<%= Html.RenderRemote('http://ads.mydomain.com', Model');
You wouldn't be able to take advantage of the routes on the remote domain, so you'd have to construct the literal URL yourself, which means if they change your routing rules your URL won't work anymore.
In principal yes, though your question is a little vague.
Have a look at "portable areas" within MvcContrib on codeplex. This technique allows separate teams to develop separate MVC apps that would then be orchestrated by a central application.
I am working on eCommerce app Using Asp.net 3.5 MVC.
On my Cart View I have checkout button that redirect to Checkout action on the same controller:
<%= Html.ActionLink("CheckOut", "CheckOut") %>
My controller looks like this:
[RequireSsl(Redirect=true)]
public ActionResult CheckOut()
{
return View();
}
But when I click on checkout the URL seems to be correct: (see update) https://localhost/Cart/CheckOut but I get following error:
Data Transfer Interrupted
The connection to localhost was interrupted while the page was loading.
The browser connected successfully, but the connection was interrupted while transferring information. Please try again.
Any idea what I am doing wrong?
UPD: Actually after redirection the port number is gone. (I am using ASP.Net development server). But even typing in address box correct url produce the same error
Is the site setup in IIS? If not, that could be the issue. I do not believe the Visual Studio Debugger supports SSL.