I have some WCF services which employes default DataContractSerialization. Some of the service methods return Dictionary objects. One of the clients are generating XSD files from WCF services (biztalk related) and he is requesting to convert all dictionary types to a new dictionary type which implements IXmlSerializable.
I wonder, if there will be any unexpected results of this conversion which may affect the DataContract serialization somehow?
Update:
Server and client share the same domain dlls, clients do not generate them from service. Maybe in the question I was missing the main point; I wonder if an object is to be serizalized through datacontract serialization, implementing IXmlSerializable in the object will cause any problems.
Is your client sharing dlls with the service?
Unless he is sharing libraries (dlls) with service then making changes at the service end won't make any difference. Your WCF is returning data, not classes. That data is being reconstituted into classes which are created by the client based on the definitions in the WSDL your service returns. You can't control those generated libraries (by making chnages on the server) unless you share dlls between the client and the server.
If he wants to wrap the generated dictionaries in an IXmlSerializable dictionary then he can, or if he wants to generate a different type of dictionary then he can probably do that as well, but I don't think there is anything you can do server side.
Tell your client to use the following serializable dictionary when they need to serialize a dictionary result from a service call: C# Serializable Dictionary – a Working Example
It accepts an ordinary dictionary as constructor argument thus converts any dictionary into a serializable one. You can also return SerializableDictionary type as the service call result if you like.
There is an unexpected problem; since domain objects are already implementing data contract serialization, there is no way to implement IXmlSerializable without modifying the whole serialization mechanism.
Related
I need to generate or define new class based on deserialization serialized class. So I want to transfer class definition from server to client to have access to it's properties later.
Is it possible and how?
Proper way to do it would be to either expose a schema definition for your service for clients to consume & generate strongly type class definitions from that or provide a DLL with your DTO contract definitions (class/interface definitions) to the client.
If you chose neither of those approaches (no schema & no dll with interfaces) but still
want to generate a class definition, you can in an improper way generate .cs class definitions, from a sample data of the service (call the services couple of times and intercept the responses or use some http client). However this approach does not guarantee that you will get an accurate or/and complete generation. Basically you can go from:
XML->XSD->C# cs class file (or even XML to C# cs file directly)or JSON->C# class file
And deserializing object to dynamic especially when you don't own both the server & client code is pretty much the worst thing you can do. And this way you didn't transfer you class definition to the client. Deserializng to dynamic objects is actually no desrialization at all as matter of fact, it gives you a dictionary of strings with syntactical sugar to access them as properties at runtime with not compile time support which can be equal to a disaster. In short don't do it unless you own all the code (not that it's a good idea then either but maybe you could get by somehow)
One portable way to transfer the property definitions and the data itself is to use the JSON serializer.
You can deserialize into a dynamic object using JSON.Net
Deserialize json object into dynamic object using Json.net
In our project we are consuming WCF webservices exposed at Central location as services with basicHttpBinding.
In client desktop application we need consume those webservices. I am able to generate proxy class using WSDL.exe.
But, I need to convert data/class given by the webservice into my local class, for that now I am xmlserialzing those class/objects given by webservice and deserializing into my local classes as both classes schema matches exactly same.
Is there any better way that I can follow?
or
Do I need to assign each property from one class to another?
thanks
nRk.
declare class manually instead of generating. This is the most DRY solution.
try Automapper
If you have control on your local classes (they are not generated code; or you are generating them, yourself) you can use xml attributes to decorate your class, so you can serialize and deserialize it to that xml you work with and you do not have to have specific names for your properties. In addition to this, you may have additional properties on your local class.
If you have not control on defining your local classes, then you have to define a converter or as elder_george mentioned, use AutoMapper.
Using a manual written converter IMO is the fastest way and you can define them as implicit converter operators on your local class.
I've done the serialize/deserialize thing myself just as you had. If your classes have the same properties as the proxy classes you could write a helper method that uses reflection to iterate through the properties of the proxy and set the corresponding properties of your class. As long as the property names are the same, that one method should work on all classes.
A few thoughts:
use assembly sharing via WCF; this allows you to use the same actual assembly at both ends. As long as this is a DTO assembly, this is fine (not hugely portable, though). This is /reference (also /r) in svcutil.exe, or you can do it via the IDE
use DataContractSerializer and round-trip (like you are already; just that WCF maps most closely to DataContractSerializer, not XmlSerializer)
I have a class with a read-only property defined. In my code I define this as a property with a getter only.
I want to be able to send this object back and forth across a web service. When I call a "Get" method in the service, it would be populated with a value on the service side. Once I define this property, I don't want the consumer of the web service to be able to set/change this property.
When I add a reference to this web service to a project, the object has the property serialized a few different ways depending on how I try to define the object on the service side:
internal setter: Creates the property in the WSDL. Visual Studio generates a class with both a getter & a setter for this property.
no setter: Does not create the property in the WSDL. Visual Studio then obviously does not define this property at all.
Read-only public member variable - Does not create the property in the WSDL. Again, Visual Studio will not do anything with this property since it doesn't know about it.
Allowing the consumer of the web service to set a value for this property will not cause any harm. If the value is set, it is ignored on the web service side. I'd just prefer if the consumer can't change/set the property to begin.
Is there any way to define a property as read-only? Right now we're using C#/.NET 2.0 for the web service, and (for now at least) we have control over all of the consumers of this service, so I can try changing configurations if needed, but I prefer to only change things on the web service and not the consumers.
I can be wrong, but I think the problem here is how serialization works - in order to deserialize an object the serializer creates an empty object and then sets all the properties on this object - thats why you need a setter for the properties to be included in serialization. The client code has the same "interface" to the object as the deserializer.
Caveat, I am a Java guy so the first part of my answer focuses on what may be possible in C#.
Firstly, with a custom serializer in Java, you can do almost anything you want, including directly setting values of a protected or private field using reflection so long as the security manager doesn't prevent this activity. I don't know if there are analogous components in C# for the security manager, field access, and custom serializers, but I would suspect that there are.
Secondly, I think there is a fundamental difference in how you are viewing Web services and the Web service interface as part of your application. You are right-click generating the Web service interface from existing code - known as "code first". There are many articles out there about why WSDL first is the preferred approach. This one summarizes things fairly well, but I would recommend reading others as well. While you are thinking in terms of a shared code library between the client side and server side of your Web service and maintaining object structure and accessibility, there is no such guarantee once you publish an API as a Web service and don't have control over all of the consumers. The WSDL and XSD serve as a generic description of your Web service API and your server and client can be implemented using different data binding configurations, object classes, or languages. You should think of your Web service interface and the XML that you pass in and out of it as describing the semantics of the exchange, but not necessarily the syntax of the data (your class structure) once it is internalized (deserialized) in your client or server.
Furthermore, it is advisable to decouple your transport related structures from your internal business logic structures lest you find yourself having to refactor both your server implementation, your Web service API, and your (and other's) client implementations all at the same time.
There's no built-in way to do this in .NET 2.0 as far as I know. In cases where I wanted to serialize a read-only property, I've implemented the IXmlSerializable interface so that I could control the ReadXml() and WriteXml() methods.
In later versions of the .NET framework, you can serialize read-only properties by setting an attribute on the backing field.
Does WCF support generic collections?
I looked at the proxy object, and it seems to generate object array from a generic list collection.
Thanks
WCF does support generic collections. Over the wire it is transfered as an array of objects (this is the standard way of sending lists/arrays/etc), but WCF does the serialization/deserialization for you, so as far as your client/server are concerned, the collections are generic.
Edit: a caveat is, of course, that the collection has to be serializable. Also, take a look at this if you asking your question because your custom collection is being treated as an T[] on the client.
When you add/edit the service client, if you click on the "Advanced ..." button you will see an option allowing you to choose the collection type your service client will create. The default is System.Array, but you can change it to System.Collections.Generic.List (along with many other choices).
http://msdn.microsoft.com/en-us/library/bb514724.aspx
Using generics are fine as long as you are using WCF at both ends. If you haven't already; you must carefully consider the scenarios where a non-wcf client might need to use your services.
Should I bind directly to objects returned from a webservice or should I have client-side objects that I bind to my gridcontrols? For instance if I have a service that returns object Car should I have a client side Car object that I populate with values from the webservice Car object?
What is considered best-practice?
In C# do I need to mark my classes as serializable or do something special to them?
This is a good question, which follows the sames lines as two questions I have asked myself:
Large, Complex Objects as a Web Service Result.
ASP.NET Web Service Results, Proxy Classes and Type Conversion.
Both of these may be a worthwhile read for you.
Heres my two bits:
Try to keep the return types of your Web Services to primitives where possible. This not only helps reduce the size of the messages, but also reduces complexity at the receiving end.
If you do need to return complex objects, return them as a raw xml string (I'll explain below).
What I then do is create a seperate class which represents the object and handles it's xml. I ensure the class can be instantiated from and serialized to xml easily. Then both projects (the web service and the client) can reference the DLL with the concrete object in, but there is none of the annoying coupling with the proxy class. This coupling causes issues if you have shared code.
For example (using your Car class):
Web Service (CarFactory) method BuyCar(string make, string model) is a factory method that returns a car.
You also write a Mechanic class that works on Car objects to repair them, this is developed without knowledge of the Web Service.
You then right a Garage class for your application. You add a web reference to the CarFactory service to get your cars, and then add some Mechanic's to your garage and then crack your knuckles and get ready to get some cars from the factory to get them working on.
Then it all falls over, when you get the result of CarFactory.BuyCar("Audi", "R8") and then tell your Mechanic.Inspect(myAudi) the compiler moans, because the Car is actually of type CarFactory.Car not the original Car type, yes?
So, using the method I suggested:
Create your Car class in its own DLL. Add methods to instantiate it and serialize it from/to XML respectively.
Create your CarFactory web service, add a reference to the DLL, build your cars as before, but instead of returning the object, return the XML.
Create your Garage adding a reference to the Mechanic, Car DLL and the CarFactory web service. Call your BuyCar method and now it returns a string, you then pass this string to the Car class, which re-builds its object model. The Mechanic's can happily work on these Car's too because everything is singing from the same hymn sheet (or DLL?) :)
One major benefit is that if the object changes in its design, all you need to do is update the DLL and the web service and client apps are completely decoupled from the process.
Note: Often it can be useful to then create a Facade layer two work with the web services and auto-generate objects from the XML results.
I hope that makes sense, if not, then please shout and I will clarify .
This really depends on what you are getting from the web service. If they are simple data transfer objects and you are only displaying data, then yes, you can bind. If you plan to edit the objects, it may not be usefull as you will need to track changes.
Do your objects and/or collections on the client track changes? If so you can use them.
If you have no change tracking, then you will need to track changes yourself, so you may need to translate the objects or wrap them in something to track changes.
Again, it really depends on what you are getting, what they support, what you are doing with them, as well as what response the server wants back for changes.
One thing you can do is to create client classes corresponding to the web service data contracts with any additional functionality that you want and set the web service reference to reuse existing types. Then there is no reason to create an additional wrapper class to bind to.
If you bind directly to the Web service types, you're introducing a coupling. Should the Web service change in future, this may have undesired side-effects that mean lots of code changes.
For example, what if you're using .asmx Web services today, then shift to WCF tomorrow? That might mean quite a few changes through your code if you've used types that WCF won't serialize.
It's often better in the long run to create specific client-side objects and then translate to and from Web service data contract types. It may seem a lot of work, but this is often repaid greatly when it's time to refactor, as your changes are localised in one place.
If you are the owner of both the web service and the client.
And you need the parameters of the web service calls to be complex classes which contain not only data but also behavior (actual coded logic) then you are in a bit of a pickle when developing these web services using web service frame works.
As suggested in the answer by Rob Cooper you can use pure xml as web service parameters and xml serialization, but there is a cleaner solution.
If you are using Visual Studio 2005 (probably applies the same for 2008), You can customize the way VS creates you proxy as described in this article:
Customizing generated Web Service proxies in Visual Studio 2005
This way you can tell VS to use your own classes instead of generating a proxy class.
Well when I think of it, it's pretty much same solution as proposed by Rob Cooper, with the little twist, that you wont be writing a Facade layer your self but will be using VS itself as this layer.