I’m really quite taken with the preview of RIA Services, as I blogged a couple of weeks ago, but that is not to say that I don’t have some issues with it. One problem I’ve had is when I tried to have my data access and RIA web services in separate assemblies. I think this I quite a normal thing to want to do, because in this case I’m using Entity Framework and I may want to reuse this model in more than one application. My data assembly is called “MyProject.Data” and my web service project is called “MyProject.Web”. I’ve chosen to have the namespaces the same as my project names.
Unfortunately this will not work out of the box with this version of RIA. There is more than one issue with this scenario, actually.
Solving “The type 'MyProject.Data.Customer' cannot be used as type parameter 'TEntity' in the generic type or method 'System.Data.Objects.DataClasses.EntityCollection'. There is no implicit reference conversion from 'MyProject.Data.Customer' to 'System.Data.Objects.DataClasses.IEntityWithRelationships'.”
The first issue is to do with metadata classes RIA uses for annotating validation on fields. The way this works is with a partial class that is generated to complement the entity classes in my data model. However by default they will be generated in the project that contains my domain service, which in this case is not the project that contains my data model. The effect of this is that, as the partial classes are in separate projects, they will be compiled as independent classes in the same namespace “MyProject.Data”… that will of course not compile.
The answer to this problem is to manually move the metadata classes file the is generated for the “MyDomainService” domain service to the project that contains the data model. It will normally be called “MyDomainService.metdata.cs”, where the “MyDomainService.cs” file will contain the domain service itself. After the move things will still not compile immediately; you will need to add the following references to the project containing the data model and metadata class file:
- System.ComponentModel.DataAnnotations
- System.Web.Ria
- System.Web.DomainServices
After that is done your solution should compile and run as expected. You could actually attempt to do it the other way around and actually fix the issue in the project containing the web service (MyProject.Web) instead. This way would involve you creating new empty inheriting partial classes for each of the entities in your data model in an new namespace (like MyProject.Web.Metadata) and changing the namespace of the metadata classes to that same new namespace. If you then change the using statement in the domain service class form the data model namespace (MyProject.Data) to the new namespace (MyProject.Web.Metadata) the conflict should be resolved.
Doing it this way around does mean that your validation annotations and references to RIA don’t need to be in the assembly containing the data model, but does involve a lot more manual work on your part.
Solving “The type or namespace ‘Validators’ could not be found – File MyProject.Web.g”
The next problem I came across when building my app is the use of custom validations. RIA allows you to specify you own validation functions for any field using the [CustomValidation(Type, string)] attribute. The custom validator functions need to be in a separate class file that has to have the “.shared.cs” extension. The class and methods need to be marked with the [Shared] attribute. This ensures that the class will be copied over to the client tier during code generation so that the domain context can access them.
The validator class needs to be in the same assembly and to have the same as the namespace as that of the metadata class (in this case that would be MyProject.Data). But here’s the trouble. At present the code generation process will only look for shared classes in the project containing the web service… so the file needs to be in 2 different projects at the same time?!
Before you start copying the file over and over, consider using a nice feature of Visual Studio called “Add as link”. To use this feature all you have to do is first ensure the validator class file is in the data project. Than go to the web service project and choose “Add Exiting Item”, point to the class file in the data project’s source folder and press the arrow on the Add button in the Add Existing Item dialog box. Select now “Add As Link”. The file will be added to the project as a link, not copied to the source folder.
This means that all changes will happen in both projects so you can’t get out of sync and still the code generator will find the class to copy. Oddly – or not – there will not be a conflict over this file between the MyProject.Web and MyProject.Data projects, even though MyProject.Web references MyProject.Data and the validators are public classes.
After I had solved these 2 problems my app worked without a hitch.
By Nick Verschueren, .Net Solutions Architect