ServiceKnownTypeAttribute doesn't pop up in WSDL - wcf

I have an service Interface:
[ServiceContract]
[ServiceKnownType(typeof(Models.ArticleImage))]
public interface IPhotoManagementService
{
[OperationContract]
bool Login(string username, string password);
[OperationContract]
bool IsLoggedIn();
[OperationContract]
void UpdateImage(string articleID, string selectedImage);
}
As you can see I specify a typeof(Models.ArticleImage) on my ServiceContract.
So building the WSDL of this service should cause ArticleImage to pop up in the WSDL. Unfortunarly this doesn't happen at all. Why is that?
ArticleImage has DataContract on it. And when I return an ArticleImage in my interface, then the WSDL does pick up ArticleImage.
Edit: it doesn't even pop up in the service reference in the consuming project!
This is the result of a lot of testing:
The model I'm trying to add is a LINQ to SQL model.
When I add a normal model with ServiceKnownType it works.
When I use my LINQ to SQL entities in my Interface it works.
When I add my LINQ to SQL entity through ServiceKnownType it doesn't pop up.

Only types used as input/output parameters of service contract operations are published in the WSDL.

Why would it need to? Where does your service expose something that could possibly be an ArticleImage?
Re your comment; when using [ServiceKnownType], the extra trype is still exposed in the "mex" (consumed via "svcutil") - but not by the WSDL. Are you using a WCF client? It should appear (I've just checked... it did). In general, though, returning vague data from a web-service isn't a great idea... sub-types, sure! Dictionary<string,ArticleImage> or even Dictionary<string,SomeBaseType> (with [KnownType] etc), fine! But object, HashTable, etc - aren't a good idea (IMO).
You might also just return a list of your type (List<ArticleImage>) which will work in all scenarios (and be easy for WSDL etc); and let the client make the dictionary at their end.
With regards to LINQ-to-SQL; objects for "mex" need to be decorated with [DataContract] / [DataMember]. You can do this in the designed by toggling the "serialization" property for the dbml. With this set (Serialization Mode = Unidirectional), it should work. To be honest, though, I think you be better-off just adding a dummy method that makes the type explicit on the API.

Related

WCF suppress deserialization of certain operation implementation parameters

I have a WCF service that has an operation that takes any .net serializable client data.
[OperationContract]
void SaveMyData(long id, string name, object serializableData);
[OperationContract]
object LoadMyData(long id, string name);
The server doesn't need to know what the data is, it just stores it or returns what is stored. And the server doesn't even know the types being serialized so of course this contract would result in deserialization exceptions.
I know that I could serialize/deserialize this independently of the WCF contract, for example:
[OperationContract]
void SaveMyData(long id, string name, byte[] serializedData);
[OperationContract]
byte[] LoadMyData(long id, string name);
But this requires additional code on the client to serialize and deserialize. I'd like to avoid that and have the client code as simple as possible.
I know that I could create a pre-build proxy in a client dll that would wrap the WCF calls and perform the additional serialization/deserialization. But I'd rather be able to rely on the clients generated from the WSDL.
Ideally, a RawAttribute could be placed on the parameters or return value which would suppress serialization/deserialization (of the universal root object type) and instead supply or expect an (object)byte[] (or (object)Stream?) from the operation.
[OperationBehavior]
public void SaveMyData(long id, string name, [Raw] object serializableData){ ... }
[OperationContract, Raw]
object LoadMyData(long id, string name);
I've looked at DataContractSurrogate and DataContractResolver but I'm not seeing how to achieve this. DataContractSurrogate seems too late in the deserialization pipeline as the type and deserialized object are already supplied. The resolver doesn't give the data, just the type info. Neither gives information about the parameter being deserialized for which to find the RawAttribute.
Does WCF offer an appropriate extensibility point for this? Or a built-in way?
I would also like to know what the declared type is, as extracted from the serialized data, but that isn't necessary.
Thanks!
Instead to fighting WCF's serialization mechanism, you should drop one level of abstraction and work at the message level of WCF. What you're looking for is a kind of "universal" service that can accept messages from any client. Read through this old but still applicable MSDN article on WCF Messaging. Toward the bottom of the article (figure 8) is sample code for a generic WCF service. That should at least give you a start in creating a service that bypasses serialization.

Effects of XmlIncludeAttribue when it's used in WCF DataContract

1) Does Binding use while creating ChannelFactory makes any difference to how serialization/deserialization works? (I know that binding used should match the server side binding of the service.)
I am using KnownType attribute in one of my DataContract but it does not work. But if I use XmlIncludeAttribute, it works! (I am migrating my ASMX services to WCF.. But I am not using any MessageContracts since I have freedom to update client side proxies too.)
[XmlInclude(typeof(Males))]
[DataContract]
public abstract class Person
{
[DataMember]
public int Name { get; set; }
}
2) If I use any Attribute ( to be specific - XmlInclude)) that uses XmlSerializer for the WCF DataContract, does WCF use XmlSerializer instead of DataContractSerializer?
DataContractSerializer supports everything that XmlSerializer supports, but the reverse is not true. But if a type is decorated with [DataContract], it switches over completely to the new DataContract programming model, completely throwing away support for [Serializable], IXmlSerializable, etc. types that it otherwise would have had.
So your [XmlInclude] magic works only if you're using ASMX and the traditional XmlSerializer. If you're using DataContractSerializer, you have to do known types, and XML-isms like [XmlInclude] and XML attributes are simply not supported. You can still use XmlSerializer instead of DataContractSerializer if you want to, though; all you need to do is decorate the service or operation you want to switch over to XmlSerializer with [XmlSerializerFormatAttribute.]
Hope this helps!

WCF and System.Drawing.Color

Thanks for the quick answers all. But I am looking for an answer and not a workoaround (serialize as string) as I want to know how to use other types from the framework
I am fairly good at WCF but I think I am still at the beginners stage since I cannot serialize a System.Drawing.Color.
This is my Service Contract
using System.Drawing;
using System.ServiceModel;
namespace wcfServer
{
[ServiceContract]
public interface IColorService
{
[OperationContract]
Color DoWork();
}
}
And here is an implementation
public class ColorService : IColorService
{
public Color DoWork()
{
return Color.Yellow;
}
}
However, at the client WCF doesn't use a System.Drawing.Color but it generates it own color type (a struct) ?
The net result is that the color Yellow does not arrive at the client
I thought that this wasn't a problem since the .net Color type is marked with the serializable attribute
Kind Regards, Tom
Colors are usually a mess - there are so many of them. Just convert to color to a 32-bit ARGB structure (the Color class has a method that does this) and use that in your WCF interface. If you want to be extra careful, define your own struct with A, R, G and B (as bytes, WPF has them as doubles, but nobody really needs that), and decouple your service from any specific UI platform.
However, at the client WCF doesn't use a System.Drawing.Color but it generates it own color type (a struct)? [...] I thought that this wasn't a problem since the .net Color type is marked with the serializable attribute
I'm assuming you use basicHttp or wsHttp here. What I'm saying doesn't go for all bindings.
Communication between a WCF service and client has nothing to do with .NET. Keyword is interoperability. The client doesn't have to be written in .NET, it might very well be a PHP or Java or whatever kind of client.
WCF therefore uses SOAP to send and receive data, which all major programming languages implement. So to let a service and client exchange data, a format for that data has to be defined. You can't say "Hey, I'm gonna send a System.Drawing.Color", since that may very well not be a valid class or struct definition in the client's language.
So your service defines a WSDL, containing a schema definition, where the contents of the Color struct will be copied from System.Drawing.Color. It won't be linked to the .NET framework from the point it gets serialized and sent over the wire.
I was able to fix this problem by using "KnownTypeAttribute" on a data contract. So you can try "ServiceKnownTypeAttribute" on a service contract like this :
[ServiceContract]
[ServiceKnownType(typeof(System.Drawing.Color))]
public interface IColorService
{
[OperationContract]
Color DoWork();
}
This works fine assuming that the client code is also using .NET.
The strategy with "KnownType" worked well in my project http://www.nquotes.net/ and let me avoid additional serialization hassle. They should have included Color as one of the base types (as they do with Guid, for example, which is "known" automatically - http://msdn.microsoft.com/en-us/library/ms731923.aspx ).

Request/Response pattern in SOA implementation

In some enterprise-like project (.NET, WCF) i saw that all service contracts accept a single Request parameter and always return Response:
[DataContract]
public class CustomerRequest : RequestBase {
[DataMember]
public long Id { get; set; }
}
[DataContract]
public class CustomerResponse : ResponseBase {
[DataMember]
public CustomerInfo Customer { get; set; }
}
where RequestBase/ResponseBase contain common stuff like ErrorCode, Context, etc. Bodies of both service methods and proxies are wrapped in try/catch, so the only way to check for errors is looking at ResponseBase.ErrorCode (which is enumeration).
I want to know how this technique is called and why it's better compared to passing what's needed as method parameters and using standard WCF context passing/faults mechanisms?
The pattern you are talking about is based on Contract First development. It is, however not necessary that you use the Error block pattern in WCF, you can still throw faultexceptions back to the client, instead of using the Error Xml block. The Error block has been used for a very long time and therefore, a lot of people are accustom to its use. Also, other platform developers (java for example) are not as familiar with faultExceptions, even though it is an industry standard.
http://docs.oasis-open.org/wsrf/wsrf-ws_base_faults-1.2-spec-os.pdf
The Request / Response pattern is very valuable in SOA (Service Oriented Architecture), and I would recommend using it rather than creating methods that take in parameters and pass back a value or object. You will see the benefits when you start creating your messages. As stated previously, they evolved from Contract First Development, where one would create the messages first using XSDs and generate your classes based on the XSDs. This process was used in classic web services to ensure all of your datatypes would serialize properly in SOAP. With the advent of WCF, the datacontractserializer is more intelligent and knows how to serialize types that would previously not serialize properly(e.g., ArrayLists, List, and so on).
The benefits of Request-Response Pattern are:
You can inherit all of your request and responses from base objects where you can maintain consistency for common properties (error block for example).
Web Services should by nature require as little documentation as possible. This pattern allows just that. Take for instance a method like public BusScheduleResponse GetBusScheduleByDateRange(BusDateRangeRequest request); The client will know by default what to pass in and what they are getting back, as well, when they build the request, they can see what is required and what is optional. Say this request has properties like Carriers [Flag Enum] (Required), StartDate(Required), EndDate(Required), PriceRange (optional), MinSeatsAvailable(Option), etc... you get the point.
When the user received the response, it can contain a lot more data than just the usual return object. Error block, Tracking information, whatever, use your imagination.
In the BusScheduleResponse Example, This could return Multiple Arrays of bus schedule information for multiple Carriers.
Hope this helps.
One word of caution. Don't get confused and think I am talking about generating your own [MessageContract]s. Your Requests and Responses are DataContracts. I just want to make sure I am not confusing you. No one should create their own MessageContracts in WCF, unless they have a really good reason to do so.

Adding a new parameter to a WCF operation: choices?

What's the best way to handle adding a new (optional) parameter to an existing operation without requiring the client to update their WSDL? I do not want to update the namespace to describe a new version of the service contracts, since this should be backwards compatible with older clients.
Should I add a new operation with a new parameter, as an overload? Or should I just add the parameter to the existing operation?
Here is my operation:
[OperationContract]
MyResponse GetData();
Should it be:
[OperationContract]
MyResponse GetData();
[OperationContract]
MyResponse GetData(string filter);
Or more simply, just change it to this:
[OperationContract]
MyResponse GetData(string filter);
The latter option seems best, and according to my reference book, "The impact on client is none. New parameters are initialized to default values at the service." Is WCF initializing it to the the so-called default value? If so, what is the default value?
One thing to take into consideration is that you can't have two OperationContracts with the same name. The way it's serialized it will throw an error.
The best approach is to go with Option 3 (just adding the new parameter) and within the method logic account for it being a null value for those clients that haven't updated yet. If it's a breaking change that the clients will need to update for, make sure to not have the entire application die because of the exception.
Well, changing an existing contract after it's been used is really against all rules of service orientation; you should never ever break an existing contract.
In reality, this happens quite frequently, and WCF is pretty good about handling that for you. As long as you only introduce non-breaking changes, existing clients will continue to work.
This can be:
a new operation contract on an existing service contract
a new non-required field on a DataContract
What you're trying to do is not going to work, though
you cannot have two method with the same name in WCF - WCF is not .NET and you cannot have two methods by the same name being different only by their signature. Doesn't work. You'll need to use two separate, distinct names. Remember: your WCF method calls will be translated into a WSDL (web service description language) document to describe the service - and WSDL simply does not support having two operations with the same name - just a difference in signature is not supported and will not work.
you cannot change the existing contract, e.g. you cannot introduce a new parameter into a method call after the fact, without breaking the contract.
So what you really need to do is this:
[OperationContract]
MyResponse GetData();
[OperationContract]
MyResponse GetFilteredData(string filter);
Any other change you suggested will a) break the contract, or b) simply not work in WCF:
you can try this:
[OperationContract]
MyResponse GetData();
[OperationContract(Name = "GetDataByFilter")]
MyResponse GetData(string filter);