Intercept messages in a WCF Client - c#

Has anyone got any experience with Web Service Extensions? I spent time trying to make a web service extension from the MS examples.
I have an .net 3.5 web service client, built by adding a reference to the WSDL, via the VS IDE "Project > Add Service Reference". This built my web service client, and all works OK.
I need to intercept the request and response body for my web service client. I have found lots of references to Web Service Extensions, but am having an attack of the tired, and just can't get my extensions to fire.
I've used the MS example from here "How to implement a SOAP extension" ( http://msdn.microsoft.com/en-us/library/7w06t139.aspx) , which builds a logger for the request / response streams.
The related MS article "Soap Message Modification" (http://msdn.microsoft.com/en-us/library/esw638yk(VS.85).aspx) shows how to enable the SOAP extension for the web client:
Implementing the SOAP Extension
There are two ways to run a SOAP extension on either a client or server application. First, you can configure the application to run the extension. To configure your SOAP extension to run for all Web methods on all Web services, especially a vroot, edit the <soapExtensionTypes> Element section within the Web.config file. The following code shows that the type attribute value must be on one line and include the fully qualified name of the extension, plus the version, culture, and public key token of the signed assembly.
<configuration>
<system.web>
<webServices>
<soapExtensionTypes>
<add type="Contoso.MySoapExtension, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
priority="1" group="0"/>
</soapExtensionTypes>
</webServices>
</system.web>
</configuration>
I've compiled the traceextension into its own class library, and referenced it in the web.config of the web service project like so:
<add type="TraceExtension, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ef8757fac167b8d8" priority="1" group="High"/>
No joy. Nothing is logged, no breakpoints are hit.
I then removed the referenced class, and dropped the source code into the web service project.
I tried to add a reference to it like so (my namespace is ServcieTest001):
<add type="ServiceTest001.TraceExtension" group="High" priority="1" />
I used the following thread as a guide as to enabling me extension "getting-raw-soap-data-from-a-web-reference-client-running-in-asp-net" (http://stackoverflow.com/questions/300674/getting-raw-soap-data-from-a-web-reference-client-running-in-asp-net).
Still no joy. I then copied the code from the above thread, and still cannot get the extension to fire when I make a SOAP request.
Can anyone point me to a functioning downloadable web service extension demo project, so I can disassemble it and work out what I'm missing?

John is right, you can intercept the messages on the client using a custom client behavior that implements IClientMessageInspector. See How To: Inspect or Modify Messages on the Client on MSDN.
The only thing 'tricky' about it is that if you plan on modifying the message body then you will need to create a copy of the original message first. See Using the Message Class for the gooey details.

Chances are you want to get some rest.
You don't ever want to use WSE. WSE is obsolete.
You don't want to be using ASMX Web Services - Microsoft now considers them to be "legacy" technology, and will not be fixing bugs. BTW, WSE is based on ASMX, so what's that make it?
You only want to work with Windows Communication Foundation. The WCF Development Center on MSDN is at http://msdn.microsoft.com/wcf/.
Have fun, and stay away from the nasty, ancient, obsolete stuff.

Yup - I was too tired.
I think the Web Service Extensions work with "Web references" (.net 2), not "Service references" (.net 3).
So I guess to alter my question - how do I intercept the request and response for a .net 3 "Service reference" connected to a legacy web service?

This is the command that gets your raw message:
OperationContext.Current.RequestContext.RequestMessage
I wasted 3 days trying with soap extention and it was way too simplier than I thought. You will find intersting reading the links Zach mentioned.

Related

SoapExtension System.Configuration.ConfigurationErrorsException in web.config The value of the property 'type' cannot be parsed

I have problems with the configuration of a SoapExtension (not with the implementation).
First of all, I've already read all these posts (among others), related in some way with SoapExtensions:
Intercept SOAP messages from and to a web service at the client
https://www.codeproject.com/Articles/34381/Efficient-Tracing-Using-SOAP-Extensions-in-NET
https://social.msdn.microsoft.com/Forums/en-US/d8d6fe09-74be-4210-91bb-a8924a742e8c/how-to-log-soap-message-which-is-going-out-of-my-web-application?forum=ncl
http://www.seanmcilvenna.com/2010/08/20/logging-full-soap-messages/
How to create a web.config file to get SoapExtension loading?
Intercept messages in a WCF Client
https://msdn.microsoft.com/en-us/library/esw638yk(VS.85).aspx
https://social.msdn.microsoft.com/Forums/en-US/1ba267b8-c08d-4c30-a1e1-792bac92fc87/soapextension-does-not-work-in-client-side?forum=netfxnetcom
SoapExtension not loading
The scenario is as follow:
I'm consumming a 3rd party WS(SOAP) from a Library (dll) project: connectors.dll
In this project i've a web-reference to the 3rd party WS(SOAP). I generated the proxy with VS (adding a web-reference, and pointing to the wsdl).
In the other hand , I've a web-application (indeed is a REST-service), with a reference to a class (we could call it Connector-A) of connectors.dll
(until here, I call a rest service, over my REST-Service webapp, call the connector-A and this do a last call to proxy service of the 3rdParty. I receive a response, but it has an invalid character (0x1F at position 1), and this is why I'm trying to use SoapExtension -> to delete it before deserialization take place)
I implement the SoapExtension (XmlCleanupSoapExtension.cs) as a separate library Backend.SoapExentensions ( based on this: https://blogs.technet.microsoft.com/stefan_gossner/2009/08/26/how-to-deal-with-invalid-characters-in-soap-responses-from-asp-net-web-services/)
The last step, to configure:
* add a reference (VS->Add Reference) in my REST-Service (webapp) to Backend.SoapExtnsions.dll and
register the soapExtension in web.config :
`
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" maxUrlLength="4000" />
<authentication mode="None" />
<webServices>
<soapExtensionTypes>
<add type="Backend.SoapExtensions.XmlCleanupSoapExtension, Backend.SoapExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=66269ab3fc862c8f" priority="1" group="0" />
</soapExtensionTypes>
</webServices>
<globalization uiCulture="auto:es" culture="auto:es-ES" enableClientBasedCulture="true" />
</system.web>
`
When I call a rest-service that, at the end,it calls the WS-Soap i'm getting now a runtime exception, which makes me crazy:
The value of the property 'type' cannot be parsed. The error is: Could not load type 'Offidesk.Backend.SoapExtensions.XmlCleanupSoapExtension' from assembly 'Offidesk.Backend.SoapExtensions'.
I think I've tried all possible combinations for this line:
<add type="Backend.SoapExtensions.XmlCleanupSoapExtension, Backend.SoapExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=66269ab3fc862c8f" priority="1" group="0" />
with and without assembly name
with and without namespace
with and without Version, Culture and PublicToken
Group="0" and Group="High"
Actually, I'm completely frustated with this runtime exception. I though that perhaps the position of block inside could affect, but all my tries get the same exception...
Any idea??
thanks in advance.
Note: I also tried other tecniques to clean the server-response overriding the SoapHttpClientProtocol (in a extended class) method: GetReaderForMessage
but don't work for me neither (don't know why).
EDIT
Finally the problem with the invalid character 0x1F was not such. I didn't realize that the response was coming compressed with gzip, and the proxy-client tried to parse a compressed response as XML, which obviously, was rising an exception at runtime.
However, I'm very insterested yet in knowing the reason why my web.config, with the soap extension, don't work (sooner or later we would need this configuration....so it's better to prevent).
For Googlers like me who landed here, if your soap extension is a different project than the one using it, the expected format for "type" in your app/web.config is "namespace.class, project".
The error message is subtly different depending on what you're doing wrong.
If the error is "Could not load type 'MyType' from assembly 'System.Web.Webservices..." you don't have the second part after the comma--the project with the soap extension. It's wanting to find your class in System.Web.Webservices as the default, which of course is not where you have it.
If the error is simply "Could not load file or assembly 'MyProject' or one of its dependencies..." it means the second part after the comma is wrong rather than missing.
Make sure you actually have a reference to the soap project in the project where you're trying to use it.
Make sure you have it named correctly in your app/web.config. Don't assume it's just the first part of the namespace. In Solution Explorer go to the References of the project that has your app/web.config, right click the project you're trying to reference and see the Properties. The value you want to put in your app/web.config after the comma is in the "Identity" field.
I had a similar problem, but Chad Hedgcock's answer helped me out big time. My SopaExtension was in the same project with my WebService. When I tried to register it in web.config, I was getting all those errors, but when I moved the SoapExtension to a new project it simply started working (I only had to change the type field to include new project name).

The Global element 'configuration' has already been declared when adding .net 2.0 web service reference to MVC project

I am getting build failure due to warning in my web.config. Everything was fine before I added .net 2.0 Web service reference to the MVC project. I got warnings of Global element '{element name}' has already been declared for all the elements in my web.config. Searching has only turned up different issues than the one I am having.
Is there any way to fix this issue, perhaps by telling the configuration manager to ignore the config file in the referenced WS assembly?
I can not use the regular service reference as I am not able to call it via https. Or is there a way to reference the 2.0 web service as the regular service reference that can be invoked via https/ssl connection?
Edit: I also have a WCF service reference declared in the project, will that complicate the matter?
I figured out. I don't have to add .net 2.0 WS reference to the project. I can use in web.config to specify the transport protocol to be https.
However, it is wired that adding a web reference would invalidate the web.config elements. I would like to learn the cause of that and would appreciate your input.

Does WCF service config info go in client?

I have a question about references to WCF Services. I have two apps:
Console app
--Library
----WCF Service
The console app and library are in the same solution. Because of the WCF service in the library, its app.config has info for the WCF Service.
The console app config has nothing about the WCF Service. The console app calls the WCF Service indirectly through the library. I'm guessing that is why the console app has no WCF info in its config (since it knows nothing about the web service). The console app does a call to a static method in the library, which handles the WCF call.
I'm getting this error on the above call:
Could not find default endpoint element that references contract 'MyServiceReference.IMyService' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element
Does the host (console app) need the WCF Service related info from the library? If so, why didn't VS2010 add it.
The library you created ("--Library", in your hierarchy) likely added a service reference to your WCF service. ("in the library" makes no sense, so I'm assuming that's what you meant). This means that a bunch of information about the WCF service was added to the app.config for the library. That information needs to be in the app.config of any exe that references the library in order for the library to correctly access the WCF Service that it references.
What I'd suggest is running the SVCUtil.exe. You can run it against the running service like this:
svcutil.exe http://localhost:Port/YourSvcClass/YourSvcMethod /language:c#
What that will do is build a client-side c# (or vb) stub class in c#, plus a .Config file with the exact client side configuration file you'd need to connect ... all the good stuff. You can also run svcutil against your WCF dll like this:
svcutil.exe c:\yourfolder\YourService.dll /language:c#
Whether you use the stub class or not, the .config file will be helpful in setting up the client.
Good luck

Generating the System.ServiceModel configuration section for WCF Data Service client

When I use the "Add Service Reference" utility in Visual Studio to connect to a WCF Data Service (OData), visual Studio doesn't generate an App.config file with the System.ServiceModel section for me. (The proxy class is generated fine). Is this normal?
Is there still a way to have this config generated automatically? The WCF service in question is secured and I therefore struggle with authentication issues if I try to to use the command line svcutil.exe with the /config option.
svcutil.exe cannot be used with WCF Data Services (OData), there's a datasvcutil.exe which is used instead.
The Add Service Reference for OData should not generate anything into your app.config as it doesn't need it. To use it, you just new up the generated context class and pass in the URI of the service.
If your OData endpoint required authentication though, the Add Service Reference doesn't support that though, so I'm surprised it works for you.

ASP.NET: Multiple assembly versions, same web application

Hopefully you ASP.NET pros out there can answer this question. I have a single web application that contains a website and a web service - both have several assembly references in common (data access layer, utilities, etc) - however, recent changes made to the web service will require different versions of the common assemblies, versions that the website won't work with (in case you're wondering, the website is some legacy 1.x .NET code that explodes when using the newer version assemblies.)
Can anyone think of a way to allow my web service to reference one version and have my website reference another? I can obviously have only one version with the same name within the bin folder.
Thanks!
(P.S. - It just dawned on me that I could probably compile and reference the common assemblies with a different name, and place those in the web app's bin folder - but that sounds really fugly...)
Or you could separate the webservice into a new application independant of the website.
You can use the runtime part of the web.config to specify the dll to use (We have done it for SQLLite before):
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<qualifyAssembly partialName="System.Data.SQLite" fullName="System.Data.SQLite, Version=1.0.60.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" />
</assemblyBinding>
</runtime>
I have a single web application that contains a website and a web service
That's your main problem there, you've released a partially functioning Application that relies on two different library code bases...
Even if you were to duplicate and re-reference your common assembly with a different name, you're still boned (pardon the phrase) re: Namespaces of all your classes inside that assembly.
I think you're best bet, would be to Pull the webservice out of your Web Application temporarily, and host them as two seperate app's until you can get your Common Lib's versioning issues sorted out.
I don't think compiling the newer set into an assmebly with a different name would work - .NET would still see the same namespace - so at best you'd have "Ambiguous Reference" or "Type x is already declared in dll y" errors, or at worst the framework would load the one relevant to the part of the app that was called first (website => 1.1, webservice => 2.0) and ignore the other one.
Your best bet would be to refactor the application in to two - web site and web service.
We've been doing this over the last couple of years with one of our clients - they have a huge site built on ASP.NET 1.1, but recent stand alone projects for them have started to move to 2.0 (3.5 under the hood, but obviously that's still hosted under 2.0) - we've basically had to port the common code to a new set of libraries built against 3.5, taking advantage of the new language features as we go, and we've moved those sections to new web sites (in IIS) as they are completed.
It's not ideal, yes we're then left with two copies of the codebase (1.1 and 2.0) and any fixes generally have to be rolled out in two places, but it seemed the best way to start moving them on.

Categories

Resources