My service uses a type Foo defined in another DLL, and my client also uses that DLL to get that type. Rather than generating a proxy class for that type, I'd like the proxy code to just refer to the real type. I can accomplish this manually by generating the proxy with WSDL.EXE on the running service, manually editing out the partial class Foo definition from it, and adding a Using statement. I'd like to do it without hand-editing if possible.
It seems like maybe the answer is to use SVCUTIL.EXE instead of WSDL.EXE. There are two intriguing options: /R and /ET. I tried putting /ET:Foo and /ET:My.FQN.Util.Foo, and /ET:www.my.com.the.servicenamespace.Foo, and also adding the DLL filename to the option. But nothing changes in the ServiceWithFoos.cs proxy class that gets created. The partial class definition for Foo is still there.
Am I on the right track? What am I doing wrong?
Add [DataContract(Namespace = "http://anything.here")] to your Foo type, then use svcutil with the /r option taking the path of the library containing Foo. This way svcutil should see the same contract namespace and map Foo correctly.
Related
Although this is a long question the coding and testing part should be really easy to reproduce.
I have created two separate Class Libraries in C# and I think I am running into a name collision problem caused by existing registry keys from my previous projects and trials.
Here are my two classes:
using System;
using System.Runtime.InteropServices;
namespace Test
{
[InterfaceType(ComInterfaceType.InterfaceIsDual),
Guid("ED5D264B-1D80-4A5D-9C14-8297D90B7037")]
public interface ITest
{
// body
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("8B261B92-8EC5-4CDC-A551-67DEB42137FF")]
[ProgId("Test.TestClass")]
public class TestClass : ITest
{
// body
}
}
and
using System;
using System.Runtime.InteropServices;
using ADODB;
namespace Test
{
[InterfaceType(ComInterfaceType.InterfaceIsDual),
Guid("ED5D264B-1D80-4A5D-9C14-8297D90B7037")]
public interface IConnection
{
// body
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("8B261B92-8EC5-4CDC-A551-67DEB42137FF")]
[ProgId("Test.Connection")]
public class Connection : IConnection
{
// body
}
}
I have Exposed .Net Components to COM like this:
In order to access the assemblies from Excel I have added the ADODB references to the assembly, ticked make assembly COM visible and register for com interop. Also, I've added references to each *.tlb file(2 files for two projects) so I can access them using an early binding and use VBA Intellisense.
I have followed the same procedure on another machine and I can use early binding using the Connection as class.
I am thinking there are some old registry keys I haven't deleted on my original machine which will not allow me to use Connection as the class name in VBE. I've manually scanned my registry and deleted everything I could think of related to my project.
I have also deleted the project entirely and used a 3rd party software to scan registry for missing dlls however that didn't help:/
Removed all previously registered GUIDs and applied new ones each time I created a new Project (just in case)
Created new projects using different namespaces and class names (using ADODB;) I haven't been able to use early binding yet like this Test.Connection therefore I am assuming I have a name collision problem. I am suspecting the name class Connection to be causing it although I am not 100% sure.
The Test.TestClass namespace in VBA:
I can declare and use instances of the TestClass type in two ways using early binding:
Dim x as Test.TestClass
Dim x as TestClass
Now going into VBE Object Explorer F2 the TestClass is properly displayed in comparison to other libraries and general idea of using COMs.
However, when I want to use the Test.Connection library I am unable to use early binding following the same pattern as TestClass because the generated *.tlb file automatically changes(renames) the ProgId's. So, instead I have to bind it like this
Dim x As Test.Test_Connection
Dim x As Test_Connection
and the Object Explorer displays the names using _ (underscores) and not . (dots), which is easy to explain why this happens - keep reading :)
As it stands I am sure it is not the VBE environment that changes the names to avoid collisions. It is the VS' *.tlb generator.
I went to the assembly folder and opened both *.tlb files in Notepad++. I can clearly see that the *.tlb for the Test.Connection library already includes the names with the _s unlike the Test.TestClass which has .s
I have tried to manually edit the *.tlb file but as its a mixed binary file it takes some effect but also causes Excel to stop responding in some weird ways so I have to avoid this method.
I think I have explained well what the problem is and where it comes from. Now my question is: Are there any attributes to use in C# code to tell the *.tlb generator not to override my ProdIds? Are there any alternative ways of manipulating *.tlb files? Is this issue a name collision and is it avoidable without changing the name of Connection class?
I'm sorry for such long question but I have been digging and digging for almost a week now and I still cant solve this.
Note: In VBA ( or VBE Object Explorer ) using IntelliSense ctrl+space it does not seem that either Connection or Recordset have been used. Since they are not already reserved in the VBE environment I recon it has to do with my library itself.
As a reference to why this issue has been raised here, please see VBA equivalent to C# using or VB.NET imports creating aliases
Thank you very much for your time!
Do avoid focusing on the ProgId. You are not actually using it, the dialogs that you made a screenshot of show the actual class names, not the ProgId.
Getting the class name renamed to "Test_Connection" is normal behavior for the type library exporter. It will do so whenever it detects a conflict with another interface or class name that has the same name. You are certainly increasing the likelihood of this happening by also having a dependency on ADODB, it also has a Connection class. A very trivial solution is to simply rename your own type.
Your code snippet cannot reproduce this problem. But of course it is incomplete, we can't see what you are really doing in the code. You'll bring in the dependency on ADODB if any of your public methods use a type from this type library. Also note that there are non-zero odds that this will happen by accident. You might have written a method that intended to use your own Connection type but the compiler resolved it to the ADODB type.
An essential tool to debug this is Oleview.exe, run it from the Visual Studio Command Prompt. First create the type library for your C# assembly with Tlbexp.exe. Then use File + View Typelib, you'll see the content of your type library expressed in the IDL syntax. You'll have little trouble recognizing the mapping of your C# types to the IDL declarations.
Pay attention to the importlib directives at the top of the file. They should look like this:
// TLib : // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
importlib("mscorlib.tlb");
// TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");
There should only be those two. The first one imports the .NET types, defining _Object. The second one imports standard COM types, like IDispatch. If you see additional ones here then you increase the odds of a name collision.
This IDL also gives you a way to solve the problem, in case it is unsolvable, you can edit it to name the types the way you want them. Save it to a .idl file. And compile it with midl.exe /tlb to generate a type library with your preferred names. Do note that this is not something you want to have to do often.
I have 2 WCF services (different projects) sharing a class library with a MyExceptions defined.
Both services uses:
[OperationContract]
[FaultContract(typeof(MyException))]
void op();
When I add both references in the client project I get:
Type namespace.MyException already defines a member called MyException
with the same parameter types.
Basically the classes has the same name so the constructor is defined twice.
Any Idea of how to change the Exception namespace?
Please note that:
I am using svcutils
the namespace option doesn't work.
Thanks
Create the proxy using svcutil /reference:SharedLibrary.dll. This way svcutil won't generate classes that it finds in the SharedLibrary.dll, so the client uses the class definitions from the assembly.
Don't forget to add a reference to the DLL in the client project, if you haven't already done so.
Besides the namespace suggestion what can be done is to edit the proxy code generated by SVCUTIL and remove the duplicate code for the MyException class.
The steps:
1. Create a proxy file for Service1.
2. Create a proxy file for Service2.
3. Add the proxies to the client.
4. Compile and it gives error for having MyException already being declared.
5. Edit either one of the proxies and remove the MyException class code.
I have several message contracts that use an external library to standardize a particular functionality between several services. Their code looks somewhat like this...
using System.ServiceModel;
using Query.Search;
[MessageContract(WrapperName = "MyMessageContract")]
public partial class MyMessageContract
{
[MessageBodyMember(Name = "Search")]
public SearchTerms Search { get; set; }
}
The SearchTerms class is in the Query.Search DLL and looks like so...
public class SearchTerms : List<SearchTerm> { }
... with the SearchTerm class also in the same DLL. It works just fine in the service and knows that I'm addressing the Query.Search classes, but when I generate the proxies, these classes are reassigned to the wrong namespace and make it very difficult to build a service adapter in the UI. I'm using svcutil with the following arguments...
/t:code /mc /n:*,MyProject.UI.Proxies /ct:System.Collections.Generic.List`1 /l:cs
/o:WSProxies.cs /config:output.config http://localhost:49207/Service1.svc?wsdl
http://localhost:49207/Service2.svc?wsdl http://localhost:49207/Service3.svc?wsdl
Now, I understand that the namespace argument as it's defined here is basically assigning all my proxy namespaces to MyProject.UI.Proxies and if I remove it, the namespaces for my Query.Search class are set correctly. However, this means that all the other proxies now fall under the default "MyService.DataContracts" namespace in which they're defined. So I tried using...
/n:MyService.DataContracts,MyProject.UI.Proxies
... but had no luck as the output reverts to "MyService.DataContracts" after it's generated. What I'd like to be able to do is for my proxies to have the UI namespace of "MyProject.UI.Proxies" while maintaining the namespace for the SearchTerms class as "Query.Search" without manually modifying the output file so a new run of svcutil doesn't wipe out the manual changes. Is this possible and am I just using the /namespace argument wrong, or will I have to manually modify the output file every time I generate proxies?
EDIT: After a fruitless day of trying to get this working, I simply created a workaround, creating a set of similar classes in the services and translating them to the Query.Search ones. Would still be interested to know if what I wanted can be done but form what I've gathered, using these classes in a message contract sort of dooms it to be listed under the same namespace as the MC.
You should tell svcutil to reuse your classes instead of fighting with proxy namespaces.
This is achievable using /reference parameter.
It also will be good idea to move all such classes to separate assembly. Otherwise you will have direct reference between WCF server and client what is not good architecturally.
Check this link for sample:
http://blogs.msdn.com/b/youssefm/archive/2009/10/09/reusing-types-in-referenced-assemblies-with-svcutil-s-r-switch.aspx
You also can do the same task in Visual Studio. See my answer here:
How to use a custom type object at the client
Update:
I did some investigation. You are right SVCUtil does not generate proxy classes if you references assembly that contains all interfaces and data contracts.
That behavior is different from Visual Studio. Visual Studio seems to not use SVCUtil work with WCF directly.
This is command line I tried:
C:\Windows\system32>svcutil /directory:D:\prog\myfolder /r:"D:\prog\SampleWcf\Server\bin\Debug\Contract.dll" http://localhost:8080/Service/mex
One difference from your code is that I used metadata instead of wsdl.
You have two options:
Generate proxies in Visual Studio.
Work with Service without profies using ChannelFactory
BasicHttpBinding myBinding = new BasicHttpBinding();
EndpointAddress myEndpoint = new EndpointAddress("http://localhost/MathService/Ep1");
ChannelFactory myChannelFactory = new ChannelFactory(myBinding, myEndpoint);
IMath wcfClient1 = myChannelFactory.CreateChannel();
http://msdn.microsoft.com/en-us/library/ms734681.aspx
This is my service generated class:
public partial class MyClass : object,
System.Runtime.Serialization.IExtensibleDataObject,
System.ComponentModel.INotifyPropertyChanged
{ }
I'm using my own service. In MyClass I have overridden ToString() but I don't have it in my client. I want either to generate it or as MyClass is partial am I able to override ToString myself?
I know that I can write in generated .cs file. What is the best way to do it and at all should I do it?
If you are defining both the client and the service, you don't need to use the WSDL-generate classes. Move the shared objects into a separate assembly, and reference it from both client and server projects. When you create the service reference, there's an "advanced" option (which I think is on by default) that reuses any known classes from the WSDL instead of generating new ones.
Even better, if you move the service contract into your shared library, you don't even need to create the service reference, you can just call the ChannelFactory directly and eliminate the entire auto-generated proxy class.
I have a demonstration on how to do both of these things on my blog: http://blog.kutulu.org/2012/03/proxy-free-wcf-ditching-proxy.html
If you absolutely need to use the WSDL from the service (e.g. you don't have control over the service side and it could change on you), then you can extend the partial classes that VS creates (as you suggested). Most auto-generate classes you get from VS these days are partial classes specifically to make this kind of extension possible. The downside, of course, is that nothing guarantees client and server's additional partial class methods are the same. I'd definitely consider this a last-resort option.
If you share the dll where overriden method exixts between client and server project, you can use the method. By default, WCF generates each class with only properties declared in the service interface. No method is generated.
You can just create a seperate dll file and put what you want to share between service and client into this dll; and add this dll as a reference to both client and service projects. By default, when you generate the proxy, it will not auto generate the shared classes.
I've got a situation where I have several web services that I need to consume. I need the ability to perform custom actions in the constructor of the proxy before any calls are made (assigning the configured URL, assigning the SOAP header, etc.).
My first solution is to create a child class that derives from the generated proxy, then make those actions in the constructor of the child class. That way, app code can call the constructor of the child, and get a valid proxy that has the stuff I need.
I'm trying to prevent the app code from calling the constructor of the generated proxy, so people don't accidentally instantiate the proxy without doing my custom stuff. My first thought is to move the generated code into a separate assembly from the child, and make sure the app code only has a reference to the child assembly. This works for the most part, but...
The services contain complex types, defined in the proxy. I need the app code to reference these classes, which means the app code needs a reference to the base assembly anyway, which means they now have access to the generated constructor.
I've tried an overly-complex solution of wrapping each of the generated complex types in an interface, and then hiding the real calls and replacing them with copies of the object as the interface type. This worked once or twice, but it gets ugly really quick.
It seems that the only way I can have everything I want is to remove the public constructor of the generated proxy, and replace it with a protected constructor, then allow a reference to this assembly - they'll be able to work with the complex types, but won't be able to call the constructor. My problem is that the only way I can think of to do this is to manipulate the generated code to change the constructor.
Any ideas? I'm using WSDL.exe to generate the proxies, and there's no option there to hide the constructor. Is there another way that I'm just missing? I suppose I can write a tool to automatically modify the proxy immediately after it's generated, but that just feels ugly to me.
Thanks
Are you stuck using .NET 2.0? If not, then you shouldn't be using WSDL.EXE. You should be using SVCUTIL.EXE or "Add Service Reference".
Instead of creating a derived class, you should create your own wrapper classes, which use the proxy classes. One would use something like MyWrapper.CreateProxy(), which would return a properly-configured instance of the proxy class.
BTW, WSDL.EXE creates proxies using the legacy "ASMX" technology, which has no ability to use the types from the service.
I ended up going with modifying the proxy generated code to make the constructor protected instead of public. The call to WSDL.exe was handled in an automated project already, so it wasn't that big of a deal. This was really the only way I could get everything I wanted.
Instead of doing that, why can't you override the GetWebRequest method? It will be called before the service method call anyways.
If you have added a service reference, implementing message inspector will do same thing.