Posts mit dem Label RIA Services werden angezeigt. Alle Posts anzeigen
Posts mit dem Label RIA Services werden angezeigt. Alle Posts anzeigen

Samstag, 13. November 2010

Using authenticated RIA Services with Windows Phone 7

In my older post RIA Services: Windows Phone 7 and SOAP endpoint | .NET - Red zone : Best practices and latest stuff I have described how a RIA Service can be used as normal WCF SOAP service for example with Windows Phone 7.

But if you want to use RIA Services with Windows Phone 7, there is the problem that Silverlight for Windows Phone 7 does not support authentication headers. But using the instructions here Using Authenticated Ria Services on your WP7 phone - Marcel de Vries, MVP Team System - blog community you can still use the cool authorization mechanism of WCF RIA Services with Windows Phone 7.

The key steps are:

1. Add enableHttpCookieContainer="true" to your ServiceReferences.ClientConfig

After the proxy is generated enable the HttpCookieContainer at your bindings for authentication service and your domain service. You have to remove it for each proxy new configuration to avoid an error message during proxy generation.

   1: <bindings>
   2:             <basicHttpBinding>
   3:                 <binding name="BasicHttpBinding_AuthenticationServiceSoap" maxBufferSize="2147483647"
   4:                          enableHttpCookieContainer="true"
   5:                     maxReceivedMessageSize="2147483647">
   6:                     <security mode="None" />
   7:                 </binding>
   8:                 <binding name="BasicHttpBinding_EmployeeDomainServiceSoap" maxBufferSize="2147483647"
   9:                       enableHttpCookieContainer="true"
  10:                     maxReceivedMessageSize="2147483647">
  11:                     <security mode="None" />
  12:                 </binding>
  13:             </basicHttpBinding>
  14:         </bindings>
2. Store the returned cookie container of your Login-Call for the next service calls
   1: protected virtual void OnLoginCompleted(object sender, LoginCompletedEventArgs e)
   2:        {
   3:            var args = new LoginServiceCompletedEventArgs();
   4:            
   5:            CookieContainer = null;
   6:            
   7:            if (e.Result != null)
   8:            {
   9:                args.User = null;
  10:                args.Error = true;
  11:  
  12:                CookieContainer = _authclient.CookieContainer;
  13:                ViewModelLocator.AuthCookieContainer = _authclient.CookieContainer;

Hint: Don’t be surprised that the cookie container looks empty at this point (count is 0). There is a kind of “magic” cookie still in there.

3. Use the returned cookie container for your proteced domain service calls
   1: var client = new EmployeeDomainServiceSoapClient
   2:                  {
   3:                      CookieContainer = ViewModelLocator.AuthCookieContainer
   4:                  };

Samstag, 10. Juli 2010

RIA Services: Windows Phone 7 and SOAP endpoint

You can use RIA services as a normal WCF service with several clients. For example as Excel OData-Source or as data delivery service for your Windows Phone 7 application. To achieve this goal you have to install the latest RIA Services Toolkit and do a little configuration work.

Reference for Microsoft.ServiceModel.DomainServices.Hosting

Add a reference of Microsoft.ServiceModel.DomainServices.Hosting to your RIA Services project.

It is important that you choose the version which was shipped by the RIA Services (Silverlight) toolkit. The standard standard assembly from the SDK does not contain the SoapXmlEndpointFactory and JSonEndpointFactory.

So take this one:

image

For the OData endpoint you need the System.ServiceModel.DomainServices.Hosting.OData assembly from the SDK directory.

Configure the endpoints

Configure the Json, Soap and OData endpoints in the web.config:

<system.serviceModel>
      <domainServices>
        <endpoints>
          <add name="Soap" 
               type="Microsoft.ServiceModel.DomainServices.Hosting.SoapXmlEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          <add name="Json" 
               type="Microsoft.ServiceModel.DomainServices.Hosting.JsonEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          <add name="OData"
               type="System.ServiceModel.DomainServices.Hosting.ODataEndpointFactory, System.ServiceModel.DomainServices.Hosting.OData, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        </endpoints>
      </domainServices>
       <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
     </system.serviceModel>
Using of RIA Services in your Windows Phone 7 application

To use the rias service (Soap endpoint) in your Windows Phone 7 application you have only to add a new reference and enter the Uri of your ria service.

Your Uri consists of the <namespace of your ria service>-<classname of your ria service>.svc where “.” are replaced with “-“ !

image

 

Now you can create a proxy client and access to your Domainservice methods:

   1: public partial class MainPage : PhoneApplicationPage
   2:     {
   3:         object _selectedItem;
   4:         PrivatbilanzService.FinancialPlanningDomainServiceSoapClient client;
   5:  
   6:         public MainPage()
   7:         {
   8:             InitializeComponent();
   9:  
  10:             client = new PrivatbilanzService.FinancialPlanningDomainServiceSoapClient();
  11:  
  12:             SupportedOrientations = SupportedPageOrientation.Portrait;
  13:             Loaded += new RoutedEventHandler(MainPage_Loaded);
  14:  
  15:             PageTransitionList.Completed += new EventHandler(PageTransitionList_Completed);
  16:  
  17:             // Set the data context of the listbox control to the sample data
  18:             DataContext = new MainViewModel();
  19:         }

 

Uri of all endpoints

The Uri for our exposed endpoints are:

OData : http://localhost:[portnumber]/<namespace of your ria service>-<classname of your ria service>.svc/OData/

SOAP: http://localhost:[portnumber]/<namespace of your ria service>-<classname of your ria service>.svc

JSON: http://localhost:[portnumber]/<namespace of your ria service>-<classname of your ria service>.svc/JSON/

With these exposed endpoints, you can talk to multiple clients:

  • Excel Power pivot - Using the OData endpoint
  • Windows Phone 7 – Using the SOAP endpoint
  • AJAX client – Using the JSON endpoint

Sonntag, 20. Juni 2010

Silverlight: Managing presentation model state

In our current project Privatbilanz we had the problem that we have to manage the state of the IsExpanded property in a treeview.

Our architecture:
  • Data Access Layer: Entity Framework
  • WCF RIA Services
  • Silverlight client

After each manipulation of our nodes of the treeview, we have to call the WCF service to give us back the fresh list of nodes. After this action the tree will have has initial look – all nodes are collapsed :-(

So what we did now was to extend our data model at the client side with a partial class to define for our entity a IsExpanded property.

Step 1 – Extend entity
   1: public partial class AnzeigeKategorie
   2:     {
   3:         private bool _isExpanded;
   4:         
   5:         public bool IsExpanded
   6:         {
   7:             get { return _isExpanded; }
   8:             set
   9:             {
  10:                 if (value == _isExpanded) return;
  11:                 _isExpanded = value;
  12:                 RaisePropertyChanged("IsExpanded");
  13:             }
  14:         }
  15:     }

Note: You have to use the same namepace as your model at the service side (WCF RIA Services)

Step 2 – Bind the property to UI
   1: <!--TreeViewItem Style-->
   2:     <Style TargetType="controls:TreeViewItem">
   3:         <Setter Property="Padding" Value="3"/>
   4:         <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
   5:         <Setter Property="VerticalContentAlignment" Value="Top"/>
   6:         <Setter Property="Background" Value="Transparent"/>
   7:         <Setter Property="Foreground" Value="{StaticResource TextBrush}"/>
   8:         <Setter Property="FontFamily" Value="{StaticResource ContentFontFamily}"/>
   9:         <Setter Property="FontSize" Value="{StaticResource ContentFontSize}"/>
  10:         <Setter Property="TextOptions.TextHintingMode" Value="Animated"/>
  11:         <Setter Property="BorderThickness" Value="1"/>
  12:         <Setter Property="Cursor" Value="Arrow"/>
  13:         <Setter Property="IsTabStop" Value="True"/>
  14:         <Setter Property="TabNavigation" Value="Once"/>
  15:         <Setter Property="Margin" Value="0 1 0 0"/>
  16:         <Setter Property="Helpers:SetterValueBindingHelper.PropertyBinding">
  17:             <Setter.Value>
  18:                 <Helpers:SetterValueBindingHelper Property="IsExpanded" Binding="{Binding IsExpanded, Mode=TwoWay}" />
  19:             </Setter.Value>
  20:         </Setter>

Because in our case the control is a TreeviewItem we have to do this in our style definition. Unfortunately Silverlight does not support this kind of binding at the normal way – WPF is at this point much better.

So what we have to do additional is to define a helper class SetterValueBindingHelper. We found this really useful class at Delay’ Blog:

As the platform evolves, so do the workarounds [Better SetterValueBindingHelper makes Silverlight Setters better-er!] - Delay's Blog - Site Home - MSDN Blogs

 
Step 3 – Helper class for Setter binding
   1: /// <summary>
   2:     /// Class that implements a workaround for a Silverlight XAML parser
   3:     /// limitation that prevents the following syntax from working:
   4:     ///    &lt;Setter Property="IsSelected" Value="{Binding IsSelected}"/&gt;
   5:     /// </summary>
   6:     public class SetterValueBindingHelper
   7:     {
   8:         /// <summary>
   9:         /// Optional type parameter used to specify the type of an attached
  10:         /// DependencyProperty as an assembly-qualified name, full name, or
  11:         /// short name.
  12:         /// </summary>
  13:         [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods",
  14:             Justification = "Unambiguous in XAML.")]
  15:         public string Type { get; set; }
  16:  
  17:         /// <summary>
  18:         /// Property name for the normal/attached DependencyProperty on which
  19:         /// to set the Binding.
  20:         /// </summary>
  21:         public string Property { get; set; }
  22:  
  23:         /// <summary>
  24:         /// Binding to set on the specified property.
  25:         /// </summary>
  26:         public Binding Binding { get; set; }
  27:  
  28:         /// <summary>
  29:         /// Gets the value of the PropertyBinding attached DependencyProperty.
  30:         /// </summary>
  31:         /// <param name="element">Element for which to get the property.</param>
  32:         /// <returns>Value of PropertyBinding attached DependencyProperty.</returns>
  33:         [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
  34:             Justification = "SetBinding is only available on FrameworkElement.")]
  35:         public static SetterValueBindingHelper GetPropertyBinding(FrameworkElement element)
  36:         {
  37:             if (null == element)
  38:             {
  39:                 throw new ArgumentNullException("element");
  40:             }
  41:             return (SetterValueBindingHelper)element.GetValue(PropertyBindingProperty);
  42:         }
  43:  
  44:         /// <summary>
  45:         /// Sets the value of the PropertyBinding attached DependencyProperty.
  46:         /// </summary>
  47:         /// <param name="element">Element on which to set the property.</param>
  48:         /// <param name="value">Value forPropertyBinding attached DependencyProperty.</param>
  49:         [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
  50:             Justification = "SetBinding is only available on FrameworkElement.")]
  51:         public static void SetPropertyBinding(FrameworkElement element, SetterValueBindingHelper value)
  52:         {
  53:             if (null == element)
  54:             {
  55:                 throw new ArgumentNullException("element");
  56:             }
  57:             element.SetValue(PropertyBindingProperty, value);
  58:         }
  59:  
  60:         /// <summary>
  61:         /// PropertyBinding attached DependencyProperty.
  62:         /// </summary>
  63:         public static readonly DependencyProperty PropertyBindingProperty =
  64:             DependencyProperty.RegisterAttached(
  65:                 "PropertyBinding",
  66:                 typeof(SetterValueBindingHelper),
  67:                 typeof(SetterValueBindingHelper),
  68:                 new PropertyMetadata(null, OnPropertyBindingPropertyChanged));
  69:  
  70:         /// <summary>
  71:         /// Change handler for the PropertyBinding attached DependencyProperty.
  72:         /// </summary>
  73:         /// <param name="d">Object on which the property was changed.</param>
  74:         /// <param name="e">Property change arguments.</param>
  75:         private static void OnPropertyBindingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  76:         {
  77:             // Get/validate parameters
  78:             var element = (FrameworkElement)d;
  79:             var item = (SetterValueBindingHelper)(e.NewValue);
  80:             if ((null == item.Property) || (null == item.Binding))
  81:             {
  82:                 throw new ArgumentException(
  83:                     "SetterValueBindingHelper's Property and Binding must both be set to non-null values.");
  84:             }
  85:  
  86:             // Get the type on which to set the Binding
  87:             Type type = null;
  88:             if (null == item.Type)
  89:             {
  90:                 // No type specified; setting for the specified element
  91:                 type = element.GetType();
  92:             }
  93:             else
  94:             {
  95:                 // Try to get the type from the type system
  96:                 type = System.Type.GetType(item.Type);
  97:                 if (null == type)
  98:                 {
  99:                     // Search for the type in the list of assemblies
 100:                     foreach (var assembly in AssembliesToSearch)
 101:                     {
 102:                         // Match on short or full name
 103:                         type = assembly.GetTypes()
 104:                             .Where(t => (t.FullName == item.Type) || (t.Name == item.Type))
 105:                             .FirstOrDefault();
 106:                         if (null != type)
 107:                         {
 108:                             // Found; done searching
 109:                             break;
 110:                         }
 111:                     }
 112:                     if (null == type)
 113:                     {
 114:                         // Unable to find the requested type anywhere
 115:                         throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
 116:                             "Unable to access type \"{0}\". Try using an assembly qualified type name.",
 117:                             item.Type));
 118:                     }
 119:                 }
 120:             }
 121:  
 122:             // Get the DependencyProperty for which to set the Binding
 123:             DependencyProperty property = null;
 124:             var field = type.GetField(item.Property + "Property",
 125:                 BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Static);
 126:             if (null != field)
 127:             {
 128:                 property = field.GetValue(null) as DependencyProperty;
 129:             }
 130:             if (null == property)
 131:             {
 132:                 // Unable to find the requested property
 133:                 throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
 134:                     "Unable to access DependencyProperty \"{0}\" on type \"{1}\".",
 135:                     item.Property, type.Name));
 136:             }
 137:  
 138:             // Set the specified Binding on the specified property
 139:             element.SetBinding(property, item.Binding);
 140:         }
 141:  
 142:         /// <summary>
 143:         /// Returns a stream of assemblies to search for the provided type name.
 144:         /// </summary>
 145:         private static IEnumerable<Assembly> AssembliesToSearch
 146:         {
 147:             get
 148:             {
 149:                 // Start with the System.Windows assembly (home of all core controls)
 150:                 yield return typeof(Control).Assembly;
 151:  
 152:                 // Fall back by trying each of the assemblies in the Deployment's Parts list
 153:                 foreach (var part in Deployment.Current.Parts)
 154:                 {
 155:                     var streamResourceInfo = Application.GetResourceStream(
 156:                         new Uri(part.Source, UriKind.Relative));
 157:                     using (var stream = streamResourceInfo.Stream)
 158:                     {
 159:                         yield return part.Load(stream);
 160:                     }
 161:                 }
 162:             }
 163:         }
 164:     }