Silverlight 3 and RIA Services – The advanced things

My last article was about the basics of RIA Services. This article goes about the more advanced things in RIA Services. This article contains a few things that make the usage of RIA Services in more advanced scenario’s possible.

  • Complex Types in RIA Services
  • RIA Services in a separate class library
  • RIA Services and Out of browser mode
  • RIA Services on a different host

Using Complex Types in RIA Services

In my other article I just made use just a string as input parameter and a string as output parameter. It’s however very well possible to use custom types instead. There’s hower one prerequisite for those custom types.

  • Each Custom Type needs to have one property decorated with a KeyAttribute. This is required for input and output types.

I created a WorldRequest and a WorldResponse which fits nicely in the example for HelloWorld.

public class WorldRequest
{
    [Key]
    public string Name { get; set; }
}

public class WorldResponse
{
    [Key]
    public string Greeting { get; set; }
}

This can be used in the HelloWorldDomainService just like you would do in a normal class.

[EnableClientAccess]
public class HelloWorldDomainService : DomainService
{
    [ServiceOperation]
    public WorldResponse HelloWorld(WorldRequest worldRequest)
    {
        return new WorldResponse { Greeting = string.Format("Hello {0}.", worldRequest.Name) };
    }
}

After compilation those custom types get generated in the Silverlight project as well as we saw in my previous article. The Custom Type is now overloaded from Entity. And has a specific method called GetIdentity. This has something to do with the KeyAttribute that’s required to add to one property inside a custom types. Although this is probably necessary for integration with the Entity Framework it doesn’t make sense in my example.

[DataContract(Namespace="http://schemas.datacontract.org/2004/07/MM.Ria")]
public sealed partial class WorldRequest : Entity
{
    
    private string _name;
    
    [DataMember()]
    [Key()]
    public string Name
    {
        get
        {
            return this._name;
        }
        set
        {
            if ((this._name != value))
            {
                this.ValidateProperty("Name", value);
                this.RaiseDataMemberChanging("Name");
                this._name = value;
                this.RaiseDataMemberChanged("Name");
            }
        }
    }
    
    public override object GetIdentity()
    {
        return this._name;
    }
}

We can now easily use this generated class as we would have done in different scenario’s.

var helloWorld = new HelloWorldDomainContext();
helloWorld.HelloWorldCompleted += HelloWorldHelloWorldCompleted;
helloWorld.HelloWorld(new WorldRequest{Name = "Mark Monster"});

And in the EventHandler we have to cast the ReturnValue property to the WorldResponse type. Again I hope they make InvokeEventArgs a generic type so that we don’t have to cast this ReturnValue and have it return the correct type.

private void HelloWorldHelloWorldCompleted(object sender, InvokeEventArgs e)
{
    Debug.WriteLine((e.ReturnValue as WorldResponse).Greeting);
}

Move code for the RIA Service to a class library

Next thing that came in my mind was the fact what if I want to share my RIA Services with other people? Do they need to have the source or is a different approach possible?

Luckily it’s possible to create class library (standard .NET) add references to a few dlls.

image

After that just move your RIA Service code in there. This library can now be used in any Web project that’s linked to a Silverlight application. Just add a reference to the new library containing your RIA Service and while building code will get generated in your Silverlight application.

image

What about using RIA Services in the Out of browser mode?

It just works. I didn’t have to do anything to make the Out of browser version communicate with the RIA Services.

When the host running the RIA Services is different from the url hosting the Silverlight application?

Of course in some scenario’s the RIA Services are hosted on a different location than the Silverlight application itself. Of course you have to remind yourself about cross domain issues, so make sure the host has a clientaccesspolicy.xml or crossdomain.xml file in place.

When we take a closer look into the generated code we’ll find a default constructor and a constructor where you can specify the service URI.

/// <summary>
/// Default constructor.
/// </summary>
public HelloWorldDomainContext() : 
        base(new HttpDomainClient(new Uri("DataService.axd/MM-Ria-HelloWorldDomainService/", System.UriKind.Relative)))
{
}

/// <summary>
/// Constructor used to specify a data service URI.
/// </summary>
/// <param name="serviceUri">
/// The HelloWorldDomainService data service URI.
/// </param>
public HelloWorldDomainContext(Uri serviceUri) : 
        base(new HttpDomainClient(serviceUri))
{
}

We can now make use of the constructor which accepts a serviceUri to connect to the RIA Service that’s running at a different location. The tricky part however is the DataService.axd/MM-Ria-HelloWorldDomainService/ part. Besides DataService.axd it contains also the namespace and type name for the RIA Service, but instead of using dots to separate the namespace parts and the type name dashes are used. But for the easy parts, just copy it from the generated code I would say.

var helloWorld = new HelloWorldDomainContext(new Uri("http://myhostruningsomewhere.com/DataService.axd/MM-Ria-HelloWorldDomainService/", UriKind.Absolute));
helloWorld.HelloWorldCompleted += HelloWorldHelloWorldCompleted;
helloWorld.HelloWorld(new WorldRequest {Name = "Mark Monster"});

Ps. This article is cross posted on: Mark Monster’s blog and Silverlight Help.

  • Gravatar Przemek April 6th, 2009 at 09:24
    Hi Mark,
    excellent job, however I have a comment regarding the editing part of your blog entries in general. I see that there is a utility strip in the top-right corner of every code insert. This utility strip (which has the printer icon and others) in most cases hides portions of your code, thus making it unreadable. Would it be possible to remove it?
    regards, Przemek
  • Gravatar Devika June 5th, 2009 at 09:05
    Could you please share the code of example you explained here? Basically i want to know how we can move the ria service code to classlibrary.

    Thanks in advance
  • Gravatar Dennis August 22nd, 2009 at 13:58
    I have been trying to get the RIA code to work in another webapplication too. I followed the instructions but it didn't work. I was wondering where to place the connectionstring. I put it in the website that hosted the silverlight application. In the same webapp, I added a reference to the dll containing the RIA code, built and run the application. But no data showed up. According to this article 'while building code will get generated in your Silverlight application.' This didn't happen.

    Also, if this works I want to take it one step further. I want to use the original XAP file in Sharepoint. This means that a solution where code is generated in the silverlight app will not do because I want to use the original code.
  • Gravatar Todd Morrison August 23rd, 2009 at 19:20
    Hey, thanks for the example. Super cool...

    Next question:
    how do we return a collection of custom types. I can't get Array, Generics, or IQueryable wrappers to return.. keep getting the good ole'

    Service operation named '' does not conform to the required signature. Both return and parameter types must be an entity type or one of the predefined serializable types.
  • Gravatar Mark Monster August 25th, 2009 at 12:45
    @Todd

    I'm not sure, but did you try IEnumerable<T> to return from your service operation? Or EntityList<T>? Please try it, and if it still doesn't work, try to get help from the Silverlight forums.
  • Gravatar Dennis August 27th, 2009 at 17:28
    Mark,

    Can you please elaborate on how to move the code for the RIA service to a class library? I have tried it but cannot get it to work. Thanks
  • Gravatar Angarola September 13th, 2009 at 13:29
    Hey, thanks for the example. Super cool...

    Next question:
    how do we return a collection of custom types. I can't get Array, Generics, or IQueryable wrappers to return.. keep getting the good ole'

    Service operation named '' does not conform to the required signature. Both return and parameter types must be an entity type or one of the predefined serializable types....
  • Gravatar Danijel Stulic October 12th, 2009 at 10:16
    @Dennis, @Devika, There is a documentation on RIA services with detailed explanation how to move code for the RIA service to class library. Basically, either you are missing http handler in web.config or you are missing reference from web application to newly created class library for web. Also, you can examine exception which should provide more details where the problem occurred.
  • Gravatar Thomas Arnold March 18th, 2010 at 14:25
    ServiceOperation Attribute has renamed to Invoke.
  • Gravatar Mark Monster March 18th, 2010 at 14:50
    Thanks Thomas,

    I have to admit, this article is outdated, it's almost a year old.
  • Gravatar Matt May 4th, 2010 at 20:28
    Mark,

    I know this is an old article but I have a question about hosting RIA Services on a domain that is different than the silverlight app. How did you get around the RiaContext problem re: the Authentication service? I can't find anywhere to jack in a URI for that service.
  • Gravatar Jairo December 14th, 2010 at 02:49
    This does not work on RIA services for silverlight 4, any ideas or hints on how to do it work on the latest version?
Gravatar