7

On the server side of my Silverlight solution, I have 2 projects.

  1. Website that serves up the Silverlight page.
  2. A Entity Framework data access layer.

I have a entity with FirstName and LastName properties on it. I want to add a FullName property that will be available from the Silverlight client side.

I have added the property:

namespace Server.DAL.Model
{
    public partial class Contact
    {
        public string FullName
        {
            get
            {
                return string.Format("{0} {1}", this.FirstName, this.LastName);
            }
        }
    }
}

When tested from the server side, this new property is present and working correctly. The property is NOT present on the Silverlight client side. I tried adding a metadata class with the Include attribute but since string is a primitive type, I get the following error on compilation:

The property 'FullName' in entity type 'Contact' cannot be marked with the IncludeAttribute because 'String' is not a valid entity type. Entity types cannot be a primitive type or a simple type like string or Guid.

How can I make this property available to the Silverlight client?

DaveB
  • 9,470
  • 4
  • 39
  • 66
  • In your xxDataService.cs file on the server side, in one of the methods that deals with Contact, does your code compile if you reference the FullName property? On the client side, if you look in the *.Web.g.cs file in the Generated_Code folder, can you find the Contact class and see if the FullName property is there or not? – hatchet - done with SOverflow Jul 19 '11 at 19:03
  • @hatchet - No, the FullName property is not present in a method that deals with the Contact entity. There is only 1 property named EntityKeyPropertyName and 3 methods. The *.Web.g.cs file is empty. – DaveB Jul 19 '11 at 19:19
  • 1
    Did you add [DataMember] to your FullName property? Here are some instructions on adding methods/properties to ComplexTypes. They might apply to entities as well. Maybe using a buddy class, I haven't tried this for entities. http://thegrayzone.co.uk/blog/tag/wcf-ria-services/ – Derek Beattie Jul 19 '11 at 20:22
  • @Derek Beattie - I added the [DataMember] attribute and it works. You should make this comment into an answer. – DaveB Jul 19 '11 at 21:43

4 Answers4

6

Add [DataMember] to your FullName property. Here are some instructions on adding methods/properties to ComplexTypes. They might apply to entities as well. Maybe using a buddy class, I haven't tried this for entities.

namespace Server.DAL.Model
{
    public partial class Contact
    {
        [DataMember]
        public string FullName
        {
            get
            {
                return string.Format("{0} {1}", this.FirstName, this.LastName);
            }
        }
    }
}
Derek Beattie
  • 9,429
  • 4
  • 30
  • 44
1

You should put the code you have shared into a file called Contact.shared.cs. The WCF RIA tooling takes this code exactly and creates a file in the Silverlight project with that code. The client-side code then has access to this member and a duplication of the code compiled in the server project.

Here is more information on shared code in the MSDN docs.

Ed Chapel
  • 6,842
  • 3
  • 30
  • 44
0

I assume you're using RIA Services? If so, the problem is that RIA Services will only copy the structure of your server side classes to the client, not any custom code you've written within properties or methods.

The good news is, the solution is simple and you're almost there. RIA Services generates the client-side classes as partial classes, just like Entity Framework does on the server. That means you can extend those classes in the Silverlight project using partial classes in exactly the manner you did on the server project.

Simply move your class from the server project to the Silverlight project, make sure your namespace matches the namespace of the class RIA Services generated for you, and you'll be good to go.

Good luck!

Michael Ames
  • 2,607
  • 1
  • 16
  • 22
  • In his case, RIA services doesn't need to get the logic of FullName to the client. If it exposes it as a public property, and executes the logic on the server, the computed value should be transmitted to the client, and become available for use there, as long as the client side model exposes the value as well. That said, I usually do this as a client side partial class as you've suggested. – hatchet - done with SOverflow Jul 19 '11 at 19:49
  • Interesting. I can't say I've ever tried extending the class on the server in order to propagate computed values to the client. Could be advantageous if you were developing a single service for multiple clients, because you wouldn't have redefine FullName for every client. But I like the client side approach, too, because a) it's always worked for me, and b) I think of the Silverlight project as the presentation layer, and computing something like FullName is, to my mind, a presentation issue! – Michael Ames Jul 19 '11 at 19:56
  • @Michael Ames - I would be open to a client side solution. I am using the MVVM pattern. Could you post some sample code? – DaveB Jul 19 '11 at 20:29
  • I could, but perhaps my explanation isn't clear, because there really isn't anything more I could show you than the code you've already written. You had the exact right idea, using a partial class to extend Contact. The only thing you need to do differently is extend the version of Contact that RIA Services generated for you, which lives in the Silverlight project, rather than extending the version that the Entity Framework generated for you, which lives in you server project. – Michael Ames Jul 19 '11 at 20:39
  • You will accomplish this by literally moving the partial class definition you already wrote from the Server project to the Silverlight project. Drag and drop, baby! The only caveat is that RIA may have generated the client-side version of the Contact class in a different namespace from the one you defined it in. In that case, you'll need to change your namespace definition to match. – Michael Ames Jul 19 '11 at 20:41
  • You don't need any special [Attributes] or other modifiers on your partial class. Contact.FullName will be compiled as a first-class citizen of the Contact class, just like Contact.LastName and Contact.FirstName. It'll show up in Intellisense, you can bind it to a TextBlock or a DataGrid column, etc., etc., etc. That's really all there is to it. – Michael Ames Jul 19 '11 at 20:44
0

IMHO I think adding the property to the datamodel isn't the best approach as I like to keep the model clean (and not implementation specific so my entities work across various projects without clutter from other projects). The way I address this issue is using Extension Methods. Here is the EXACT same scenario (from my code) using extension methods instead of adding it to the datamember.

namespace <MyAppName>.Services.Entities
{
  public static class UserExtension
  {

    public static String FullName(this User user)
    {
        return String.Format("{0} {1}", user.First, user.Last);

    }
  }
}

Note the parameter of the method and its definition (i.e. this isn't a normal method definition). I have a "Common.dll" that holds the base routines for my application that is always referenced...so I place the extension methods in that DLL. I also ensure that the Namespace of the extension methods match exactly the namespace of the entities. If you do that, the method will appear on the entity as if it was part of the entity.

The only downside to this is you have to implement it as a method and cannot define it as a property....which means no direct data binding. But your ViewModel or an IValueConverter can handle that pretty trivially.

Mike S.
  • 402
  • 1
  • 3
  • 13