It Matters Where WCF Generates Your Proxy Class
Posted by Keith Elder | Posted in WCF | Posted on 15-08-2007
I just ran into a weird situation and I’m documenting it so I think I’m crazy later on. I have the following method in a WCF service which basically returns a List<> of data contracts.
public GetRuleSetsByCategoryIdResponse GetRuleSetsByCategoryId(GetRuleSetsByCategoryIdRequest request)
{
RuleSetLogic logic = new RuleSetLogic();
List<RuleSet> ruleSets = logic.GetRulesByCategoryId(request.CategoryId);
GetRuleSetsByCategoryIdResponse response = new GetRuleSetsByCategoryIdResponse();
response.RuleSets = ContractTranslator.TranslateBetweenRuleSetDataContractAndRuleSet.TranslateRuleSetListToRuleSetDataContractList(ruleSets);
return response;
}
There is nothing weird or fancy about the service. It just returns a collection of data contracts. When I first generated the proxy for this service I added a service reference to the Winform project (right clicked project, add service reference). The above collection of RuleSets got returned as a BindingList<RuleSetDataContract>. To me that was weird, I had expected it to be RuleSetDataContract[]. Basically an array of objects. It was weird but I lived with it whilst I was prototyping.
Later as I fleshed my app out more I moved my proxy class into a C# class library all on its on. When I generated the proxy class from a plain old C# class library class, the BindingList<RuleSetDataContract> collection was in fact replaced with an array of RuleSetDataContracts! If someone cares to go deep on this and explain why you would get two totally different types of proxy classes generated for me I’m all ears. Right now I’m in the coding zone and have to get done so let me leave you with my fix so I can get back to coding.
In the end what I really wanted to deal with were generic lists (List<Object>). Instead of using VS2005 to generate the file I shelled out to the Visual Studio command prompt and ran this command:
svcutil /d:. /noconfig /o:OrbbService.cs /r:DataContracts.dll /ct:System.Collections.Generic.List`1 http://localhost:57199/MyService.svc
Here is the break down of what these switches mean:
- /d – working directory
- /noconfig – don’t generate the config file (duh)
- /o – filename for generated code
- /r – Used to specify assemblies that might contain types representing the metadata being imported
- /ct – fully qualified name of the type to use as a collection data type when code is generated from schemas
By running the above command I now have everything the way I really want it with List<Object> for all of the return types. Life is good. I can now continue my regularly scheduled programming.
Hi Brent,
It is exactly what you said, but if you generated a proxy in a Console Application class and you got the string[] type, and you add System.Windows.Form dll reference to the Console Application and generate again, you still got string[] type. So I think it is not the System.Windows.Form problem.
Nice catch David. I confirmed your observation. I had a similar incident with the BindingList<T> object. I generated a proxy in a Windows Form class and I got the BindingList<T> instead of a string[] type. I removed the System.Windows.Form dll reference from C# Project, DELETED my existing proxy and regenerated the proxy again and then I got the string[] type.
I’m not positive about this, but it may have to do with WinForms vs. a class library. I typically generate in a plain old class library, and I always get the array of type generated (Type[]). I just generated in a WinForms app and got the BindingList<T>. I’m assuming the difference is because VS assumes you are going to bind the data to a UI element, and so gives you the extra functionality available in a BindingList<T> object. /shrug
Interesting…
You have me curious on this one. I will do a little investigation and see what I can find.
I knew you would chime in Mr. WCF 🙂 Actually I generated them both in the same manner. Right clicked on the project and added a Service Reference. I didn’t generate them from the command line in either case. Yet I got two very different generated versions. So your statement of “always get a BindingList<T> in your proxy” is exactly what I didn’t get.
Hey Keith,
When you generated the proxy that used an array rather than BindingList, did you manually create it via svcutil without specifying /ct? If so, I probably understand why you got two different types of collections.
If I am not mistaken, VS2005 always uses /ct:System.ComponentModel.BindingList`1 when it executes svcutil behind the scenes. Consequently, you will always get a BindingList<T> in your proxy when you use the Add Service Reference context menu from within the IDE. If you directly use svcutil and do not specify /ct, it will default to using an array.
Hope this helps with your sanity. 🙂
If you were in a coding zone, wouldn’t pausing to blog about this have ruined your focus?