How to resolve: ListBox UI does not update (refresh) on WCF .NET Ria Services domaincontext async call in Silverlight 3

When you are calling a function on a WCF .NET RIA service, the completed eventhandler will take you back to the UI thread, but if you are binding the ListBox to a List<….> the UI of the Listbox won’t be updated.

Solution: don’t use a List<…> as ItemSource but a System.Collections.ObjectModel.ObservableCollection<…>

Get the DomainService (LINQ to SQL) to load child entities with .NET RIA Services in Silverlight 3

If you have a table with related tables then you can get the child entries by editing the DomainService and the metadata:
Add the include attribute ([Include()]) to the property containing the child table reference and use the DataLoadOptions to specify the child tables to include in the query result view.

In this case a Task table contains a reference to a Project table and the Project table contains a reference to the Customer table:

 

The domainservice class TTSDomainService

// TODO: Consider
// 1. Adding parameters to this method and constraining returned results, and/or
// 2. Adding query methods taking different parameters.
public IQueryable<Task> GetTasks()
{
// Define the child entries to get 
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Task>(t => t.Project);
options.LoadWith<Project>(p => p.Customer);
this.DataContext.LoadOptions = options;
// Get the tasks ordered by customer, project, task
return from t in this.DataContext.Tasks
orderby t.Project.Customer.Name, t.Project.Name, t.Name
select t;
}

 

The domainservice meta data class: TTSDomainService.metadata.cs

 

// The MetadataTypeAttribute identifies TaskMetadata as the class
// that carries additional metadata for the Task class.
[MetadataTypeAttribute(typeof(Task.TaskMetadata))]
public partial class Task
{
// This class allows you to attach custom attributes to properties
// of the Task class.
//
// For example, the following marks the Xyz property as a
// required field and specifies the format for valid values:
//    [Required]
//    [RegularExpression("[A-Z][A-Za-z0-9]*")]
//    [StringLength(32)]
//    public string Xyz;
internal sealed class TaskMetadata
{
// Metadata classes are not meant to be instantiated.
private TaskMetadata()
{
}
public Nullable<int> CategoryAbbrID;
public int CategoryID;
public Nullable<decimal> EstDuration;
public Nullable<int> HourType;
public string Name;
     [Include()]
        public Project Project;
public int ProjectID;
public EntitySet<TaskTimeSpan> TaskTimeSpans;
}
}

 

See:

http://chriswalshie.wordpress.com/2009/08/11/masterdetail-binding-with-net-ria-services-and-the-agdatagrid/

Entities not loaded after domainContext.Load(domainContext.GetUsers) in WCF RIA service

If you use LINQ to SQL and you’re entities are not loaded after you call a GetQuery on the DomainContext, you probably did not use a callback.

TTSDomainContext context = new TTSDomainContext();
LoadOperation op = context.Load(
context.GetTasksQuery(),
result =>
{
if (!result.HasError)
{
//At this point the entities are loaded
       }
},null); 

Get only the changed data from the database with Linq to SQL and .NET RIA Services in Silverlight 3

If you cache data in you’re Silverlight 3 application and want to sync (get the latest data from the database) the entities, you can use the Load function with the LoadBehavior.RefreshCurrent option. This will get the latest data from the database, but only the changed entities.

private EntitySet<TTUser> _userData;
public EntitySet<TTUser> UserData
{
get
{
return _userData;
}
set
{
_userData = value;
}
}

private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (WebContext.Current.User.IsAuthenticated)
{
TTSDomainContext context = new TTSDomainContext();
this.UserData = context.TTUsers;
tasksDataGrid.ItemsSource = this.UserData;
context.Load(context.GetUsersQuery(),LoadBehavior.RefreshCurrent,true);
}
}

 

You can use the Submitchanges() function to update the database.

Implementing custom authentication with .NET RIA Services and Silverlight 3, by using a Custom Membership Provider

I am creating a Silverlight 3 application that must work with a database that is used by a legacy ASP .net 1.0 system. The database contains tables for users and roles. The Silverlight 3 application should use forms authentication and use the “User” and “Role” table in the database.

First I tried to change the uthenticationService : AuthenticationBase<UserWeb> to inherit my “LINQ to SQL” domainservice, but then I got a exception:

The entity type ‘Ada.Tts.Toggle.Silverlight.Web.Company’ is exposed by multiple DomainService types. Entity types cannot be shared across DomainServices

I solved this problem by implementing a custom membership provider, the custom membership provider uses the Linq to SQL domainservice.

TTSMembershipProvider.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
namespace Ada.Tts.Toggle.Web.BC
{
public class TTSMembershipProvider : MembershipProvider
{
public override string ApplicationName
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public override bool ChangePassword(string username, string oldPassword, string newPassword)
{
throw new NotImplementedException();
}
public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
{
throw new NotImplementedException();
}
public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
throw new NotImplementedException();
}
public override bool DeleteUser(string username, bool deleteAllRelatedData)
{
throw new NotImplementedException();
}
public override bool EnablePasswordReset
{
get { throw new NotImplementedException(); }
}
public override bool EnablePasswordRetrieval
{
get { throw new NotImplementedException(); }
}
public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
{
throw new NotImplementedException();
}
public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
{
throw new NotImplementedException();
}
public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
{
throw new NotImplementedException();
}
public override int GetNumberOfUsersOnline()
{
throw new NotImplementedException();
}
public override string GetPassword(string username, string answer)
{
throw new NotImplementedException();
}
public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
{
throw new NotImplementedException();
}
public override MembershipUser GetUser(string username, bool userIsOnline)
{
throw new NotImplementedException();
}
public override string GetUserNameByEmail(string email)
{
throw new NotImplementedException();
}
public override int MaxInvalidPasswordAttempts
{
get { throw new NotImplementedException(); }
}
public override int MinRequiredNonAlphanumericCharacters
{
get { throw new NotImplementedException(); }
}
public override int MinRequiredPasswordLength
{
get { throw new NotImplementedException(); }
}
public override int PasswordAttemptWindow
{
get { throw new NotImplementedException(); }
}
public override MembershipPasswordFormat PasswordFormat
{
get { throw new NotImplementedException(); }
}
public override string PasswordStrengthRegularExpression
{
get { throw new NotImplementedException(); }
}
public override bool RequiresQuestionAndAnswer
{
get { throw new NotImplementedException(); }
}
public override bool RequiresUniqueEmail
{
get { throw new NotImplementedException(); }
}
public override string ResetPassword(string username, string answer)
{
throw new NotImplementedException();
}
public override bool UnlockUser(string userName)
{
throw new NotImplementedException();
}
public override void UpdateUser(MembershipUser user)
{
throw new NotImplementedException();
}
public override bool ValidateUser(string username, string password)
{
bool result = false;
TimeTrackerDataContext context = new TimeTrackerDataContext();
var users = from u in context.TTUsers
where u.UserName == username && u.Password == Protector.Encrypt(password)
select u;
if (users != null && users.ToList<TTUser>().Count > 0)
{
result = true;
}
return result;
}
}
}


Web.config

<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
<sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere"/>
<section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
<section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
<section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
</sectionGroup>
</sectionGroup>
</sectionGroup>
</configSections>
<appSettings/>
<connectionStrings>
<remove name="LocalSqlServer" />
<add name="LocalSqlServer" connectionString="Data Source=.;Initial Catalog=TimeTracker;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<!-- 
Set compilation debug="true" to insert debugging 
symbols into the compiled page. Because this 
affects performance, set this value to true only 
during development.
-->
<roleManager enabled="true"/>
<globalization culture="auto"/>
<membership defaultProvider="TTSMembershipProvider">
<providers>
<clear/>
<add
name="TTSMembershipProvider"
type=" Ada.Tts.Toggle.Web.BC.TTSMembershipProvider, Ada.Tts.Toggle.Web"/>
</providers>
</membership>
<compilation debug="true">
<assemblies>
<add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
</assemblies>
</compilation>
<!--
The <authentication> section enables configuration 
of the security authentication mode used by 
ASP.NET to identify an incoming user. 
-->
<authentication mode="Forms">
<forms name=".Ada.Tts.Toggle_ASPXAUTH" />
</authentication>
<!--
The <customErrors> section enables configuration 
of what to do if/when an unhandled error occurs 
during the execution of a request. Specifically, 
it enables developers to configure html error pages 
to be displayed in place of a error stack trace.
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
<profile>
<properties>
<add name="FriendlyName"/>
</properties>
</profile>
<pages>
<controls>
<add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</controls>
</pages>
<httpHandlers>
<add path="*.asmx" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
<add path="*_AppService.axd" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
<add path="ScriptResource.axd" verb="GET,HEAD" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
</httpHandlers>
<httpModules>
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add name="DomainServiceModule" type="System.Web.Ria.Services.DomainServiceHttpModule, System.Web.Ria, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</httpModules>
</system.web>
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<providerOption name="CompilerVersion" value="v3.5"/>
<providerOption name="WarnAsError" value="false"/>
</compiler>
</compilers>
</system.codedom>
<!-- 
The system.webServer section is required for running ASP.NET AJAX under Internet
Information Services 7.0.  It is not necessary for previous version of IIS.
-->
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules>
<remove name="ScriptModule"/>
<add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add name="DomainServiceModule" preCondition="managedHandler" type="System.Web.Ria.Services.DomainServiceHttpModule, System.Web.Ria, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</modules>
<handlers>
<remove name="WebServiceHandlerFactory-Integrated"/>
<remove name="ScriptHandlerFactory"/>
<remove name="ScriptHandlerFactoryAppServices"/>
<remove name="ScriptResource"/>
<add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</handlers>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/>
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
</system.serviceModel>
</configuration>

 

For more information on implementing a custom roleprovider, see:

http://davidhayden.com/blog/dave/archive/2007/10/17/CreateCustomRoleProviderASPNETRolePermissionsSecurity.aspx

Making the Silverlight 3 .NET RIA Services Business Application, authenticate to SQL Server and not SQLServerExpress

If you’re are using SQL Server Developer edition to develop a Silverlight 3 .NET RIA Services Business Application you might encounter an exception during login:

Load operation failed for query ‘Login’.

at System.Web.DomainServices.ReflectionDomainServiceDescriptionProvider.ReflectionDomainOperationEntry.Invoke(DomainService domainService, Object[] parameters)
   at System.Web.DomainServices.DomainOperationEntry.Invoke(DomainService domainService, Object[] parameters, Int32& totalCount)
   at System.Web.DomainServices.DomainService.Query(QueryDescription queryDescription, IEnumerable`1& validationErrors, Int32& totalCount)
   at System.Web.Ria.Services.QueryOperationBehavior`1.QueryOperationInvoker.InvokeCore(Object instance, Object[] inputs, Object[]& outputs)

This is because the providers make use of the connectionstring with the name [LocalSqlServer] from you’re machine.config by default this contains the .\SQLServerExpress instead of MSQLServer, you can change this by editing the web.config:

<connectionStrings>
<remove name="LocalSqlServer"/>
<add name="LocalSqlServer"  connectionString="Data Source=.;Initial Catalog=YoureTestDb;Integrated Security=True"    providerName="System.Data.SqlClient"/>
</connectionStrings>

Note:

Make sure the “YoureTestDb” contain the “aspnet_…” authentication tables, by using: C:\Windows\Microsoft.NET\Framework\v2.0.50727>Aspnet_regsql.exe

To install all functionality on a specific database use:
“C:\Windows\Microsoft.NET\Framework\v2.0.50727\Aspnet_regsql.exe” -S MyServer -E -d MyDatabase -A all

If you only want to add membership and roles use:

“C:\Windows\Microsoft.NET\Framework\v2.0.50727\Aspnet_regsql.exe” -S MyServer -E -d MyDatabase -A mr

Don’t forget to do an iisreset

see: http://msdn.microsoft.com/en-us/library/x28wfk74.aspx