Friday, August 3, 2012

silverlight mvvm light + WCF RIA

Step 1: Create an empty Solution.


Step 2: Add an Empty Web Project:


Step 3: Add Silverlight Class Library (works on SL5)


Step 4: Add MVVM light 5



Step 5: Link .Web to Silverlight Application:

.Web -> Properties -> Silverlight -> Add SilverLight Project


remove .aspx start file generated by the link (in this example MvvmRIASample.SLTestPage.aspx)
and rename MvvmRIASample.SLTestPage.html to index.html and make it start page.

Step 6: Add Folder Models to .Web (where the .emdx is created)



COMPILE!!!

Step 7: Add Folder Service to .Web



Step 8: Link .Core to .Web (WCF RIA Service Link) through .Core Properties

Step 9:  Make .SL depend on .Core


Step 10: Add the same references that .Core has to .SL

- System.ComponentModel.DataAnnotations
- System.ServiceModel
- System.ServiceModel.DomainServices.Client
- System.ServiceModel.DomainServices.Client.Web
- System.ServiceModel.Web.Extensions

Step 11: Make the previous .DLL do NOT copy in LOCAL (in .Core) to avoid duplication in the final executable.

Step 12: Modify MainViewModel.cs (to test that everything is working correctly)

adding the following:

using MvvmRIASample.Web.Models;
using MvvmRIASample.Web.Services;
using System.Linq;


        #region Welcome
        public const string WelcomePropertyName = "Welcome";

        private string _welcome = "";

        public string Welcome
        {
            get
            {
                return _welcome;
            }

            set
            {
                if (_welcome == value)
                {
                    return;
                }

                var oldValue = _welcome;
                _welcome = value;

                RaisePropertyChanged(WelcomePropertyName);

            }
        }
        #endregion


        public MainViewModel()
        {
            if (IsInDesignMode)
            {
                Welcome = "Design Data";
            }
            else
            {
                AWDomainServices context = new AWDomainServices();
                context.Load(context.GetProductsQuery(), (result =>
                {
                    if (!result.HasError)
                    {
                        Product first = result.Entities.FirstOrDefault();
                        if (first != null)
                        {
                            Welcome = first.Name;
                        }
                    }
                }), null);
            }
        }


Add Authentication Service


Step 13: Add the following in web.config in .Web project


<!--<system.web>-->
<!--  <compilation debug="true" targetFramework="4.0" />-->
  <authentication mode="Forms"></authentication>
  <roleManager enabled="true"></roleManager>
  <profile enabled="true">
    <properties>
      <add type="System.Int32" defaultValue="10" name="DefaultRows"/> <!-- test -->
    </properties>
  </profile>
<!-- </system.web>-->


Step 14: Add "Authentication Domain Service" to .Web (Services\AuthenticationDomainService.cs)



Step 15: Oepn AuthenticationDomainService.cs and add the following


[EnableClientAccess]
public class AuthenticationDomainService : AuthenticationBase<User>
{
}

public class User : UserBase
{
    public int DefaultRows { get; set; }
}

And build the solution.

Step 16: Create an Test User using ASP.NET Web Site Administration Tool

Step 17: Manually create the class WebContext.cs in .Core

    public sealed partial class WebContext: WebContextBase
    {
        partial void OnCreated();

        public WebContext()
        {
            this.OnCreated();
        }

        public new static WebContext Current
        {
            get
            {
                return ((WebContext)(WebContextBase.Current));
            }
        }

        public new User User
        {
            get
            {
                return ((User)(base.User));
            }
        }
    }

Step 18: Configuring the Client for Authentication
in App.xaml.c 
        public App()
        {
            Startup += Application_Startup;
            Exit += Application_Exit;
            UnhandledException += Application_UnhandledException;

            InitializeComponent();

            /////////////////////// added
            WebContext webContext = new WebContext();
            webContext.Authentication = new FormsAuthentication();
            this.ApplicationLifetimeObjects.Add(webContext);
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            /// Added Code
            ((WebAuthenticationService)WebContext.Current.Authentication).DomainContext = new MultiTier.Web.AuthenticationDomainContext();
            this.Resources.Add("WebContext", WebContext.Current);
            //////////////////

            RootVisual = new MainPage();
            DispatcherHelper.Initialize();
        }

Step 19: Adding Login Functionality to the Client (step 19 is to add some code to see it works)
Add the following snippet to MainPage.xaml: 
            <TextBlock x:Name="WelcomeText" Visibility="Collapsed"></TextBlock>
            <HyperlinkButton x:Name="LogoutButton" 
                 Content="Logout" 
                 Click="LogoutButton_Click" 
                 Visibility="Collapsed">
            </HyperlinkButton>
            <Border x:Name="LoginBorder" 
        Margin="10,10,0,0" 
        BorderThickness="2" 
        BorderBrush="Black" 
        HorizontalAlignment="Left" 
        CornerRadius="15" 
        Padding="10" 
        Background="BlanchedAlmond" 
        Width="300">
                <Grid HorizontalAlignment="Left">
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                        <RowDefinition Height="30" ></RowDefinition>
                        <RowDefinition Height="30"></RowDefinition>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Row="0" 
                   Grid.ColumnSpan="2" 
                   Grid.Column="0" 
                   FontWeight="Bold" 
                   HorizontalAlignment="Left" 
                   VerticalAlignment="Center" 
                   Text="Log In Existing User">
                    </TextBlock>
                    <TextBlock Grid.Row="1" 
                   Grid.Column="0" 
                   HorizontalAlignment="Right" 
                   VerticalAlignment="Center" 
                   Text="User Name: ">
                    </TextBlock>
                    <TextBox x:Name="UserName" 
                 VerticalAlignment="Center" 
                 Grid.Row="1" 
                 Grid.Column="1"  
                 Width="100">
                    </TextBox>
                    <TextBlock Grid.Row="2" 
                   HorizontalAlignment="Right" 
                   Grid.Column="0" 
                   VerticalAlignment="Center" 
                   Text="Password: ">
                    </TextBlock>
                    <PasswordBox x:Name="Password" 
                     VerticalAlignment="Center" 
                     Grid.Row="2" 
                     Grid.Column="1"  
                     Width="100">
                    </PasswordBox>
                    <TextBlock x:Name="LoginResult" 
                   TextWrapping="Wrap" 
                   Visibility="Collapsed" 
                   Grid.Row="3" 
                   Grid.ColumnSpan="2" 
                   Foreground="Red">
                    </TextBlock>
                    <Button x:Name="LoginButton" 
                Margin="0,5,0,0" 
                Grid.Row="4" 
                Grid.Column="1" 
                Content="Log In" 
                Click="LoginButton_Click">
                    </Button>
                </Grid>
            </Border>


and following codes to MainPage.xaml.cs


        protected void OnNavigatedTo(NavigationEventArgs e)
        {
            SetControlVisibility(WebContext.Current.User.IsAuthenticated);
        }

        private void LoginButton_Click(object sender, RoutedEventArgs e)
        {
            LoginParameters lp = new LoginParameters(UserName.Text, Password.Password);
            WebContext.Current.Authentication.Login(lp, this.LoginOperation_Completed, null);
            LoginButton.IsEnabled = false;
            LoginResult.Text = "";
        }

        private void LoginOperation_Completed(LoginOperation lo)
        {
            if (lo.HasError)
            {
                LoginResult.Text = lo.Error.Message;
                LoginResult.Visibility = System.Windows.Visibility.Visible;
                lo.MarkErrorAsHandled();
            }
            else if (lo.LoginSuccess == false)
            {
                LoginResult.Text = "Login failed. Please check user name and password.";
                LoginResult.Visibility = System.Windows.Visibility.Visible;
            }
            else if (lo.LoginSuccess == true)
            {
                SetControlVisibility(true);
            }
            LoginButton.IsEnabled = true;
        }

        private void SetControlVisibility(bool isAuthenticated)
        {
            if (isAuthenticated)
            {
                LoginBorder.Visibility = System.Windows.Visibility.Collapsed;
                WelcomeText.Text = "Welcome " + WebContext.Current.User.Name;
                WelcomeText.Visibility = System.Windows.Visibility.Visible;
                LogoutButton.Visibility = System.Windows.Visibility.Visible;
            }
            else
            {
                LoginBorder.Visibility = System.Windows.Visibility.Visible;
                WelcomeText.Visibility = System.Windows.Visibility.Collapsed;
                LogoutButton.Visibility = System.Windows.Visibility.Collapsed;
            }
        }

        private void LogoutButton_Click(object sender, RoutedEventArgs e)
        {
            WebContext.Current.Authentication.Logout(this.LogoutOperation_Completed, null);
        }

        private void LogoutOperation_Completed(LogoutOperation lo)
        {

            if (!lo.HasError)
            {
                SetControlVisibility(false);
            }
            else
            {
                //ErrorWindow ew = new ErrorWindow("Logout failed.", "Please try logging out again.");
                //ew.Show();
                lo.MarkErrorAsHandled();
            }
        }