I've got a WCF client connecting to an STS server, which I don't have any control over (it's a 3rd party PHP service).
After days of research I managed to talk to the server in a way it accepts using purely WCF. Of course, it would have been easy to just put some characters onto the network, ignoring all the SOAP stuff. But in the end I managed to guess every configuration parameter right, so the STS service answers my request like this
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<RequestSecurityTokenResponse xmlns="http://schemas.xmlsoap.org/ws/2005/02/trust">
<TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</TokenType>
<RequestedSecurityToken>
<SecurityContextToken xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<Identifier>bipro:D5J9M0...</Identifier>
</SecurityContextToken>
</RequestedSecurityToken>
</RequestSecurityTokenResponse>
</Body>
</Envelope>
But now I have trouble to extract the identifier value. For my proxy class (SecurityTokenServicePortTypeClient : ClientBase<SecurityTokenServicePortType>, SecurityTokenServicePortType) I tried every imaginable combination of ServiceContract, DataContract and XmlSerialization on all the types. But all I get is null.
The (heavily modified) interface for the service contract looks like this
[ServiceContract(Namespace = "http://schemas.xmlsoap.org/ws/2005/02/trust")]
public interface SecurityTokenServicePortType {
[OperationContract(Action = "urn:RequestSecurityToken", ReplyAction = "*")]
object RequestSecurityToken();
}
The (heavily modified) implementing class has a method like this
object SecurityTokenServicePortType.RequestSecurityToken() {
var x = base.Channel.RequestSecurityToken();
return x;
}
x is always null.
Instead of a return type of object it was originally RequestSecurityTokenResponse and so on.
I had the same problem with WSE years ago and I was able to solve that by just using the right combination of for example XmlElementAttribute to control the deserialization process. But this time it doesn't seem to help.
Thanks for any advice!
Björn
Related
I have a large WSDL file that I need to generate a WCF Web service from. I can generate a service using svcutil.exe, however it's not generating what I need.
I need a service that accepts/returns XML, rather than serialized types. The reason for this is if there is an error in the incoming XML it will fail before it hits my code - we can't have this. We need to intercept the XML before any serialization happens to catch it.
Is this possible?
Or is there a way I can modify the generated services so I can work with the raw XML rather than the derived "Message" type?
Effecitvely I want something similar to:
XmlDocument PersonRevised(XmlDocument request);
Current code:
[ServiceContract(Namespace = "urn:hl7-org:v3")]
public interface IPRPA_AR101202
{
[OperationContract(Name = "PersonRevised", Action = "urn:hl7-org:v3/PRPA_IN101204")]
PersonRevisedResponse PersonRevised(Message request);
}
public class PRPA_AR101202 : WCFServiceBase, IPRPA_AR101202
{
PersonRevisedResponse IPRPA_AR101202.PersonRevised(Message request)
{
PersonRevised pr = this.ParseMessage<PersonRevised>(request, HL7_XML_NAMESPACE);
PersonRevisedResult result = new PersonRevisedResult();
PersonRevisedResponse r = new PersonRevisedResponse(result);
return r;
}
}
update:
Based on the answer I was able to create a WCF service that accepted a string, however now I am getting null on the implemented services that are based off of WSDL contracts( on the input parameter); regardless of whether it's a string or an XmlDocument/XmlNode.
Thoughts?
I need a service that accepts/returns XML, rather than serialized
types
In that case you are better off using POX and not using SOAP/WSDL at all. There are some resources for this here and here.
The reason for this is if there is an error in the incoming XML it
will fail before it hits my code - we can't have this.
I kind of know what you're saying here. It is annoying that any serialization exceptions will kill the channel rather than bubble back to the client, however, the whole point of exposing a service metadata endpoint is that clients will always serialize types which are exposed outside the service boundary correctly because that's what the WSDL is supposed to be for.
Effecitvely I want something similar to: XmlDocument
PersonRevised(XmlDocument request);
As you are no doubt aware, exposing a XmlDocument type is not equivalent to exposing XML. Exposing XmlDocument will not be pretty.
If you absolutely need full control over the deserialization, you will have to expose your operation as accepting a parameter of type string. Then you can do what you want with it.
public string PersonRevised(string request)
{
// Deserialize here...
}
I have an application in WCF that runs in all machines on my customer. But just one works like a server in the net.
In this model, every time the WCF "client" is called, he call your WCF "server" to obtain your response.
So, I have this configuration on my Interface:
[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest)]
[OperationContract]
MyObjectReturn CheckUpdate(string foo1, string foo2, string foo3);
In my code, this:
MyObjectReturn myObjReturn = new MyObjectReturn();
if (this.Master)
{
myObjReturn.Code = 15000;
myObjReturn.Message = "New Update found";
return myObjReturn;
}
else
{
var myTask = Task<MyObjectReturn >.Factory.StartNew(() =>
{
ServerContractClient server = new ServerContractClient(master.Url);
return server.CheckUpdate(foo1, foo2, foo3);
}
return myTask.Result;
}
When the WCF "client" calls his "server", the return is always null! If I do not use the "Task . Factory.StartNew", I get a Bad Request error
Any tip?
Uh, first, "server" and "client" are the preferred nomenclatures.
Second, Servy has a point that if you want the data back immediately, there's no real point in starting a thread. That said, threads are fun! Who doesn't want to thread? To do it properly you'll have to revise your application a bit, but for now you'll at least have to design the WCF method to be asynchronous, and the client making the call needs to know it's asynchronous; otherwise the result is null, as you experienced. Best starting point is here.
I'm ashamed to say it, but the problem was not what I thought. I noticed that when I called the WCF Server via browser, my return was not null. It was then that I realized that my Binding was the real problem. I noticed that there were two errors:
1) My Bindding is created via code. As noted in my interface, I declared my WebMessageBodyStyle as WrappedRequest. But when creating the Binding Client, I was using Wrapped;
2) The namespace of my ServiceBehavior and DataContract were different, which also caused confusion in WCF.
This link helped me clarify this last point:
WCF Web Service Call to Another WCF Web Service returns no data
Anyway, thank you all who gave me very valuable tips on this problem.
I have a client application that consumes a number of services. It's not always immediately obvious when a service is down or incorrectly configured. I own the service side code and hosting for most of the services, but not all of them. It's a real mixed bag of client proxies - different bindings (basichttp/wshttp/nettcp), some have been generated using svcutil.exe, while others are made programatically with ChannelFactory where the contract is in a common assembly. However, I always have access to the address, binding and contract.
I would like to have a single component in my client application that could perform a basic check of the binding/endpoint config and the service availability (to show in some diagnostic panel in the client). As a minimum I just want to know that there is an endpoint at the configured address, even better would be to find out if the endpoint is responsive and supports the binding the client is trying to use.
I tried googling and was surprised that I didn't find an example (already a bad sign perhaps) but I figured that it couldn't be that hard, all I had to do was to create a clientchannel and try to open() and close() catch any exceptions that occur and abort() if necessary.
I was wrong - in particular, with clients using BasicHttpBinding where I can specify any endpoint address and am able to open and close without any exceptions.
Here's a trimmed down version of my implementation, in reality I'm returning slightly more detailed info about the type of exception and the endpoint address but this is the basic structure.
public class GenericClientStatusChecker<TChannel> : ICanCheckServiceStatus where TChannel : class
{
public GenericClientStatusChecker(Binding binding, EndpointAddress endpoint)
{
_endpoint = endpoint;
_binding = binding;
}
public bool CheckServiceStatus()
{
bool isOk = false;
ChannelFactory<TChannel> clientChannelFactory = null;
IClientChannel clientChannel = null;
try
{
clientChannelFactory = new ChannelFactory<TChannel>(_binding, _endpoint);
}
catch
{
return isOk;
}
try
{
clientChannel = clientChannelFactory.CreateChannel() as IClientChannel;
clientChannel.Open();
clientChannel.Close();
isOk = true;
}
catch
{
if (clientChannel != null)
clientChannel.Abort();
}
return isOk;
}
}
[Test]
public void CheckServiceAtNonexistentEndpoint_ExpectFalse()
{
var checker = new GenericClientStatusChecker<IDateTimeService>(new BasicHttpBinding(), new Endpointaddress("http://nonexistenturl"));
// This assert fails, because according to my implementation, everything's ok
Assert.IsFalse(checker.CheckServiceStatus());
}
I also tried a similar technique with a dummy testclient class that implemented ClientBase with the same result. I suppose it might be possible if I knew that all my service contracts implemented a common CheckHealth() method, but because some of the services are outside my control, I can't even do that.
So, is it even possible to write such a simple general purpose generic service checker as this? And if so how? (And if not, why not?)
Thanks!
Have you looked at WCF Discovery?
WCF Discovery allows a client to search for a service based on
different criteria including contract types, binding elements,
namespace, scope, and keywords or version numbers. WCF Discovery
enables runtime and design time discovery. Adding discovery to your
application can be used to enable other scenarios such as fault
tolerance and auto configuration.
For a first attempt, you could query the endpoint to see if it supports the expected contract.
The big benefit is that you can have the client “discover” which service it wants to talk to at runtime. Which removes a lot of the client side configuration errors that you are likely used to seeing.
You need to check out SO-AWARE. It is a web service management tool that can manage SOAP or REST WCF-based service across your organization. Further it has a Test Workbench!
Here are a couple of videos that show it off too:
Part 1
Part 2
To put it in perspective, this is so complex that these people make a living doing it, I don't think it's something you want to realistically build on your own.
I have a WCF Host with something like this:
[ServiceContract]
public interface IMountToOs
{
[OperationContract]
char GetMountDriveLetter();
[OperationContract]
MyTestClass MyTest();
}
public class MyTestClass
{
public string A { get; set; }
public string B { get; set; }
}
Client
private IMountToOs _proxy;
public IMountToOs Proxy
{
get
{
if (_proxy == null)
{
NetTcpBinding binding = new NetTcpBinding();
binding.MaxReceivedMessageSize = 2147483647;
binding.OpenTimeout = TimeSpan.FromMilliseconds(50000);
EndpointAddress address = new EndpointAddress("net.tcp://localhost:1234/MountToOsHost");
//_proxy = new MountToOsClient(binding, address);
ChannelFactory<IMountToOs> factory = new ChannelFactory<IMountToOs>(binding);
_proxy = factory.CreateChannel(address);
}
return _proxy;
}
}
While I can access
MessageBox.Show("Okay - " + Proxy.GetMountDriveLetter());
I can't call this method:
MessageBox.Show("Okay - " + Proxy.MyTest().A);
The complete extension is not working. But only while using it in an extension. Even if I insert a Messagebox in the first line of the extension it is not hit. I don't know why. It seems to run a pre-check and find the call of the custom class which is refused or so...
If I use a winform or so there is no problem.
.net 3.5
curious is that I have a break-point and a message of the hosts side. So I see that the method is not called
Update
now I moved the wcf-call in the Load Method of the extension and get a exception:
System.MissingMethodException: method not found:
"Contracts.Interfaces.MyTestClass
Contracts.Interfaces.IMountToOs.MyTest()".
My winform test and this extension use the same interface so that the method should known from both. no contract or so is outdated
According to what I found here and in the comments of the post: "For creating dynamic service proxy using client channel factory method, you will need datacontracts of the service. If you don't have datacontracts but you have the service URL, then you could use reflection to create proxy at runtime and call the service method."
Seems that the MyTestClass type is not known on the client side, so I think you could use reflection, or share the class between the client and server or much more simple, use the datacontract attribute.
Also, found something on MSDN that says something like this:
"When to use a proxy?
We create proxy using svcutil.exe. The output of this tool gives a proxy class and makes corresponding changes to the application configuration file. If you have a service that you know is going to be used by several applications or is generic enough to be used in several places, you'll want to continue using the generated proxy classes. We use proxy in WCF to be able to share the service contract and entities with the client. Proxies have several restrictions like they need to have gets and sets , contructors can't be exposed , methods other than the service contract cannot be exposed, repetition of code, everytime that we add/modify a service contract/data contract/message contract we need to re-generate the proxy for the client.
When to use ChannelFactory
The other option is using the ChannelFactory class to construct a channel between the client and the service without the need of a proxy . In some cases, you may have a service that is tightly bound to the client application. In such a case, it makes sense to reference the Interface DLL directly and use ChannelFactory to call your methods using that. One significant advantage of the ChannelFactory route is that it gives you access to methods that wouldn't otherwise be available if you used svcutil.exe..
When to use a ChannelFactory vs Proxy class?
A DLL is helpful if the client code is under you control and you'd like to share more than just the service contract with the client -- such as some utility methods associated with entities and make the client & the service code more tightly bound. If you know that your entities will not change much and the client code is less, then a DLL would work better than a proxy. If the client to your service is external to the system, such as API, it makes sense to use a proxy, because it makes sharing the contract easier by giving a code file rather than a DLL."
We cant see the class
MountToOsClient: IMountToOs
So we can only assume it is ok.
[DataContract] // Missing
public class MyTestClass
{
[DataMember] // Missing
public string A { get; set; }
[DataMember] // Missing
public string B { get; set; }
}
MountToOsClient can not expose Mytestclass without these attributes.
I'm in the process of learning WCF, and as a practical exercise I've decided to write generic wrapper for the ServiceHost class. The idea is to have a class like the one below :
public class Host<I(nterface), S(ervice)>
where S : I, new()
{
/**/
ServiceHost mServiceHost;
S mServiceInstance = new S();
}
Where the I type is the interface with the [ServiceContract] attribute & the S type is the Service that's implementing the forementioned interface.
I've created an auxiliary hello-world type service in the mean time to test my class on the go.
In the Host's constructor I've instantiated the internal ServiceHost like this :
mServiceHost = new ServiceHost(mServiceInstance);
I've added a service endpoint :
mServiceHost.AddServiceEndPoint(typeof(I), new BasicHttpBinding(), new Uri("http://localhost:40000/MyTestService"));
a bit later I've opened the host, launched my application and attempted to see if my browser will indicate a service present under the "http://localhost:40000/MyTestService" - I got a blank page and all attempts to add a service reference failed.
I've later added the same Uri to the ServiceHost's constructor :
mServiceHost = new ServiceHost(mServiceInstance, new Uri("http://localhost:40000/MyTestService"));
That constructor's 2nd argument is either :
params string[] baseAddresses
or
params Uri[] baseAddresses
In any case, the presence of the "params" keyword tells me that this parameter is OPTIONAL.
I've reacitvated my app, and (using the browser) navigated to the uri. The service page popped up. All in all - it's working but not the way I expected, I seem to be missing something.
Questions :
Why did the service fail when I did not supply the optional baseAddresses parameter in the ServiceHost constructor - while attempting to feed the addresses while adding service endpoints?
Can I achieve my goal "the way I initially wanted it to be" ?
Best regards, and hoping to hear from any WCF experts soon(tm).
Greg Sansom answered your first question.
As for the second it can be done: please get a look at Juval Lowy's ServiceModelEx classes (especially ServiceHost) download here it contains several useful classes for WCF