Showing posts with label MVC. Show all posts
Showing posts with label MVC. Show all posts

Tuesday, July 2, 2013

ASP.NET MVC4 - Mobile Views

In ASP.NET MVC4 you have the ability to easily present a view directed at a mobile display without requiring the use of an add on tools.  Sure, for a good mobile experience, you may choose to implement jQueryMobile or something similar, but the fact remains that it is not required with this functionality.


Mobile Experience

A good portion of visual design for mobile can come from using simple media queries to detect the current size of the users' device and render a visual experience accordingly.   Media queries within CSS are straightforward and can handle the majority of simple user experience changes.  For instance, if you wanted to change any properties of an element based on the screen width and orientation of the users' device, you could simply create some combination of the following code:
/* #### Mobile Phones Portrait #### */
@media screen and (max-device-width: 480px) and (orientation: portrait){
  /* some CSS here */
}

/* #### Mobile Phones Landscape #### */
@media screen and (max-device-width: 640px) and (orientation: landscape){
  /* some CSS here */
}

/* #### Mobile Phones Portrait or Landscape #### */
@media screen and (max-device-width: 640px){
  /* some CSS here */
}

/* #### iPhone 4+ Portrait or Landscape #### */
@media screen and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2){
  /* some CSS here */
}

/* #### Tablets Portrait or Landscape #### */
@media screen and (min-device-width: 768px) and (max-device-width: 1024px){
  /* some CSS here */
}

/* #### Desktops #### */
@media screen and (min-width: 1024px){
  /* some CSS here */
}

That sort of thing will go a long way, but sometimes it can lead to clutter and hard to follow CSS.


Overriding a mobile view in MVC4

With MVC 4, there is a very simple mechanism that lets you override any view for mobile browsers in general.  You can also define your own parameters for a specific mobile override, giving you the ability to build specific views for specific devices or user agents.  To provide a view that overrides for any mobile device, all you have to do is copy the view to a new file and add .Mobile to the file name. For example, to create a mobile Something view, copy Views\Home\Something.cshtml to Views\Home\Something.Mobile.cshtml.  The current context will trigger which view is pulled in a run time for a given client.  Now, you have effectively created a mobile specific view that can be visually altered for an experience geared at a mobile platform.


Custom Override Views

You can create almost any kind of custom mobile view you would like by defining a context condition and inserting into the DisplayModeProvider instance. For example, the following code will create a specific display mode based on check the user agent of the current context against 'iPhone'. Then, you add it to the list of display modes within the ApplicationStart method of the global.asax:

public class MvcApplication : System.Web.HttpApplication 
 {
 protected void Application_Start()
    {
    AreaRegistration.RegisterAllAreas();

     DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("iPhone")
        {
         ContextCondition = (ctx =>
         ctx.Request.UserAgent.IndexOf("iPhone", StringComparison.OrdinalIgnoreCase) >= 0)
        });

    //Add another one specifically for some tablets too 
    DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("Tablet")
        {
         ContextCondition = (ctx =>
         ctx.Request.UserAgent.IndexOf("iPad", StringComparison.OrdinalIgnoreCase) >= 0 ||
         ctx.Request.UserAgent.IndexOf("Android", StringComparison.OrdinalIgnoreCase) >= 0 &&
         ctx.Request.UserAgent.IndexOf("Mobile", StringComparison.OrdinalIgnoreCase) <= 0
        )
        });
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
 }

As you can see, the framework gives you the ability to create as many focused views, with as much device granularity as you see fit for your application. This will help ensure good user experiences on specific devices without having to rework existing CSS or get into switching to mobile sites.

Thursday, February 28, 2013

Using MVC style controllers in ASP.NET WebForms with AJAX

I have been working on a project that is based in ASP.NET web forms recently with the knowledge that a near-future generation of this software will be created using MVC.  Always trying to find a way to share code and create leverage with solid SOA design, I decided to drive the ASP.NET application from controllers interacting with services.  By doing this, I am am assuring that not only the service layers are portable to other platforms, but that the controllers can be reused as well.  This gives us another layer of code reuse and a mechanism to limit the testing requirements on the future application.  The first step is to integrate the MVC references into your ASP application.  In order to do this, you must add the references to your project and include them in your web.config as follows.


Next, we have to make sure that our routes are created using the MVC 'magic'.  This is accomplished with a global.asax file executing the .net map paths functionality.  This is done via a single method call at the start of the application as illustrated below.
Code:
public class Global : HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        RouteTable.Routes.MapRoute(
            "Default",
            "{controller}/{action}/{id}",
            new {id = UrlParameter.Optional}
         );
    }
}

At this point, we are able to add controllers to interact with our data. The controller classes must be inherited from the Controller object. Once this class is stubbed in, you are able to simply frame in your methods to interact with the data as needed. Here is an example of a controller class.
Code:
public class TaskController : Controller    
{

    /// <summary>
    /// Completes the task.
    /// </summary>
    /// <param name="taskId">The task id.</param>
    /// <returns></returns>
    public ActionResult CompleteTask(int taskId)
    {
      
        try
        {
            MyTask data = ***service call to complete task and return updated data
            return Json(data, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            return Json("");
        }
    }

    /// <summary>
    /// Get a list of tasks.
    /// </summary>
    /// <returns></returns>
    public ActionResult TaskList()
    {
       
        try
        {   
            List<MyTask> tasks = *** Service call to get task list.

            return Json(tasks, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            return Json("");
        }
    }
}

The last step is to simply consume these controllers via AJAX calls in your client.
Code:
function loadTasks() {
    
    $.mobile.showPageLoadingMsg();
    var request = $.ajax({
        url: "/Task/TaskList",
        type: "POST",
        data: {},
        context: this
    });

    request.done(downloadDone).fail(downloadFailed).error(downloadError);
}

function downloadDone(responseData) {

    $.each(responseData, function (i, obj) {
         // do something with each task from the list by using obj.* to reference values.

    $.mobile.hidePageLoadingMsg();

}
function downloadFailed() {
    alert("Could not retrieve task data at this time.");
    $.mobile.hidePageLoadingMsg();
}

function downloadError(error) {
    $.mobile.hidePageLoadingMsg();
    console.log(error);
}

At this point, I can add controllers that represent my service interaction layer, and then simply reuse them when the application is migrated to MVC. This gives us the ability to separate the actual presentation layer from its interaction with the services and target that logic for reuse.