Client side code is not generated for XElement properties - wcf

My domain service has invoke operation method and returns a custom
type say 'User'. This class has many properties such as String,
Integer, Boolean, XElement. When I rebuild the solution to generate
client-side proxy, it generates code for the class User in the client
for all the properties, except for XElement. What is the fix for this?
Will RIA not generate any code for XNode or XElement types? Should
these elements be converted to String? Are there any fixes for this
error?
I'm using VS2010 SP1, .Net Framework 4, WCF RIA, Silverlight 5.

According to the Silverlight DataContract documentation, you can mark your classes as either opt-in using the DataContract/DataMember attributes or opt-out and rely on only serializing public scope class members. You need to show the code of the class you're having problems with to get better suggestions.

Related

Share POCO types between WCF Data Service and Client Generated by Add Service Reference

I have a WCF Data Service layer that is exposing POCO entities generated by the POCO T4 template. These POCO entities are created in their own project (i.e. Company.ProjectName.Entities) because I'd like to share them wherever possible.
I have a set of interfaces in another project (Company.ProjectName.Clients) that reference these POCO types by adding an assembly reference to the Company.ProjectName.Entities.dll. One of the implementation of these interfaces is a .NET client that I want to consumes the service using the WCF Data Service Client Library.
I've used the Add Service Reference to add service reference. This generated the DataServiceContext client class and the POCO entities that are used by the service. However, these POCO types gemerated by the Add Service Reference utility now have a different namespace (i.e. Company.ProjectName.Clients.Implementation.WcfDsReference).
What that means is that the POCO types defined in the interfaces cannot be used by the types generated by the utility without have to cast or map.
i.e. Suppose I have:
1. POCO Entity: Company.ProjectName.Entities.Account
2. Interface: interface IRepository<Company.ProjectName.Entities.Account>{....}
3. Implementation: ServiceClientRepository : IRepository<Company.ProjectName.Entities.Account>
4. WcfDsReference: Company.ProjectName.Clients.Implementation.WcfDsReference
& Company.ProjectName.Clients.Implementation.WcfDsReference.Account
Let's say I want to create a DataServiceQuery query on the Account, I won't be able to do this:
var client = new WcfDsReference(baseUrl);
var accounts = client.CreateQuery<Company.ProjectName.Entities.Account>(...)
OR: client.AddToAccounts(Company.ProjectName.Entities.Account)
, because the CreateQuery<T>() expects T to be of type & Company.ProjectName.Clients.Implementation.WcfDsReference.Account
What I currently have to do is to pass the correct entity to the CreateQuery method and have to map the results back to the type the interface understands. (Possible with a mapper but doesn't seems like a good solution.)
So the question is, is there a way to get the Add Service Reference utility to generate methods that use the POCO types that are in the Company.ProjectName.Entities namespace?
One solution I am thinking of is to not use the utility to generate the DataServiceContext and other types, but to create my own.
The other solution is to update the IRepository<T> interface to use the POCO types generated by the utility. But this sounds a little bit hacky.
Is there any better solution that anyone has come up with or if there's any suggestion?
Ok, a few hours after starting the bounty I found out why it wasn't working as expected on my end.
It turns out that the sharing process is quite easy. All that needs to be done is mark the model classes with the [DataServiceKey] attribute. This article explains the process quite well, in the 'Exposing another Data Model' section
With that in mind, what I was trying to do is the following:
Placing the model on a separate class library project C, sharing it with both webapplication projects A and B
Create the data service on project A
Add the service reference on project B
Delete the generated model proxies out of the service reference, and update it to use my model classes in project C
Add the DataServiceKey attribute to the models, specifying the correct keys
When I tried this it did not work, giving me the following error:
There is a type mismatch between the client and the service. Type
{MyType} is not an entity type, but the type in the
response payload represents an entity type. Please ensure that types
defined on the client match the data model of the service, or update
the service reference on the client.
This problem was caused by a version mismatch between project C (which was using the stock implementations on the System.Data.OData assemblies) and the client project B that was calling the service (using the Microsoft.Data.OData assemblies in the packages). By matching the version on both ends, it worked the first time.
After all this, one problem remained though: The service reference procedure is still not detecting the models to be shared, meaning proxies are being created as usual. This led me to opt out of the automatic service integration mechanic, instead forcing me to go forward with a simple class of my own to serve as the client to the Wcf Data service. Basically, it's a heavily trimmed version of the normally autogenerated class:
using System;
using System.Data.Services.Client;
using System.Data.Services.Common;
using Model;
public class DataServiceClient : DataServiceContext
{
private readonly Lazy<DataServiceQuery<Unit>> m_units;
public DataServiceClient(Uri _uri)
: base(_uri, DataServiceProtocolVersion.V3)
{
m_units = new Lazy<DataServiceQuery<Unit>>(() => CreateQuery<Unit>("Units"));
}
public DataServiceQuery<Unit> Units
{
get { return m_units.Value; }
}
}
This is simple enough because I'm only using the service in readonly mode. I would still like to use the service reference feature though, potentially avoiding future maintenance problems, as evidenced by the hardcoded EntitySet name in this simple case. At the moment, I'm using this implementation and have deleted the service reference altogether.
I would really like to see this fully integrated with the service reference approach if anyone can share a workaround to it, but this custom method is acceptable for our current needs.

Flex unable to find definition for type from WCF Service?

I have a WCF Service running SOAP and allowing Flex / Flash to connect to it using basicHttpBinding by using the 'Data' \ 'Import Web Service' option. Unfortunately when I consume and invoke this service within Flex it throws the following error...
Error: Cannot find definition for type
'http://schemas.datacontract.org/2004/07/System.Drawing::Size' at
mx.rpc.xml::XMLDecoder/decodeType()
...when using the following code...
// This will return an array of presentations
var service:PresentationAuthoring = new PresentationAuthoring();
var token:AsyncToken = service.getAllPresentationByClientId(
mClientId , mUserId , mWCFServiceHash );
token.addEventListener( ResultEvent.RESULT, onResult );
token.addEventListener( FaultEvent.FAULT, onFault );
This method returns an array of Presentation objects that are retreived by the service. At the moment there are no DataContracts and I'm allowing the POCO Presentation object to be serialised and punted out by the service that works fine. However, this class has a readonly property of the type System.Drawing.Size that derived from appropriate height and width properties. Looking through the generated code, it doesn't register a 'Size' class in the base import schema although it still seems to create a Size class.
An alternative has been to stop the derived property from being serialised using the [XmlIgnore] but that has not worked.
Ideally, I need a way of allowing my Flex application to communicate with my WCF service but it seems to choke on the System.Drawing.Size type and while I could change this, there are other framework types such as Point, Rectangle, etc, etc. that are utilised within the project. Has anyone else experienced this problem or can suggest an alternative approach to take?
[Please note that the WCF Service functions correctly when a .NET application consumes it.]
Kind regards and thanks in advance - S
Well the answer was to box the Size struct with a custom class that worked perfectly although it is somewhat irksome I might have to do this with (potentially) other native drawing structs. Ho hum.

Validating parameters with WCF, Unity and VAB

I am developing an application that exposes a WCF service using the Message/Response pattern for service methods. The application is using Unity 2.0 for dependency injection and the Validation Application Block from MS Patterns & Practices. I've already gotten Unity tied into WCF using a custom HttpModule I picked up from several website a while back and everything works great.
In my service interface I have a method such as:
DoSomethingResponse DoSomething(DoSomethingRequest request)
I can easily attach VAB attributes to the service contract to verify that 'request' is never null but I also want to validate the contents of the request object.
To do this, I inject the validator into the DoSomethingRequest constructor and include an internally scoped IsValid property which handles interacting with the VAB validator. Unfortunately, this constructor doesn't get called because WCF deserializes the object and constructors aren't used.
Without getting into the merits of having the request object be a simple DTO versus having some server-side business logic, is there a way to cleanly inject dependencies into an object passed into WCF service as an argument?
If I'm understanding your issue correctly, you have properties on DoSomethingRequest that are instances of some other classes (data contracts) and you want to validate your data contracts as well? Is there some reason you can't just apply validation attributes to your data contract classes as well? This is the approach I've used when using WCF with VAB integration and it's worked out quite nicely.
So it turns out that adding the validation attributes to my DataContract actually works with no additional code. Unfortunately, it doesn't work if validation is defined in the app's config file (app.config or web.config).
As a result, I've stripped out the constructor injection and IsValid property on my DataContract (request object) which makes it more of an annotated DTO which I think is preferred anyway. I only wish that it would work the same with the XML configuration.

.NET webservice using an instance of a parameter type?

I have a Windows forms project and a Web Service project in my solution, and I'm trying to call the web service and return a customer object as the result. The problem is that when I try to receive the return object, I get an error that it can't convert it. For example, here is the signature for my webservice:
Public Function GetDriverByID(ByVal DriverID As Integer) As Driver
And here is the code I'm using to call it:
Dim d As Driver = mywebserviceinstance.GetDriverByID(1)
But I receive this compile-time error (wsDrivers is the name of the web reference I've added to my form project): "Value of type ProjectNamespace.Common.wsDrivers.Driver cannot be converted to ProjectNamespace.Common.Driver"
This "Common" namespace contains the Driver class, and I'm not sure why the return class from the web service isn't just a generic "Driver", but is instead a "wsDrivers.Driver", and I can't convert it back. Anybody know how I can deal with this type mismatch?
EDIT: Thanks for the explanations - this actually makes it clear what it's doing. However, is there any way that I can force it to use the actual type instead of the proxy (or, rather, is there any way to convert between the "real" instance and the "proxy" instance), or do I have to serialize the properties before I send them over the wire, and then manually de-serialize the return values?
This is actually pretty common. What's happening is that the Web Service has defined in it the definitions of all the types used in the web service. When you add a reference to that web service, it auto-generates a proxy type in a sub namespace of your namespace. That is what is being returned by your web service when you call it.
However, you probably are also referencing the same library that the web service does seperately that contains the same type. That is the type that is expected when you Dim Driver. That's why there is a mismatch.
The web service reference in a VB.NET or C# project can reference any type of web service and is not limited to those provided by ASP.NET. That is why Visual Studio creates proxy classes for each object which can be retrieved from the web service.

.NET base type cannot be serialized by WCF

I'm writing a WCF service and want to expose some custom configuration elements (e.g. Custom ConfigurationSection and ConnectionStringSettings) so that I can modify the service's configuration.
One of my custom configuration elements inherits from System.Configuration.ConfigurationElementCollection. When I try to start my WCF service I get the following error message...
Type 'System.Configuration.ConfigurationElementCollection' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute.
Is there a way to implement the DataContract for this Type? I have my inherited class marked with the [DataContract] attribute.
Just hit this issue today. It was confusing because the problem came up moving a project from machine to machine. This article seems relevant:
http://blogs.msdn.com/youssefm/archive/2009/08/10/serializing-plain-old-clr-objects-poco-types-with-datacontractserializer.aspx
To summarize in case of link rot, the issue seems to emerge in runtime 3.5 and go away in runtime 3.5 SP1.
Ok, well in the end I had to re-architect my solution. I found the SerializableConfigurationSection most beneficial. It's in the patterns and practices EnterpriseLibrary. So rather than trying to pass my Custom Configuration Sections through WCF, I perform the seralization/deserialization manually and pass the configuration sections through WCF as a string.