Returning shared types using Data Contracts in WCF
I have a type, TestResult, in an assembly and this assembly is used by two applications. I also have a WCF service that is hosted in one application (Win Service) which exposes a method that returns an instance of this开发者_运维问答 TestResult type.
Although this works would it be considered good practice to only ever return Data Contact types? There may be other applications, in the future, that may need to use this service and I would ideally like to remove the need to ship a DLL with an application just so it can use the service.
The beauty of DataContracts (and sometimes their curse) is that VS can create an object that will fulfill the DataContract, without you having to make your implementation public. So, if you don't want to ship the DLL, fine; when consumers of your service add the service reference, VS creates its own TestResults object that implements ITestResults and defines accessors for the DataMembers.
Note that, because of this behavior, it is best to make DataContract implementations "anemic"; you cannot define business logic that will convey to a generated implementation, so it is generally best to set them up as containing only fields or simple properties. That way your service can make no assumptions about what any generated class will be able to do on the other side.
EDIT: If the class or interface that is the ServiceContract exposes the method that returns the TestResult as an OperationContract, then TestResult MUST be a DataContract and any properties or fields of interest must be DataMembers. It's not best-practice, it's flat required. On the other side of the coin, regardless of the method's visibility in server-side code, if the method is not an OperationContract, then it's not visible to the client, and TestResult doesn't have to be a DataContract UNLESS some other OperationContract method accepts or returns an instance of TestResult.
You have stated that you return a TestResult as the result of your service call. Actually, what it sounds like is that your OperationContract returns a DataContract class that looks just like a TestResult, and you are returning the TestResult. That indicates to me that there is an implicit conversion specified between TestResult and TestResultDataContract, or some behavior in a higher level that clones the TestResult into the TestResultDataContract. That's fine; the conversion happens before returning, and the DataContract is still what actually comes out of the service method. You may want to document what's happening if you return a TestResult from a method specifying it returns your TestResultDataContract type.
The other possibility is that you aren't really calling the service as a remote WCF service through the generated client proxy; you're just instantiating and calling the class that actually implements the service. I've seen it happen many times; all it takes is a reference to the implementation class instead of the proxy, and say hello to bugs in the production environment that you didn't see in dev. Provided that you REALLY ARE using the client proxy, it's perfectly fine to reference the same TestResult implementation (or its DataContract-decorated brother) in the client code, provided you have access to the DLL containing that contract on the client. However, the whole point is that that's not necessary; if you do not have an object matching the DataContract signature of the service, one will be created for you.
Maybe I'm misunderstanding, but it sounds like you should define TestResult as a DataContract, and continue returning that type from your service operation as normal. For applications that have access to the binary representation of the type (the DLL), they can reference that DLL and use the service the same way you do it today.
For future use cases where it is NOT possible (or practical) for them to have a binary representation of the DataContract, you can expose a MEX endpoint (and/or use the serviceMetadata behavior) that will allow a consumer to build their own copy of the DataContract. An example of this process would be the "Add Service Reference" - this sucks in the metadata for your service and builds a local copy of the DataContracts, among other things.
Yes, I would consider it a best practice for your services to only expose/consume defined DataContracts or native types (like string).
精彩评论