Silverlight

Verbose steps to migrate a Silverlight application from .NET RIA Services (July 09) to WCF RIA Services (PDC 09)

These are the steps I had to go through to migrate a Silverlight application that was running on the .NET RIA Services preview released in July 09, to the new WCF RIA Services released during PDC 09:

  1. Delete all HttpHandler references to DataService.axd from your web.config. Basically, these two need to go:
    <system.webServer>
      ...
      <handlers>
        ...
        <add name="DataService" verb="GET,POST" path="DataService.axd" type="System.Web.Ria.DataServiceFactory, System.Web.Ria, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      </handlers>
    </system.webServer>
    <httpHandlers>
      ...
      <add path="DataService.axd" verb="GET,POST" type="System.Web.Ria.DataServiceFactory, System.Web.Ria, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false" />
    </httpHandlers>
  2. Add/update your web.config along the lines of:

    .NET 3.5:

    <?xml version="1.0"?>
    <configuration>
      <system.web>
        <httpModules>
          <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.webServer>
        <modules>
          <add name="DomainServiceModule" preCondition="managedHandler" type="System.Web.Ria.Services.DomainServiceHttpModule, System.Web.Ria,Version=2.0.0.0,Culture=neutral,PublicKeyToken=31BF3856AD364E35"/>
        </modules>
      <system.webServer>
      <system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
      </system.serviceModel>
    </configuration>

    .NET 4.0:

    <?xml version="1.0"?>
    <configuration>
    
      <system.web>
        <httpModules>
          <add name="DomainServiceModule" type="System.Web.Ria.Services.DomainServiceHttpModule, System.Web.Ria, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        </httpModules>
        <compilation debug="true" targetFramework="4.0" />
      </system.web>
    
      <system.webServer>
        <validation validateIntegratedModeConfiguration="false"/>
        <modules runAllManagedModulesForAllRequests="true">
          <add name="DomainServiceModule" preCondition="managedHandler"
              type="System.Web.Ria.Services.DomainServiceHttpModule, System.Web.Ria, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        </modules>
        <validation validateIntegratedModeConfiguration="false" />
      </system.webServer>
    
      <system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
      </system.serviceModel>
    </configuration>
  3. If you’re throwing DomainServiceException, take note that the class has been renamed to DomainException. Update your code accordingly.
  4. Remove any reference you may have to System.Web.DomainServices.Providers.dll, you will need to add a new reference to either System.Web.DomainServices.EntityFramework.dll or System.Web.DomainServices.LinqToSql.dll depending on what you use.
  5. Change this:
    using System.Web.DomainServices.LinqToEntities;

    To this:

    using System.Web.DomainServices.Providers;

    Everywhere.

  6. The DomainService.Context property has been renamed to ObjectContext. Update all your code accordingly.

     

    Now, your Web application should build, but you may still get this error while building the actual Silverlight application:

    Error    5    The "CreateRiaClientFilesTask" task failed unexpectedly.
    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: The AutoGenerateField property has not been set.  Use the GetAutoGenerateField method to get the value.
       at System.ComponentModel.DataAnnotations.DisplayAttribute.get_AutoGenerateField()

    In my case, this was a problem with the System.ComponentModel.DataAnnotations.dll reference. Remove it and re-add it from the Global Assembly Cache.

  7. Remove the reference to System.Windows.Ria.Controls.dll and add one to System.Windows.Controls.Ria.dll.
  8. You will need to update your XAML to reference the new assembly:

    Replace System.Windows.Ria.Controls with System.Windows.Controls.Ria in your namespace declarations in the header of the XAML file. Here’s how the old ones look:

    xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Ria.Controls" xmlns:System_Windows_Data="clr-namespace:System.Windows.Data;assembly=System.Windows.Ria.Controls"
  9. RiaContext (.Current) has been renamed to WebContextBase. It’s in the System.Windows.Ria namespace.
  10. The System.Windows.Ria.Data namespace has been removed. So make sure to remove it from your usings also.
  11. RiaContext.Current.User is now WebContextBase.Current.Authentication.User
  12. In XAML, the namespace for the ControlParameter type has changed to System.Windows.Controls from System.Windows.Data, update accordingly.
  13. If you use Forms Authentication, update the RiaContext reference in App.xaml to a WebContext reference such as:
    <Application.ApplicationLifetimeObjects>
        <app:WebContext>
            <app:WebContext.Authentication>
                <appsvc:FormsAuthentication/>
                <!--<appsvc:WindowsAuthentication/>-->
            </app:WebContext.Authentication>
        </app:WebContext>
    </Application.ApplicationLifetimeObjects>

With some luck, your project should be migrated to WCF RIA Services now. These were the steps I needed to get mine working.

Additional breaking changes in the new release can be found here.

Good luck!

Workaround for Silverlight RIA Services DateTime discrepancy between server and client

While working on a Silverlight application. I discovered that all the dates displayed in my DataGrid were skewed by a few hours from the real date stored in the database. Upon a closer look I noticed this skew was closely correlated to the time difference between the server’s time zone and the UTC date.

I needed my Silverlight application to display and use the exact same dates as the database regardless of the time zone my users were in.

Apparently, there’s a little known bugfeature” in the latest RIA Services Beta for Silverlight that involves dates:

RIA uses JSON to send data across the wire, and the Microsoft JSON serializers always serialize dates as UTC.

Dates retrieved from the database always seem to come up as DateTimeKind.Unspecified, meaning that the serializer will take a guess and treat them as local dates (in the server’s local time zone) and convert them to UTC time before sending out on the wire.

There’s an overridable property in the DomainService class called UsesUtcDateTimes which should in theory make the serializer leave your dates alone by treating them as UTC – which is still not ideal, but it means it won’t change them further – the property, however, currently doesn’t do anything.

The gotcha here is that the original time zone of the date is lost on the wire. It’s not sent along with the date so there’s no way you could determine, on the client, what time zone the date was in originally!

Example: if the server’s timezone is GMT+1, a date of December 21, 2012 12:21 PM will be converted to the UTC (GMT+0) date of December 21, 2012 11:21 AM before being sent out!

The Silverlight application will now display the UTC date of December 21, 2012 11:21 AM instead of the expected date from the database.

The easy workaround…

… is to mimic the behavior of the currently un-implemented UsesUtcDateTimes property and fool the serializer into thinking all of your dates are already in UTC so it doesn’t mess with them. Thanks to partial classes, you can do this.

Create new partial classes for each of your RIA Data Classes that hold DateTime values and override the On(DateTimePropertyName)Changed() methods like the following:

public partial class MyDataClass
{
    partial void OnDateChanged()
    {
        _Date = DateTime.SpecifyKind(_Date, DateTimeKind.Utc);
    }

    partial void OnOtherDateChanged()
    {
        _OtherDate = DateTime.SpecifyKind(_OtherDate, DateTimeKind.Utc);
    }
}

(Notice the partial keyword on the methods as well, not just on the class.)

The technically correct workaround…

.. is to pass the original time zone, as a property, along with the UTC DateTime across the wire, and then re-apply the time zone to it on the client before using it.

I’m hoping for a future RIA Services release to address this issue better, and perhaps pass the time zone across by itself.

UPDATE: This appears to be fixed in the latest release of WCF RIA Services. This workaround is no longer necessary unless your application still uses the older .NET RIA Services.

I have written a verbose guide on upgrading an application to WCF RIA Services. Check it out here.