Pages

martedì 7 maggio 2013

MVC 4 and different views for mobile devices

I've just discovered a really interesting feature of ASP.NET MVC 4 that will help web developers to create websites that displays in a good way on all devices.

The main idea is to create different version of the same view: the standard one for desktop and another one optimized for smartphones and tablets. It's even possible to create additional versions of the same view for a specific User-Agent.

Doing this is very easy. Let's start with the most basic example: creating two different layouts for desktop and mobile version.

All we need to do is to create a copy of the layout (in a standard project you can find it in the path "Views\Shared\_Layout.cshtml"), rename it "_Layout.Mobile.cshtml" and apply the changes on that particular file.

with this naming convention MVC will AUTOMATICALLY choose the file"_Layout.Mobile.cshtml" to render the page only in case of mobile device,otherwise it will choose the classic "_Layout.cshtml"

you can use this naming convention not only for Layouts but for ALL the Views, including Partials.

".Mobile" is the suffix provided by default but we can create additional ones to render the same view in a different way for a specific browser or device.

To add a suffix we need to change the "Global.asax" file adding this instruction to the method "Application_Start":


DisplayModeProvider.Instance.Modes.Insert(0, 
//indicate here the new suffix
new DefaultDisplayMode("iPhone")
{
 //indicate here the condition that need to be true
 //to pick up the views with the suffix
    ContextCondition = (context => context.GetOverriddenUserAgent().Contains("iPhone"))
});

Using this instruction we will be able to create an additional copy of the layout named "_Layout.iPhone.cshtml" that will work ONLY on iPhones.

mercoledì 27 marzo 2013

Vanity URL on Asp.Net MVC

I think the title is clear enough to understand the subject of this post :).

How to implement Vanity URL on ASP.NET MVC!

(Surprised, huh?)

The type of vanityURL implemented is that one used by twitter and facebook, something like:

www.yourwebsite.com/mazzimo

will show the profile of the user "mazzimo"

www.yourwebsite.com/mazzimo/messagges

will show mazzimo's messages

...and so on. Vanity URL's are awesome, but not so easy to manage: the vanity URLs must not override the existing urls.

This is our example: This is the controller "UsersController" that has inside all the "pages" about the user:


    public class UsersController : Controller
    {
        public ActionResult Index(string name)
        {

        }

        public ActionResult Messages(string name)
        {

        }

    }

Now let's look inside the "App_Start/RouteConfig.cs" file. It will look like this:


        public static void RegisterRoutes(RouteCollection routes)
        {
            //Default route
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );

        }

This function initializes the routing rules that allows MVC to call the right controller depending on the incoming url. The default settings is "{controller_class}/{method_name}/{id_parameter}".

leaving this default setting as it is, to reach the methods on our example controller for the user "mazzimo" we'll need to call the urls "www.yourwebsite.com/Users?name=mazzimo" and "www.yourwebsite.com/Users/Messages/?name=mazzimo"...not really pretty, isn't it?

To let the Urls working as we want we need to follow 3 steps:

  • Change the default rule to let it be ignored in case no controller matches with that one indicated on the url;
  • Add another rule that will call the "UsersController" class taking the first part of the RawUrl as the "name" parameter (this will be placed after the default rule, so it will be executed only if the default rule is ignored);
  • (Not Mandatory) Change this new rule to let it be ignored if there is no user that matches that particular username;

Step 1: Change the default rule

We need to call a different overload of the "MapRoute" function that uses the "costraints", objects that allows us to put additional checks on the values passed through the url. We'll use the costraint to check if the controller name indicated in the url actually exists. Usually we can indicate a regular expression as costraint but in this case we will create a custom class: This class must implement the interface "IRouteConstraint":

    public class ControllerConstraint : IRouteConstraint
    {
        static List<string> ControllerNames = GetControllerNames();

        private static List<string> GetControllerNames()
        {
            List<string> result = new List<string>();
            foreach(Type t in System.Reflection.Assembly.GetExecutingAssembly().GetTypes())
            {
                if( typeof(IController).IsAssignableFrom(t) && t.Name.EndsWith("Controller"))
                {
                    result.Add(t.Name.Substring(0, t.Name.Length - 10).ToLower());
                }
            }
            return result;
        }

        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            return ControllerNames.Contains(values[parameterName].ToString().ToLower());
        }
    }
We will pass an instance of this class when we call the "MapRoute" method inside the "RouteConfig.cs" file:
            //Default route
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
                //add this line
                constraints: new { controller = new ControllerConstraint() }
            );

Step 2: add the "vanity URL" rule

We need to call the "MapRoute" method again but AFTER the default rule:


        public static void RegisterRoutes(RouteCollection routes)
        {
            //Default route
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
                constraints: new { controller = new ControllerConstraint() }
            );

            //Additional route
            routes.MapRoute(
                name: "VanityUrl",
                url: "{name}/{action}/{id}",
                defaults: new { controller = typeof(UsersController).Name.Replace("Controller", ""), action = "Index", id = UrlParameter.Optional }
            );

Now all already works: request will be routed to our controller "Users" only if the default rule is ignored.

Step 3: Username check

Want to be more precise? all you need to do is changing the second rule adding another class as costraint.

Is pretty much similar from what we have seen before for the controllers, the only difference is that instead of taking the name of the controllers through reflection, we will make a query to check if the input value matches with an actual username.


    public class UserNameConstraint : IRouteConstraint
    {

        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            //do the query
            //if values[parameterName].ToString().ToLower() matches an username
                //return True
            //else
                //return False
        }
    }

The second rule will look like this:


            //Additional route
            routes.MapRoute(
                name: "VanityUrl",
                url: "{name}/{action}/{id}",
                defaults: new { controller = typeof(UsersController).Name.Replace("Controller", ""), action = "Index", id = UrlParameter.Optional }
                constraints: new { name = new UserNameConstraint() }
            );

giovedì 7 marzo 2013

How to add a "Clear" button (or whatever you want) to jQuery UI's datepicker.

In a perfect world everybody would have an IQ at least equal than a sea sponge. Sadly, is not like this and we have to see a world where people still votes for Berlusconi and people that tries to insert dates haphazardly in our Web Application. Unfortunately we have no hope for the first problem, but for the second God gave us a powerful tool to face them: JQuery UI e it's datepicker.

This tool is useful against the dangerous criminals that enjoys putting "31/Feb/2040" as birth date, but has a little flaw: there's no "Clear" feature.

After seconds and seconds of meditation, i decided to take the screwdriver and put the hands on the jquery UI code to let it work as I wish. all it takes it's two simple steps and less that 100 chars of code:

the final result.
  • Add the functionality to the datepicker's handlers. In other words, exists a function called "_attachHandlers" that creates every command that will be called through the buttons placed inside the datepicker. All we gotta do is adding the indicated lines of code inside this function.

     _attachHandlers: function(inst) {
      var stepMonths = this._get(inst, "stepMonths"),
       id = "#" + inst.id.replace( /\\\\/g, "\\" );
      inst.dpDiv.find("[data-handler]").map(function () {
       var handler = {
        prev: function () {
         window["DP_jQuery_" + dpuuid].datepicker._adjustDate(id, -stepMonths, "M");
        },
        next: function () {
         window["DP_jQuery_" + dpuuid].datepicker._adjustDate(id, +stepMonths, "M");
        },
        hide: function () {
         window["DP_jQuery_" + dpuuid].datepicker._hideDatepicker();
        },
        today: function () {
         window["DP_jQuery_" + dpuuid].datepicker._gotoToday(id);
        },
        // ******** THIS IS THE FUNCTIONALITY ADDED **********
        clear: function () {
            window["DP_jQuery_" + dpuuid].datepicker._clearDate(id); 
        },
        // ********************************************************************    
        selectDay: function () {
         window["DP_jQuery_" + dpuuid].datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
         return false;
        },
        selectMonth: function () {
         window["DP_jQuery_" + dpuuid].datepicker._selectMonthYear(id, this, "M");
         return false;
        },
        selectYear: function () {
         window["DP_jQuery_" + dpuuid].datepicker._selectMonthYear(id, this, "Y");
         return false;
        }
       };
       $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
      });
     }
    
    
    

    The "clear" function is very simple: it just calls the _clearDate function from the datepicker to clear the value.

  • Add the button and link it to the brand new functionality: to do this we need to modify another function called "_generateHTML" to add to the button bar the html representing the button. Two attributes needs to be added to the button to let it link to the functionality just created above: the first is "data-handler" and it represents the name of the function to call ("clear" in our case) and "data-event" that represents the event of the HTML element that fires that functionality (in our case a boring but effective "click"). This is translated to the following code

      //********** old code
      buttonPanel = (showButtonPanel) ? "
    " + (isRTL ? controls : "") + (this._isInRange(inst, gotoDate) ? "" : "") //********** ADD THIS LINE + "" //****************** + (isRTL ? "" : controls) + "
    " : "";

    That's it. It doesn't take to much to achieve that. My example was limited to the "clear" function, but the same proceedings can be used to add new functionalities such as "copy value" functions or other stuff.

venerdì 18 gennaio 2013

Add historical search suggestions on your Windows 8 app

Today I will talk to you about how to add search suggestions inside a Windows 8 store app: I will NOT talk about how to integrate searching feature because there are loads and loads of article about that (msdn is the first link that comes into my mind)

In this case I will fill the suggestions with the previous search by the user, but this example can be easily adapted to use different sources like REST services,telepathy or extra-terrestrial data teletransport.

To get this done we'll use "ApplicationData.Current.LocalSettings" to store locally every search query made by the user. The class above will help us to encapsulate the logic:

    public class SuggestionsHelper
    {
        internal const int SearchPaneMaxSuggestions = 5;
        public static string[] SuggestionsList
        {
            get
            {
                if (ApplicationData.Current.LocalSettings.Values.ContainsKey("Suggestions"))
                {
                    return ApplicationData.Current.LocalSettings.Values["Suggestions"] as string[];
                }
                else
                {
                    string[] result = new string[] { "" };
                    ApplicationData.Current.LocalSettings.Values["Suggestions"] = result;
                    return result;
                }
            }
            set
            {
                ApplicationData.Current.LocalSettings.Values["Suggestions"] = value;
            }
        }

        public static void OnSearchPaneSuggestionsRequested(SearchPane sender, SearchPaneSuggestionsRequestedEventArgs e)
        {
            var queryText = e.QueryText;
            if (!string.IsNullOrEmpty(queryText))
            {
                var request = e.Request;
                foreach (string suggestion in SuggestionsList)
                {
                    // if we find a perfect match add the suggestions and break the cycle
                    if (suggestion.CompareTo(queryText) == 0)
                    {
                        if (request != null && request.SearchSuggestionCollection != null)
                        {
                            request.SearchSuggestionCollection.AppendQuerySuggestion(suggestion);
                            break;
                        }
                    }
                    else  // else if we find a partial match we'll add to the suggestions
                        if (suggestion.StartsWith(queryText, StringComparison.CurrentCultureIgnoreCase))
                        {                    request.SearchSuggestionCollection.AppendQuerySuggestion(suggestion);
                        }

                    // break the cycle if we have reached the maximum size
                    if (request.SearchSuggestionCollection.Size >= SearchPaneMaxSuggestions)
                    {
                        break;
                    }
                }
            }
        }

        public static void addItemToSuggestionsList(string item)
        {
            if (!SuggestionsList.Contains(item))
            {
                string[] result = SuggestionsList;
                Array.Resize(ref result, result.Length + 1);
                result.SetValue(item, result.Length - 1);
                SuggestionsList = result;
            }
        }

    }

As we can see the class contains a method called "addItemToSuggestionsList" that adds the suggestion inside an array of Strings stored through the LocalSettings of the application (encapsulated by the property "SuggestionsList") and a method "OnSearchPaneSuggestionsRequested" that creates the actual list of suggestions inside the SearchPanel when is requested Using the instance of the class "SearchPaneSuggestionsRequestedEventArgs" provided by the "SearchPaneSuggestionsRequested" Event Handler. This method have to be binded to the related event inside the method "OnLaunched" available inside the App.xaml.cs file using this instruction:

            SearchPane.GetForCurrentView().SuggestionsRequested +=
                new TypedEventHandler<SearchPane, SearchPaneSuggestionsRequestedEventArgs>
                    (SuggestionsHelper.OnSearchPaneSuggestionsRequested);

The last step is to fill the array everytime the user makes a search with the query string. To do this all we need to do is call the "addItemToSuggestionsList" function inside the "LoadState" method of the Search Page of your application:

protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
        var queryText = navigationParameter as String;
        SuggestionsHelper.addItemToSuggestionsList(queryText);
}

That's pretty much it!

This is a basic example but many things can be added, for example by adding a function to flush the history or by adding a maximum limit of stored suggestions but for a default usage this version works pretty good.

mercoledì 9 gennaio 2013

The Pinterest Url Sorcery: How Pinterest changes the url with just an AJAX call.

Before starting i need to tell you first: I do not have a Pinterest account and I'm not looking forward to create one in the future.

A reason why I'll never use Pinterest.

Despite that the Pinterest's homepage caught my attention:

There's a loads and loads of "pinned" (what a horrible verb) articles. When someone cliks on one of them, a popup comes out with the details of the article loaded by AJAX. The sorcery is the fact that in the same time the URL CHANGES AS WELL: that's really cool in a SEO prospective. In top of that, if you try to copy and paste the changed url in another tab of the browser you'll get a stand-alone page of the same article.

To achieve this we need to focus on two main topics:

  • Changing the Url without a HTML call
  • Manage in the same url the Full HTML document and a JSON object (or a partial HTML response)

Let's start with the first one:

 
 
 Link First Pin
 Link Second Pin
 

the magic is done through History API of HTML 5:

"history.pushState(event.target.href, tit, event.target.href)" is the key instruction that allows us to change the url and add it into the navigation history without an actual page refresh.

The event "popstate" instead is raised at the first loading of the page and everytime we go back to the browsing history (so "popping out" the previous history pushed before by the pushState function) and allows us to recreate the same page using the value stored in "e.state" by the first argument of "pushState".

About the second topic, all you need to do is to handle GET requests in the same url in two different ways depending if the value of the HTTP header "X-Requested-With" is set to "XMLHttpRequest"or not: in the first case, you'll need to return a JSON object (or a partial HTML code), else a normal XHTML document.

This can be easily done in WebForms by making a call to the function Server.Transfer to the "partial response" or in ASP.NET MVC returning a different type of ActionResult ("Content" and "Json" for instance instead of "View")

Summarizing that:

  • in your web application, handle with the same url a normal HTML document and a JSON/partial response if the header "X-Requested-With"is set to "XMLHttpRequest"
  • handle the click of the anchor calling history.pushState to modify the url and the navigation history without an actual page refresh.
  • handle the "popstate" event to load the same informations using the "e.state" passed by the first argument of the function pushState.

For more informations about History API click here or here.

venerdì 14 dicembre 2012

Infinite Scrolling in Metro style apps/Windows Store Apps (with all this different names i'm getting confused)

I write this after two very useful days of DevCamps, where i learnt a lot of things that will be really useful in order to develop an app for Windows 8.

Most of the things that I learnt will be gradually published on the blog. the first feature that i want to talk about is an interesting way to implement the infinite scrolling inside these "Metro Style Apps"/"Store Apps"/"What-The-Hell-do-i-need-to-call-them Apps".

the "infinite scrolling" is ,for example , the way that facebook uses to load the news feed: in a first step are loaded the most recent news and when you scroll to the end of the list the list itself will grow automatically adding other news less recent...and so on.

2 things we need to do in order to achieve this in a Windows 8 app:

  • Create a class that implements "ISupportIncrementalLoading"
  • Use an instance of that class in a gridview or listview through databinding.

the interface "ISupportIncrementalLoading" got 2 things : a propery called "HasMoreItems" (that indicates if the list is completed or it needs to load other informations) and a method called "LoadMoreItemsAsync" (that executes the incremental load)


public class InfiniteScrollingCollection: ObservableCollection<YourType>, ISupportIncrementalLoading
{
    public bool HasMoreItems { get; protected set; }
    private int _page;

    public  InfiniteScrollingCollection() : base()
    {
        HasMoreItems = true;
        this._page = 0;
    }

    public async IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
    {
        return AsyncInfo.Run(async c => {
            List<YourType> data =  await LoadDataAsync(count);
            this._page++;
            foreach (var item in data) {
                Add(item);
            }

            HasMoreItems = data.Any();

            return new LoadMoreItemsResult() {
                Count = data.Count,
            };
        });
    }
    private async Task<List<YourType>> LoadDataAsync(uint count)
    {
        //load count occurrences of page "_page". 
        //i'm sorry but this step you have to do on your own.
    }

}

in this example i'm using the inheritance to the class ObservableCollection, that's because it implements all the events useful to manage the databinding in a native way.

last thing to do is to apply databinding between an instance of this class and a GridView/ListView.

venerdì 16 novembre 2012

Asynchronous code for dummies with async and await

From the latest versions of .NET framework Microsoft started to take care more about responsive interfaces that doesn't block while a long task is executed in background. This is made by writing the code in an asynchronous way letting two or more functions execute in parallel.

choosing images is my favourite thing to do in this blog.

the big problem of writing asynchronous code is that is more fiddly to write and less clear to read than a syncronous one. Microsoft is famous for let coding accessible even for monkeys: for this reason in the brand new framework 4.5 they included the modificator "async" and the operator "await".

It works like this: initially we write a function that we need to be asynchronous and add the "async" modificator

async Task<int> bullshitAsync()
{
 LongAndTediousJob();
 return 1;
}

this function needs to:

  • declare Task, Task<T> or void as return value.
  • obviously, the async modificator.
  • in case the return value is declared as Task<T>, return a value of type T.
  • (This is optional) add "Async" at the name of the function.

After that, to execute that function in asynchronous way we just need to use the await operator as follows

//in case we have Task<T> as return value
//and we need the result of the function
int result = await bullshitAsync();

//in case we have Task or void as return value
//or simply we don't give a shit about the result
await bullshitAsync();

In this case the program will wait until the end of the execution of the function WITHOUT BLOCKING THE INTERFACE. this procedure hides to the programmer the fact that the code is executed in a different thread.

That's not all...we have just seen how to avoid to block the interface, but we don't know yet how to execute code in parallel. To achieve this we need to call the function in an alternative way.

//taskBullshitAsync is an instance of class Task<int>
//that we'll need when we'll have to wait
//the end of the function bullshitAsync
Task<int> taskBullshitAsync = bullshitAsync();

//this piece of code will be executed 
//in parallel with bullshitAsync()
bullshitParallel();

//now we need the result, so we use
//the Task object with the await operator
//to wait the result of bullshitAsync()
int result = await taskBullshitAsync;

In this case the execution of bullshitAsync starts when the function is called, but the rest of the function is executed without waiting the result. the Task<int> object obtained in the first line will be used in addition to the await operator when we need the return value.

As you can see, the implementation is very easy but never forget that asynchronous programming have ITS OWN COMPLEXITY, we have to deal with data concurrency and possible scenarios of deadlocks or starvation...in this case monkey can't do too much.

Not to mention, this feature is available just from framework 4.5, so i do not recommend to use it if you want to develop something that aims to be available for previous versions of .NET.