My article got Longest Article Award in TechNet Wiki

Last week I wrote an new technical article  Authentication using Facebook, Google and Microsoft account in WP8.0 App (MVVM) and …

this article won “Longest Article Award – Biggest article updated this week” in Technet Wiki:

Longest Article Award

with it I won the White Belt related with TechNet WIKI NINJAS :)

And was featured in C# Corner

c# corner

Authentication using Facebook, Google and Microsoft account in WP8.0 App (MVVM)

This sample show to connect one Windows Phone 8.0 app to Facebook, Google and Microsoft account. Main Features: Login/Logout and has an about page with feedback, share in social networks, review and share by email.

Download C# (19.4 MB)

Introduction

This sample show how to connect one Windows Phone 8.0 app to Facebook, Google and Microsoft account.

Main Features: Login/Logout andhas an about page with feedback, share in social networks, review and share by email.

Building the Sample

You only need Visual Studio 2012/Visual Studio 2013 and Windows 8/Windows 8.1, both the RTM version.

This sample requires the installation for Live SDK (http://msdn.microsoft.com/en-US/onedrive/dn630256). 

Description

This sample show to connect one Windows Phone 8.0 app to Facebook, Google and Microsoft account.

Main Features:

– Login/Logout (for logout i added some wourkarround to fixes the logout providers from sdks!)

– About page with feedback, share in social networks, review and share by email (not important here, but is incluided in code)

Note: This sample uses MVVM Light and Cimbalino Windows Phone Toolkit.

For this sample was used:

For each provider is needed to get the app id/client id/client secrect in their websites:

For Google go to https://console.developers.google.com/project and create a new project (Apis & auth > credentials)


For Facebook go to https://developers.facebook.com/ and create a new app.

For Live SDK go to https://account.live.com/developers/applications/index and create one or use an existing app

Before you start you should change the Constant file to add client ids / client secret / app id, without it the app fails!!

This file is inside the Resource folder.

  /// <summary> 
    /// Defines the constants strings used in the app. 
    /// </summary> 
    public class Constants 
    { 
        /// <summary> 
        /// The facebook app id. 
        /// </summary> 
        public const string FacebookAppId = "<app id>"; 
 
        /// <summary> 
        /// The google client identifier. 
        /// </summary> 
        public const string GoogleClientId = "<client id>"; 
 
        /// <summary> 
        /// The google token file name. 
        /// </summary> 
        public const string GoogleTokenFileName = "Google.Apis.Auth.OAuth2.Responses.TokenResponse-user"; 
 
        /// <summary> 
        /// The google client secret. 
        /// </summary> 
        public const string GoogleClientSecret = "<client secret>"; 
 
        /// <summary> 
        /// The microsoft client identifier. 
        /// </summary> 
        public const string MicrosoftClientId = "<client id>"; 
 
      ... 
    }

Now let’s see how to connect to each provide. For help, i created a SessionService that manage the Login and Logout using a provider value, this is nice because in LoginView i set the buttons to the same command and for each command i set the provider in commandparameter. With it the LoginView and LoginViewModel are more clear and simple. Another thing is for example if i need to connect to my server to accept the user i can do it in session manager after the authentication, without to add the code to each provider.

The classes created:

  • FacebookService has all code related with authentication with Facebook account;
  • MicrosoftService has all code related with authentication with Microsoft account;
  • GoogleService has all code related with authentication with Google account;
  • SessionService call the methods login or logout for the provide requested;

The FacebookService is:

 /// <summary> 
    /// Defines the Facebook Service. 
    /// </summary> 
    public class FacebookService : IFacebookService 
    { 
        private readonly ILogManager _logManager; 
        private readonly FacebookSessionClient _facebookSessionClient; 
 
        /// <summary> 
        /// Initializes a new instance of the <see cref="FacebookService"/> class. 
        /// </summary> 
        /// <param name="logManager"> 
        /// The log manager. 
        /// </param> 
        public FacebookService(ILogManager logManager) 
        { 
            _logManager = logManager; 
            _facebookSessionClient = new FacebookSessionClient(Constants.FacebookAppId); 
        } 
 
        /// <summary> 
        /// The login sync. 
        /// </summary> 
        /// <returns> 
        /// The <see cref="Task"/> object. 
        /// </returns> 
        public async Task<Session> LoginAsync() 
        { 
            Exception exception; 
            Session sessionToReturn = null; 
            try 
            { 
                var session = await _facebookSessionClient.LoginAsync("user_about_me,read_stream"); 
                sessionToReturn = new Session 
                { 
                    AccessToken = session.AccessToken, 
                    Id = session.FacebookId, 
                    ExpireDate = session.Expires, 
                    Provider = Constants.FacebookProvider 
                }; 
 
                return sessionToReturn; 
            } 
            catch (InvalidOperationException) 
            { 
                throw; 
            } 
            catch (Exception ex) 
            { 
                exception = ex; 
            } 
            await _logManager.LogAsync(exception); 
            return sessionToReturn; 
        } 
 
        /// <summary> 
        /// Logouts this instance. 
        /// </summary> 
        public async void Logout() 
        { 
            Exception exception = null; 
            try 
            { 
                _facebookSessionClient.Logout(); 
 
                // clean all cookies from browser, is a workarround 
                await new WebBrowser().ClearCookiesAsync(); 
            } 
            catch (Exception ex) 
            { 
                exception = ex; 
            } 
            if (exception != null) 
            { 
                await _logManager.LogAsync(exception); 
            } 
        } 
    }

Note:  In logout i added a workarround to clear all cookies in browser, if i don´t this in the first time you can login with account you want but in the next time it will use the account used in last login.

The GoogleService is:

/// <summary> 
    /// The google service. 
    /// </summary> 
    public class GoogleService : IGoogleService 
    { 
        private readonly ILogManager _logManager; 
        private readonly IStorageService _storageService; 
        private UserCredential _credential; 
        private Oauth2Service _authService; 
        private Userinfoplus _userinfoplus; 
 
        /// <summary> 
        /// Initializes a new instance of the <see cref="GoogleService" /> class. 
        /// </summary> 
        /// <param name="logManager">The log manager.</param> 
        /// <param name="storageService">The storage service.</param> 
        public GoogleService(ILogManager logManager, IStorageService storageService) 
        { 
            _logManager = logManager; 
            _storageService = storageService; 
        } 
 
        /// <summary> 
        /// The login async. 
        /// </summary> 
        /// <returns> 
        /// The <see cref="Task"/> object. 
        /// </returns> 
        public async Task<Session> LoginAsync() 
        { 
            Exception exception = null; 
            try 
            { 
                // Oauth2Service.Scope.UserinfoEmail 
                _credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets 
                { 
                    ClientId = Constants.GoogleClientId, 
                    ClientSecret = Constants.GoogleClientSecret 
                }, new[] { Oauth2Service.Scope.UserinfoProfile }, "user", CancellationToken.None); 
                 
                var session = new Session 
                { 
                    AccessToken = _credential.Token.AccessToken, 
                    Provider = Constants.GoogleProvider, 
                    ExpireDate = 
                        _credential.Token.ExpiresInSeconds != null 
                            ? new DateTime(_credential.Token.ExpiresInSeconds.Value) 
                            : DateTime.Now.AddYears(1), 
                    Id = string.Empty 
                }; 
 
                return session; 
            } 
            catch (TaskCanceledException taskCanceledException) 
            { 
                throw new InvalidOperationException("Login canceled.", taskCanceledException); 
            } 
            catch (Exception ex) 
            { 
                exception = ex; 
            } 
            await _logManager.LogAsync(exception); 
            return null; 
        } 
 
        /// <summary> 
        /// Gets the user information. 
        /// </summary> 
        /// <returns> 
        /// The user info. 
        /// </returns> 
        public async Task<Userinfoplus> GetUserInfo() 
        { 
            _authService = new Oauth2Service(new BaseClientService.Initializer() 
            { 
                HttpClientInitializer = _credential, 
                ApplicationName = AppResources.ApplicationTitle, 
            }); 
            _userinfoplus = await _authService.Userinfo.V2.Me.Get().ExecuteAsync(); 
 
            return _userinfoplus; 
        } 
 
        /// <summary> 
        /// The logout. 
        /// </summary> 
        public async void Logout() 
        { 
            await new WebBrowser().ClearCookiesAsync(); 
            if (_storageService.FileExists(Constants.GoogleTokenFileName)) 
            { 
                _storageService.DeleteFile(Constants.GoogleTokenFileName); 
            } 
        } 
    }

Note: In the logout for Google provide there isn´t a logout method, the solution is to remove all cookies and remove the file created in login operation.

 The MicrosoftService is:

 /// <summary> 
    /// The microsoft service. 
    /// </summary> 
    public class MicrosoftService : IMicrosoftService 
    { 
        private readonly ILogManager _logManager; 
        private LiveAuthClient _authClient; 
        private LiveConnectSession _liveSession; 
 
        /// <summary> 
        /// Defines the scopes the application needs. 
        /// </summary> 
        private static readonly string[] Scopes = { "wl.signin", "wl.basic", "wl.offline_access" }; 
         
        /// <summary> 
        /// Initializes a new instance of the <see cref="MicrosoftService"/> class. 
        /// </summary> 
        /// <param name="logManager"> 
        /// The log manager. 
        /// </param> 
        public MicrosoftService(ILogManager logManager) 
        { 
            _logManager = logManager; 
        } 
 
        /// <summary> 
        /// The login async. 
        /// </summary> 
        /// <returns> 
        /// The <see cref="Task"/> object. 
        /// </returns> 
        public async Task<Session> LoginAsync() 
        { 
            Exception exception = null; 
            try 
            { 
                _authClient = new LiveAuthClient(Constants.MicrosoftClientId); 
                var loginResult = await _authClient.InitializeAsync(Scopes); 
                var result = await _authClient.LoginAsync(Scopes); 
                if (result.Status == LiveConnectSessionStatus.Connected) 
                { 
                    _liveSession = loginResult.Session; 
                    var session = new Session 
                    { 
                        AccessToken = result.Session.AccessToken, 
                        ExpireDate = result.Session.Expires.DateTime, 
                        Provider = Constants.MicrosoftProvider, 
                    }; 
 
                    return session; 
                } 
            } 
            catch (LiveAuthException ex) 
            { 
                throw new InvalidOperationException("Login canceled.", ex); 
            } 
            catch (Exception e) 
            { 
                exception = e; 
            } 
 
            await _logManager.LogAsync(exception); 
            return null; 
        } 
 
        /// <summary> 
        /// The logout. 
        /// </summary> 
        public async void Logout() 
        { 
            if (_authClient == null) 
            { 
                _authClient = new LiveAuthClient(Constants.MicrosoftClientId); 
                var loginResult = await _authClient.InitializeAsync(Scopes); 
            } 
 
            _authClient.Logout(); 
        } 
    }

  The SessionService is:

/// <summary> 
    /// The service session. 
    /// </summary> 
    public class SessionService : ISessionService 
    { 
        private readonly IApplicationSettingsService _applicationSettings; 
        private readonly IFacebookService _facebookService; 
        private readonly IMicrosoftService _microsoftService; 
        private readonly IGoogleService _googleService; 
        private readonly ILogManager _logManager; 
         
        /// <summary> 
        /// Initializes a new instance of the <see cref="SessionService" /> class. 
        /// </summary> 
        /// <param name="applicationSettings">The application settings.</param> 
        /// <param name="facebookService">The facebook service.</param> 
        /// <param name="microsoftService">The microsoft service.</param> 
        /// <param name="googleService">The google service.</param> 
        /// <param name="logManager">The log manager.</param> 
        public SessionService(IApplicationSettingsService applicationSettings, 
            IFacebookService facebookService, 
            IMicrosoftService microsoftService, 
            IGoogleService googleService, ILogManager logManager) 
        { 
            _applicationSettings = applicationSettings; 
            _facebookService = facebookService; 
            _microsoftService = microsoftService; 
            _googleService = googleService; 
            _logManager = logManager; 
        } 
 
        /// <summary> 
        /// Gets the session. 
        /// </summary> 
        /// <returns>The session object.</returns> 
        public Session GetSession() 
        { 
            var expiryValue = DateTime.MinValue; 
            string expiryTicks = LoadEncryptedSettingValue("session_expiredate"); 
            if (!string.IsNullOrWhiteSpace(expiryTicks)) 
            { 
                long expiryTicksValue; 
                if (long.TryParse(expiryTicks, out expiryTicksValue)) 
                { 
                    expiryValue = new DateTime(expiryTicksValue); 
                } 
            } 
 
            var session = new Session 
            { 
                AccessToken = LoadEncryptedSettingValue("session_token"), 
                Id = LoadEncryptedSettingValue("session_id"), 
                ExpireDate = expiryValue, 
                Provider = LoadEncryptedSettingValue("session_provider") 
            }; 
 
            _applicationSettings.Set(Constants.LoginToken, true); 
            _applicationSettings.Save(); 
            return session; 
        } 
 
        /// <summary> 
        /// The save session. 
        /// </summary> 
        /// <param name="session"> 
        /// The session. 
        /// </param> 
        private void Save(Session session) 
        { 
            SaveEncryptedSettingValue("session_token", session.AccessToken); 
            SaveEncryptedSettingValue("session_id", session.Id); 
            SaveEncryptedSettingValue("session_expiredate", session.ExpireDate.Ticks.ToString(CultureInfo.InvariantCulture)); 
            SaveEncryptedSettingValue("session_provider", session.Provider); 
            _applicationSettings.Set(Constants.LoginToken, true); 
            _applicationSettings.Save(); 
        } 
 
        /// <summary> 
        /// The clean session. 
        /// </summary> 
        private void CleanSession() 
        { 
            _applicationSettings.Reset("session_token"); 
            _applicationSettings.Reset("session_id"); 
            _applicationSettings.Reset("session_expiredate"); 
            _applicationSettings.Reset("session_provider"); 
            _applicationSettings.Reset(Constants.LoginToken); 
            _applicationSettings.Save(); 
        } 
 
        /// <summary> 
        /// The login async. 
        /// </summary> 
        /// <param name="provider"> 
        /// The provider. 
        /// </param> 
        /// <returns> 
        /// The <see cref="Task"/> object. 
        /// </returns> 
        public async Task<bool> LoginAsync(string provider) 
        { 
            Exception exception = null; 
            try 
            { 
                Session session = null; 
                switch (provider) 
                { 
                    case Constants.FacebookProvider: 
                        session = await _facebookService.LoginAsync(); 
                        break; 
                    case Constants.MicrosoftProvider: 
                        session = await _microsoftService.LoginAsync(); 
                        break; 
                    case Constants.GoogleProvider: 
                        session = await _googleService.LoginAsync(); 
                        break; 
                } 
                if (session != null) 
                { 
                    Save(session); 
                } 
 
                return true; 
            } 
            catch (InvalidOperationException e) 
            { 
                throw; 
            } 
            catch (Exception ex) 
            { 
                exception = ex; 
            } 
            await _logManager.LogAsync(exception); 
 
            return false; 
        } 
 
        /// <summary> 
        /// The logout. 
        /// </summary> 
        public async void Logout() 
        { 
            Exception exception = null; 
            try 
            { 
                var session = GetSession(); 
                switch (session.Provider) 
                { 
                    case Constants.FacebookProvider: 
                        _facebookService.Logout(); 
                        break; 
                    case Constants.MicrosoftProvider: 
                        _microsoftService.Logout(); 
                        break; 
                    case Constants.GoogleProvider: 
                        _googleService.Logout(); 
                        break; 
                } 
                CleanSession(); 
            } 
            catch (Exception ex) 
            { 
                exception = ex; 
            } 
            if (exception != null) 
            { 
                await _logManager.LogAsync(exception); 
            } 
        } 
 
        /// <summary> 
        /// Loads an encrypted setting value for a given key. 
        /// </summary> 
        /// <param name="key"> 
        /// The key to load. 
        /// </param> 
        /// <returns> 
        /// The value of the key. 
        /// </returns> 
        private string LoadEncryptedSettingValue(string key) 
        { 
            string value = null; 
 
            var protectedBytes = _applicationSettings.Get<byte[]>(key); 
            if (protectedBytes != null) 
            { 
                byte[] valueBytes = ProtectedData.Unprotect(protectedBytes, null); 
                value = Encoding.UTF8.GetString(valueBytes, 0, valueBytes.Length); 
            } 
 
            return value; 
        } 
 
        /// <summary> 
        /// Saves a setting value against a given key, encrypted. 
        /// </summary> 
        /// <param name="key"> 
        /// The key to save against. 
        /// </param> 
        /// <param name="value"> 
        /// The value to save against. 
        /// </param> 
        /// <exception cref="System.ArgumentOutOfRangeException"> 
        /// The key or value provided is unexpected. 
        /// </exception> 
        private void SaveEncryptedSettingValue(string key, string value) 
        { 
            if (!string.IsNullOrWhiteSpace(key) && !string.IsNullOrWhiteSpace(value)) 
            { 
                byte[] valueBytes = Encoding.UTF8.GetBytes(value); 
 
                // Encrypt the value by using the Protect() method. 
                byte[] protectedBytes = ProtectedData.Protect(valueBytes, null); 
                _applicationSettings.Set(key, protectedBytes); 
                _applicationSettings.Save(); 
            } 
        } 
    }

Now is time to build the User Interface, and because i am using MVVM, i created a LoginViewModel to binding to the LoginView.

The LoginViewModel is:

 /// <summary> 
    /// The login view model. 
    /// </summary> 
    public class LoginViewModel : ViewModelBase 
    { 
        private readonly ILogManager _logManager; 
        private readonly IMessageBoxService _messageBox; 
        private readonly INavigationService _navigationService; 
        private readonly ISessionService _sessionService; 
        private bool _inProgress; 
 
        /// <summary> 
        /// Initializes a new instance of the <see cref="LoginViewModel"/> class. 
        /// </summary> 
        /// <param name="navigationService"> 
        /// The navigation service. 
        /// </param> 
        /// <param name="sessionService"> 
        /// The session service. 
        /// </param> 
        /// <param name="messageBox"> 
        /// The message box. 
        /// </param> 
        /// <param name="logManager"> 
        /// The log manager. 
        /// </param> 
        public LoginViewModel(INavigationService navigationService, 
            ISessionService sessionService, 
            IMessageBoxService messageBox, 
            ILogManager logManager) 
        { 
            _navigationService = navigationService; 
            _sessionService = sessionService; 
            _messageBox = messageBox; 
            _logManager = logManager; 
            LoginCommand = new RelayCommand<string>(LoginAction); 
        } 
 
        /// <summary> 
        /// Gets or sets a value indicating whether in progress. 
        /// </summary> 
        /// <value> 
        /// The in progress. 
        /// </value> 
        public bool InProgress 
        { 
            get { return _inProgress; } 
            set { Set(() => InProgress, ref _inProgress, value); } 
        } 
 
        /// <summary> 
        /// Gets the facebook login command. 
        /// </summary> 
        /// <value> 
        /// The facebook login command. 
        /// </value> 
        public ICommand LoginCommand { get; private set; } 
 
        /// <summary> 
        /// Facebook's login action. 
        /// </summary> 
        /// <param name="provider"> 
        /// The provider. 
        /// </param> 
        private async void LoginAction(string provider) 
        { 
            Exception exception = null; 
            bool isToShowMessage = false; 
            try 
            { 
                InProgress = true; 
                var auth = await _sessionService.LoginAsync(provider); 
                if (!auth) 
                { 
                    await _messageBox.ShowAsync(AppResources.LoginView_LoginNotAllowed_Message, 
                        AppResources.MessageBox_Title, 
                        new List<string> 
                    { 
                        AppResources.Button_OK 
                    }); 
                } 
                else 
                { 
                    _navigationService.NavigateTo(new Uri(Constants.MainView, UriKind.Relative)); 
                } 
 
                InProgress = false; 
            } 
            catch (InvalidOperationException e) 
            { 
                InProgress = false; 
                isToShowMessage = true; 
            } 
            catch (Exception ex) 
            { 
                exception = ex; 
            } 
            if (isToShowMessage) 
            { 
                await _messageBox.ShowAsync(AppResources.LoginView_AuthFail, AppResources.ApplicationTitle, new List<string> { AppResources.Button_OK }); 
            } 
            if (exception != null) 
            { 
                await _logManager.LogAsync(exception); 
            } 
        } 
    }

Note: in LoginAction the parameter provider is the value of the CommandParameter received in LoginCommand, this is set in the login page.

The LoginPage.xaml is:

<phone:PhoneApplicationPage x:Class="AuthenticationSample.WP80.Views.LoginView" 
                            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
                            xmlns:Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP8" 
                            xmlns:controls="clr-namespace:Facebook.Client.Controls;assembly=Facebook.Client" 
                            xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
                            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                            xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" 
                            xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" 
                            xmlns:converters="clr-namespace:Cimbalino.Phone.Toolkit.Converters;assembly=Cimbalino.Phone.Toolkit" 
                            Orientation="Portrait" 
                            SupportedOrientations="Portrait" 
                            shell:SystemTray.IsVisible="True" 
                            mc:Ignorable="d"> 
    <phone:PhoneApplicationPage.DataContext> 
        <Binding Mode="OneWay" 
                 Path="LoginViewModel" 
                 Source="{StaticResource Locator}" /> 
    </phone:PhoneApplicationPage.DataContext> 
    <phone:PhoneApplicationPage.Resources> 
        <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/> 
    </phone:PhoneApplicationPage.Resources> 
    <phone:PhoneApplicationPage.FontFamily> 
        <StaticResource ResourceKey="PhoneFontFamilyNormal" /> 
    </phone:PhoneApplicationPage.FontFamily> 
    <phone:PhoneApplicationPage.FontSize> 
        <StaticResource ResourceKey="PhoneFontSizeNormal" /> 
    </phone:PhoneApplicationPage.FontSize> 
    <phone:PhoneApplicationPage.Foreground> 
        <StaticResource ResourceKey="PhoneForegroundBrush" /> 
    </phone:PhoneApplicationPage.Foreground> 
    <!--  LayoutRoot is the root grid where all page content is placed  --> 
    <Grid x:Name="LayoutRoot" Background="Transparent"> 
        <Grid.RowDefinitions> 
            <RowDefinition Height="Auto" /> 
            <RowDefinition Height="*" /> 
        </Grid.RowDefinitions> 
 
        <!--  TitlePanel contains the name of the application and page title  --> 
        <StackPanel x:Name="TitlePanel" 
                    Grid.Row="0" 
                    Margin="12,17,0,28"> 
            <TextBlock Margin="12,0" 
                       Style="{StaticResource PhoneTextNormalStyle}" 
                       Text="{Binding LocalizedResources.ApplicationTitle, 
                                      Mode=OneWay, 
                                      Source={StaticResource LocalizedStrings}}" /> 
            <TextBlock Margin="9,-7,0,0" 
                       Style="{StaticResource PhoneTextTitle1Style}" 
                       Text="{Binding LocalizedResources.LoginView_Title, 
                                      Mode=OneWay, 
                                      Source={StaticResource LocalizedStrings}}" /> 
        </StackPanel> 
 
        <!--  ContentPanel - place additional content here  --> 
        <Grid x:Name="ContentPanel" 
              Grid.Row="1" 
              Margin="24,0,0,-40"> 
            <Grid.RowDefinitions> 
                <RowDefinition Height="Auto" /> 
                <RowDefinition Height="Auto" /> 
                <RowDefinition Height="Auto" /> 
                <RowDefinition Height="Auto" /> 
                <RowDefinition Height="Auto" /> 
            </Grid.RowDefinitions> 
            <TextBlock Grid.Row="0" 
                       Style="{StaticResource PhoneTextTitle2Style}" 
                       Text="{Binding LocalizedResources.LoginView_UserAccount, 
                                      Mode=OneWay, 
                                      Source={StaticResource LocalizedStrings}}" /> 
            <Button Grid.Row="1" 
                    Margin="10" 
                    Command="{Binding LoginCommand}" 
                    CommandParameter="facebook" 
                    Content="Facebook" /> 
            <Button Grid.Row="2" 
                    Margin="10" 
                    Command="{Binding LoginCommand}" 
                    CommandParameter="microsoft" 
                    Content="Microsoft" /> 
            <Button Grid.Row="3" 
                    Margin="10" 
                    Command="{Binding LoginCommand}" 
                    CommandParameter="google" 
                    Content="Google" /> 
       </Grid> 
        <Grid Visibility="{Binding InProgress, Converter={StaticResource BooleanToVisibilityConverter}}" 
            Grid.Row="0" 
                   Grid.RowSpan="2"> 
            <Rectangle  
                   Fill="Black" 
                   Opacity="0.75" /> 
            <TextBlock  
                   HorizontalAlignment="Center" 
                   VerticalAlignment="Center" 
                   Text="{Binding LocalizedResources.LoginView_AuthMessage, 
                                  Mode=OneWay, 
                                  Source={StaticResource LocalizedStrings}}" /> 
            <ProgressBar IsIndeterminate="True" IsEnabled="True" Margin="0,60,0,0"/> 
        </Grid> 
     
    </Grid> 
</phone:PhoneApplicationPage>

Login User Interface


Source Code Files

  • IFacebookService interface for FacebookService
  • IGoogleService interface for GoogleService
  • ILogManager interface for LogManager
  • IMicrosoftService interface for MicrosoftService
  • ISessionProvider interface for all providers interface (common methods)
  • ISessionService for SessionService
  • Session class for save the information about the session (provider, token, expired date)
  • FacebookService class that has all logic about the login / logout using Facebook provider
  • GoogleService class that has all logic about the login / logout using Google provider
  • MicrosoftService class that has all logic about the login / logout using Microsoft provider
  • SessionService class for manage login/logout (it will use all services provides described before)
  • LoginViewModel class for binding to LoginView.xaml
  • LoginView class that represent the page for login
  • MainViewModel class for binding to MainView.xaml
  • MainView class that appear after the login is ok
  • AboutViewModel class for binding to the AboutView.xaml
  • AboutView class that represents the about page
  • ViewModelLocator class contains static references to all the view model in  application and provides an entry point for the bindings.

Build the Sample

  1. Start Visual Studio Express 2012 for Windows 8 and select File > Open > Project/Solution.
  2. Go to the directory in which you unzipped the sample. Go to the directory named for the sample, and double-click the Visual Studio Express 2012 for Windows 8 Solution (.sln) file.
  3. Press F7 or use Build > Build Solution to build the sample.

 Note: you can use Visual Studio 2013 in Windows 8.1.

 Run the sample

To debug the app and then run it, press F5 or use Debug > Start Debugging. To run the app without   debugging, press Ctrl+F5 or use Debug > Start Without Debugging.

Related Samples

More Information

Ask me on twitter @saramgsilva

47ª Reunião Presencial da Comunidade NetPonto em Lisboa

No dia 31-05-2014 será realizada a 47ª Reunião Presencial da Comunidade NetPonto em Lisboa. Para participar, efectue o registo de acordo com as instruções abaixo.

Agenda

09:45  – Recepção dos participantes
10:00  – Introdução ao Performance TuningNiko Neugebauer [MVP]
Esta apresentação  vai se focar nas bases de melhoria de desempenho do SQL Server. 

Operações básicas de planos de execução de Queries e maneiras para melhoria deles são os principais tópicos.

11:30  – Intervalo
12:00  – C# 6.0 April 2014 PreviewPaulo Morgado [MVP]
Uma passagem pelas novas funcionalidades do C# 6.0 presentes na antevisão de Abril de 2014 e as planeadas para futura implementação.
13:30  – Painel de Discussão e Sorteio de Prémios
Nota: Ao final da reunião, escolhemos um restaurante próximo e fazemos um almoço em grupo para continuar o convívio e aproximar as pessoas. A participação é opcional.

Registo / Inscrição

Para participar, basta efectuar a inscrição através do site:
http://netponto-lisboa-maio-2014.eventbrite.com/?aff=netorg

A entrada é gratuita.

Qualquer questão / esclarecimento, entre em contacto connosco.


Local

Microsoft Portugal – Auditório
Rua do Fogo de Santelmo, Lote 2.07.02
1990-110 Lisboa
Portugal

Clique para ampliar o mapa.

Patrocinador “Gold


Patrocinadores “Silver


Patrocinador “Bronze


Revista Programa edição nº45

Saiu mais uma edição da Revista Programar, desta vez foram publicados 3 artigos meus e o artigo da capa é meu 😀

Vejam:

Revista PROGRAMAR
Edição 45 – Maio de 2014


(clica para download)

Nesta edição trazemos até si como tema de capa o artigo Extendendo uma aplicação criada no App Studio da Microsoft. Adicionalmente, poderá ainda encontrar nesta edição os seguintes artigos:

  • JSF – Parte 3 (Managed beans)
  • Pascal – array de argumentos
  • Criar uma aplicação para Android com mapa
  • C# CRUD (Create, Read, Update & Delete)
  • C# – Novas Funcionalidades do C# 6.0 – Antevisão de Abril de 2014
  • Métodos de extensão – o que preciso, como quero
  • Programador ^ Gestor
  • Segurança em Redes Informáticas (4.ª Ed. Aumentada)
  • Estruturas de Dados e Algoritmos em C
  • Criando aplicações Windows Phone 8.1 e Windows 8.1 usando o App Studio da Microsoft (Sara Silva)
  • O Windows Phone 8.1 e a atualização do Windows 8.1 (Sara Silva)

Continuamos também a premiar os autores dos três melhores artigos, dado o sucesso nas edições anteriores. E os leitores devem dar a sua opinião para que possamos premiar correctamente. Para isso vote em http://tinyurl.com/ProgramarED45-V

Twitter Follow Button that works in IE10 and IE11

Today i found a issue in a web app, i find a different behavior in Windows Phone 8.1 and Windows Phone 8.0, that uses IE11 and IE10, for the twitter follow button.

After some search i found the code used before wasn´t the last version from twitter website.

Here is the sample code

   <a href="https://twitter.com/saramgsilva" class="twitter-follow-button" data-show-count="false">Follow @saramgsilva</a>


<script>
!function (d, s, id) { 
var js, fjs = d.getElementsByTagName(s)[0], p = /^http:/.test(d.location) ? 'http' : 'https';
if (!d.getElementById(id)) 
{ 
js = d.createElement(s); js.id = id; js.src = p + '://platform.twitter.com/widgets.js'; 
fjs.parentNode.insertBefore(js, fjs); }
}(document, 'script', 'twitter-wjs');
</script>

This works in

  • Lumia 520 with Windows Phone 8.0
  • Lumia 925 with Windows Phone 8.1
  • Lumia 920 with Windows Phone 8.1

[Visual Studio] Help make Edit and Continue better!

Do you get tired of seeing this box (I know I do)?

Tell us about it!

The Visual Studio team would like your anonymous feedback on improving Edit and Continue (E&C) when developing .NET applications. This survey can take as little as 3 minutes to complete (I’ve saved you some time already by copying all the words on that page to this page so you don’t have to read it twice) and will guide ongoing support and making it work in more places. If you consider yourself a regular E&C user or would like to see improvements that let you use it more often – we need to hear from you!

Please take a few minutes to complete the survey @ http://aka.ms/encsurvey and if it’s not too much trouble tell all of your developer pals about it. Blog, wall, and tweet the link to anyone who’ll listen!

The information you provide is entirely voluntary. If you do not wish to provide us with any information, please disregard this survey. By filling out and returning this survey, you agree that we can use, disclose, reproduce, or otherwise distribute your feedback at the aggregated level. Your personal information will remain confidential. Please check http://privacy.microsoft.com/en-us/default.aspx for Microsoft Privacy Statements.

 

 

How to avoid black transition between pages in Windows Phone

I was working in an app for Windows Phone 7.5 that contained a few issues, and one theses issues was a black transition between pages. The feedback from the users was that this behavior was very annoying.

To fix this error I added a Brush to the RootFrame’s Backgroud:

 

  private void InitializePhoneApplication()
        {
            if (phoneApplicationInitialized)
                return;

            // Create the frame but don't set it as RootVisual yet; this allows the splash
            // screen to remain active until the application is ready to render.
            RootFrame = new RadPhoneApplicationFrame();
            RootFrame.Navigated += CompleteInitializePhoneApplication;
            
            RootFrame.Background = (ImageBrush) Current.Resources["ImageBrushGeneral"];
            // Handle navigation failures
            RootFrame.NavigationFailed += RootFrame_NavigationFailed;

            RootFrame.Navigating += new NavigatingCancelEventHandler(RootFrame_Navigating);

            // Ensure we don't initialize again
            phoneApplicationInitialized = true;
        }

 

with

 

 <ImageBrush x:Key="ImageBrushGeneral"
                    x:Name="ImageBrushGerenal"
                    ImageSource="/ProjectName;component/Images/Loading.png" />

5ª Reunião Presencial da Comunidade NetPonto no Porto

No dia 24-05-2014 será realizada a 5ª Reunião Presencial da Comunidade NetPonto no Porto. Para participar, efectue o registo de acordo com as instruções abaixo.

Agenda

14:00  – Recepção dos participantes
14:30  – Era outro Cimbalino por favor! – Pedro Lamas [MSFT]
O Cimbalino Windows Phone Toolkit tornou-se para muitos dos programadores de Windows Phone, uma referência essencial nas suas aplicações!Nesta sessão será apresentado o Cimbalino Toolkit, que suportará a nova geração de aplicações para Windows 8.1 e Windows Phone 8.1, mas mais do que uma simples overview da nova versão do toolkit, iremos falar de algumas decisões tomadas para suportar Universal Apps, as alterações introduzidas nas Portable Class Libraries e os desafios que isso criou, os problemas identificados e algumas formas de os resolver.

Esta será uma sessão que se pretende bastante dinâmica, com a introdução de alguns conceitos avançados mas de fácil compreensão, e ideal para qualquer programador que esteja a pensar em criar as suas próprias bibliotecas e projectos partilhados!

16:00  – Intervalo
16:30  – Criando aplicações para Windows Phone 8.1 e Windows 8.1 com o App Studio da Microsoft –Sara Silva [MVP]
Já tiveste ideias brilhantes para uma app? Queres colocar isso em prática? Então esta sessão é para ti!O App Studio da Microsoft é um serviço para facilitar e acelerar o desenvolvimento de aplicações para Windows Phone e Windows 8.1. Nesta sessão, a Sara vai apresentar o App Studio, onde vai criar uma app e lhe vai adicionar diversas funcionalidades, como por exemplo: feed the notícias de um blog, canal de Youtube, feed de uma página de Facebook, entre outras funcionalidades.

E uma vez que o App Studio é extensível e porque código não podia faltar, a Sara irá apresentar um exemplo de como extender o código, adicionando o feed do Twitter.

18:00  – Painel de Discussão e Sorteio de Prémios
Nota: Ao final da reunião, escolhemos um restaurante próximo e fazemos um jantar em grupo para continuar o convívio e aproximar as pessoas. A participação é opcional.

Registo / Inscrição

Para participar, basta efectuar a inscrição através do site:
http://netponto-porto-maio-2014.eventbrite.com/?aff=netorgA entrada é gratuita.

Qualquer questão / esclarecimento, entre em contacto connosco.


Local

Instituto Superior de Engenharia do Porto (ISEP) – Auditório H202
Rua Dr. António Bernardino de Almeida, 431
4200-072 Porto
Portugal

Clique para ampliar o mapa.

Patrocinadores “Gold


Patrocinadores “Silver


Patrocinador “Bronze


Mais Comunidade NetPonto:

Building an On-Demand Video Service with Microsoft Azure Media Services

What isBuilding an On-Demand Video Service with Microsoft Azure Media Services?  
 

Microsoft Azure Media Services allows you to build media distribution solutions that can upload, encode, package, and stream media to multiple devices and platforms.

Traditionally, building the workflow for the creation, management, and distribution of media is problematic. It involves having to integrate multiple technologies and providers, some of which may be incompatible. In addition, it can require a huge investment in infrastructure, which may not always be fully utilized. These issues can result in a non-standardized workflow that is not easily scaled, and that requires coordination at different stages of the workflow.

Azure Media Services allow you to build scalable, cost effective, end-to-end media distribution solutions that can upload, encode, package, and stream media to Windows, iOS, Android, Adobe Flash, and other devices and platforms.

This guide describes how to design and build a video-on-demand application that uses Media Services. It provides an end to end walkthrough of a Windows Store application that communicates with Media Services through a web service, and explains key design and implementation choices.

In addition to the Windows Store application, the guide also includes client applications for Windows Phone, web, iOS, and Android devices. You can download the Windows client applications from the Microsoft Download Center. You can download the Android and iOS applications from the community site.

Quick Links

 

Public announcement

 

Source code:

http://aka.ms/amsg-code

 

Project site:

http://aka.ms/amsg-cp

 

Guides:

http://aka.ms/amsg-book

 

Web sites:
http://aka.ms/amsg-doc

What’s in the Box?  
 

─     Reference Implementation (RI) – the Contoso Video RI demonstrates the concepts around building an on-demand video system, along with clients for Windows 8.1, Windows Phone 8, HTML5, Android, and iOS.

─     Guide – Building an On-Demand Video Service with Microsoft Azure Media Services” is designed to help developers and architects understand the concepts and implementation details for on-demand video system that leverages Microsoft Azure Media Services with a simple Content Management System for encoding and delivery of video assets.
ebook
 

How to Get It?  
The Contoso Video reference implementation is on the Microsoft Download Center.

You can view the documentation online or download an eBook version.

 
Acknowledgements  
 

Many people contributed to this release! We are grateful to all of them!

Development team: David Britch (Content Master Ltd.), Martin Cabral (Southworks), RoAnn Corbisier, Nelly Delgado, Carlos Farre, Ezequiel Jadib (Southworks), Monika Jadwani (Tata Consultancy Services ), Sumit Jaiswal (Tata Consultancy Services), Douglas McMurtry (AgileThought), Gurunath Navale (Tata Consultancy Services), Andrew Oakley, Kirpa Singh, Hanz Zhang.

We want to thank the customers, partners, and community members who have patiently reviewed our early content and drafts.

We thank all community members who have followed our journey and provided feedback.