I've got a net.tcp service, which I want to make accessible to other platforms (specifically, PHP). For this, I'm using http binding.
I'm creating a http endpoint with:
ServiceHost svh = new ServiceHost(typeof(MyService));
var httpLocation = "http://" + address + ":4041";
svh.AddServiceEndpoint(typeof(IMyService), new WebHttpBinding(WebHttpSecurityMode.None),
httpLocation);
svh.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
httpLocation + "/mex"
);
svh.Open();
Now, when I'm trying to explore the service via browser by going to http://localhost:4041, I'm getting:
<Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
<Code>
<Value>Sender</Value>
<Subcode>
<Value xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:ActionNotSupported</Value>
</Subcode>
</Code>
<Reason>
<Text xml:lang="en-US">
The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
</Text>
</Reason>
What am I doing wrong?
When browsing, make sure to include the full path to the .svc or .asmx along with a trailing ?wsdl.
localhost:4041/ServiceVirtualDirectory/Service.svc?wsdl
Have you tried accessing http://localhost:4041/MyService.svc?wsdl?
Not sure if your service is REST-ful by design and that's why you used WebHttpBinding.
If your service is actually REST-ful, its format would be
http://localhost:4041/MyService.svc/MyMethod/MyData and you should see the results on the browser. Based on this ASP.NET thread, you would need to attach a WebHttpBehavior.
If your serivce isn't REST-ful, you should consider BasicHttpBinding (uses regular SOAP messages) or its cousins based on your requirements (see this SO thread).
Hope this helps.
Related
well i wanted to make a simple webservice that searches the db and return the data i know i can do it with mysql connector but this is just to learn how to use soaps here is the code for php soap server
require_once ('lib/nusoap.php');
$namespace = "http://localhost/webservice/index.php?wsdl";
$server = new soap_server();
$server->configureWSDL("DBQuery");
$server->wsdl->schemaTargetNamespace = $namespace;
$server->register(
'QueryMsg',
array('name'=>'xsd:string'),
array('return'=>'xsd:string'),
$namespace,
false,
'rpc',
'encoded',
'returns data from database');
function QueryMsg($query)
{
$con=mysqli_connect('localhost','root','','webserivce');
if (mysqli_connect_errno()) {
return "Failed to connect to MySQL: " . mysqli_connect_error();
}
if(!isset($query) or strpos(strtolower($query),'select')<=-1)
{
return "invalid order";
}
else
{
mysqli_real_escape_string($con,$query);
$result = mysqli_query($con,$query);
while($row = mysqli_fetch_array($result)) {
$data[] = $row;}
return json_encode($data);
}
}
// create HTTP listener
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
exit();
?>
it works when i try calling it from a php soap client but when i try adding this http:// localhost /webservice/index.php in visual studio as service refernce to consume it from C# application i get an error here it is
The HTML document does not contain Web service discovery information.
Metadata contains a reference that cannot be resolved: 'http://localhost/webservice/index.php'.
The content type text/xml; charset=ISO-8859-1 of the response message does not match the content type of the binding (application/soap+xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 700 bytes of the response were: '<?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body><SOAP-ENV:Fault><faultcode xsi:type="xsd:string">SOAP-ENV:Client</faultcode><faultactor xsi:type="xsd:string"></faultactor><faultstring xsi:type="xsd:string">Operation '' is not defined in the WSDL for this service</faultstring><detail xsi:type="xsd:string"></detail></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>'.
The remote server returned an error: (500) Internal Server Error.
If the service is defined in the current solution, try building the solution and adding the service reference again.
solved : well it was easy actually there is two ways either use WCF and change encoding to ISO-8859-1
or change encoding of the web service itself by adding this line $server->soap_defencoding = 'UTF-8'; after creating the soap server
I would try adding the service WSDL with a tool like SOAP U.I. and see what kind of errors you get back from that. It's a little more agnostic than adding a web reference with C#, and might disclose more details about why at the client level you can't consume this.
I'm happy to help you troubleshoot this with a little more information. Are you running this service on the same machine where you're running the client from? If it's complaining about being unable to correlate the file http://localhost/webservice/index.php to something I wonder if the discovery process is trying to evaluate a file that can't be found. I.E. an import operation in your source WSDL that points to a URL the client can't resolve.
I have a WCF service built on the classes created from a customer supplied WSDL. Unfortunately this WSDL did not contain the required message header. The client will not be supplying a new WSDL including the header. I do have an xsd file describing the header.
I also have a sample header and know which fields I need to populate.
How can I take this supplied header XML and inject it into an outbound WCF method call?
I want to call my service method as I currently do, but I also want the new header structure to form part of the outbound message.
Thanks in advance.
Any and all help will be greatly appreciated.
Here is an example of the message structure:
I need to add the entire header structure. All that the WSDL contained was the body.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<glob:requestHeader xmlns:glob="http://....">
<timestamp>2013-11-14T05:17:41.793+02:00</timestamp>
<traceMessageId>GUID</traceMessageId>
<enterpriseTraceUUId>GUID</enterpriseTraceUUId>
<contentType>TEXT/XML</contentType>
<sender>
<senderId>SENDER</senderId>
<sourceSystem>001</sourceSystem>
<sourceApplication>001</sourceApplication>
<applicationSessionId>ABC</applicationSessionId>
<sourceLocation>100</sourceLocation>
</sender>
<interfaceName/>
<version>1111</version>
</glob:requestHeader>
</s:Header>
<s:Body xmlns:xsi="http://.../XMLSchema-instance" xmlns:xsd="http://.../XMLSchema">
<UserData xmlns="http://.../Base">
<IdField>1005687</IdField>
<UserInfo>
<UserType>1</UserType>
<UserStatus>Y</UserStatus>
</UserInfo>
</UserData>
</s:Body>
</s:Envelope>
I used this, for instance, to add "User-Agent" to the header of my outgoing messages, but I think you could adapt it to your own needs:
private void AddCustomHeader(System.ServiceModel.OperationContextScope scope)
{
dynamic reqProp = new System.ServiceModel.Channels.HttpRequestMessageProperty();
reqProp.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT; blah; blah; blah)");
System.ServiceModel.OperationContext.Current.OutgoingMessageProperties(System.ServiceModel.Channels.HttpRequestMessageProperty.Name) = reqProp;
}
I call this function above from the the constructor of the client-side program I use to call the host.
AddCustomHeader(new System.ServiceModel.OperationContextScope(base.InnerChannel));
Probably the most important thing to notice is that it's adding this header variable to OutgoingMessageProperties of the "Current" OperationContext used by my client.
have you tried this? Also taken from here: How to add a custom HTTP header to every WCF call?
using (OperationContextScope scope = new OperationContextScope((IContextChannel)channel))
{
MessageHeader<string> header = new MessageHeader<string>("secret message");
var untyped = header.GetUntypedHeader("Identity", "http://www.my-website.com");
OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
// now make the WCF call within this using block
}
I have a requirement to secure a streamed WCF net.tcp service endpoint using WIF. It should authenticate incoming calls against our token server. The service is streamed because it is designed to transfer large amounts of data n stuff.
This appears to be impossible. And if I can't get around the catch, my Christmas will be ruined and I'll drink myself to death in a gutter while merry shoppers step over my slowly cooling body. Totes serious, you guys.
Why is this impossible? Here's the Catch-22.
On the client, I need to create a channel with the GenericXmlSecurityToken I get from our token server. No problemo.
// people around here hate the Framework Design Guidelines.
var token = Authentication.Current._Token;
var service = base.ChannelFactory.CreateChannelWithIssuedToken(token);
return service.Derp();
Did I say "no problemo"? Problemo. In fact, NullReferenceException style problemo.
"Bro, " I asked the Framework, "do you even null check?" The Framework was silent, so I disassembled and found that
((IChannel)(object)tChannel).
GetProperty<ChannelParameterCollection>().
Add(federatedClientCredentialsParameter);
was the source of the exception, and that the GetProperty call was returning null. So, WTF? Turns out that if I turn on Message security and set the client credential type to IssuedToken then this property now exists in the ClientFactory (protip: There is no "SetProperty" equivalent in IChannel, the bastard).
<binding name="OMGWTFLOL22" transferMode="Streamed" >
<security mode="Message">
<message clientCredentialType="IssuedToken"/>
</security>
</binding>
Sweet. No more NREs. However, now my client is faulted at birth (still love him, tho). Digging through WCF diagnostics (protip: make your worst enemies do this after crushing them and driving them before you but right before enjoying the lamentations of their women and children), I see it's because of a security mismatch between the server and client.
The requested upgrade is not supported by 'net.tcp://localhost:49627/MyService'. This could be due to mismatched bindings (for example security enabled on the client and not on the server).
Checking the host's diags (again: crush, drive, read logs, enjoy lamentations), I see this is true
Protocol Type application/ssl-tls was sent to a service that does not support that type of upgrade.
"Well, self," I says, "I'll just turn on Message security on the host!" And I do. If you want to know what it looks like, it's an exact copy of the client config. Look up.
Result: Kaboom.
The binding ('NetTcpBinding','http://tempuri.org/') supports streaming which cannot be configured together with message level security. Consider choosing a different transfer mode or choosing the transport level security.
So, my host cannot be both streamed and secured via tokens. Catch-22.
tl;dr: How can I secure a streamed net.tcp WCF endpoint using WIF???
WCF has gotchas in a few areas with streaming (I'm looking at you, MTOM1) due to a fundamental issue in how it fails to perform preauthentication the way most people would think that should work (it only affects subsequent requests for that channel, not the first request) Ok, so this is not exactly your issue but please follow along as I will get to yours at the end. Normally the HTTP challenge works like this:
client hits server anonymously
server says, sorry, 401, I need authentication
client hits server with authentication token
server accepts.
Now, if you ever try to enable MTOM streaming on an WCF endpoint on the server, it will not complain. But, when you configure it on the client proxy (as you should, they must match bindings) it will explode in a fiery death. The reason for this is that the above sequence of events that WCF is trying to prevent is this:
client streams 100MB file to server anonymously in a single POST
server says sorry, 401, I need authentication
client again streams 100MB file to server with an authentication header
server accepts.
Notice that you just sent 200MB to the server when you only needed to send 100MB. Well, this is the problem. The answer is to send the authentication on the first attempt but this is not possible in WCF without writing a custom behaviour. Anyway, I digress.
Your Problem
First up, let me tell you that what you're trying is impossible2. Now, in order for you to stop spinning your wheels, let me tell you why:
It strikes me that you are now wandering in a similar class of problem. If you enable message level security, the client must load the entire stream of data into memory before it can actually close out the message with the usual hash function and xml signature required by ws-security. If it has to read the entire stream to sign the single message (which is not really a message, but it's a single continuous stream) then you can see the problem here. WCF will have to stream it once "locally" to compute the message security, then stream it again to send it to the server. This is clearly a silly thing, so WCF does not permit message level security for streaming data.
So, the simple answer here is that you should send the token either as a parameter to the initial web service, or as a SOAP header and use a custom behaviour to validate it. You cannot use WS-Security to do this. Frankly, this is not just a WCF issue - I cannot see how it could practically work for any other stacks.
Solving the MTOM Problem
This is just for an example how I solved my MTOM streaming issue for basic authentication, so perhaps you could take the guts of this and implement something similar for your issue. The crux of it is that in order to enable your custom message inspector, you have to disable all notion of security on the client proxy (it remains enabled on the server,) apart from transport level (SSL):
this._contentService.Endpoint.Behaviors.Add(
new BasicAuthenticationBehavior(
username: this.Settings.HttpUser,
password: this.Settings.HttpPass));
var binding = (BasicHttpBinding)this._contentService.Endpoint.Binding;
binding.Security.Mode = BasicHttpSecurityMode.Transport; // SSL only
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.None; // Do not provide
Note that I have turned off transport security here because I will be providing that myself using a message inspector and custom behaviour:
internal class BasicAuthenticationBehavior : IEndpointBehavior
{
private readonly string _username;
private readonly string _password;
public BasicAuthenticationBehavior(string username, string password)
{
this._username = username;
this._password = password;
}
public void AddBindingParameters(ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(ServiceEndpoint endpoint,
ClientRuntime clientRuntime)
{
var inspector = new BasicAuthenticationInspector(
this._username, this._password);
clientRuntime.MessageInspectors.Add(inspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
EndpointDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
}
internal class BasicAuthenticationInspector : IClientMessageInspector
{
private readonly string _username;
private readonly string _password;
public BasicAuthenticationInspector(string username, string password)
{
this._username = username;
this._password = password;
}
public void AfterReceiveReply(ref Message reply,
object correlationState) { }
public object BeforeSendRequest(ref Message request,
IClientChannel channel)
{
// we add the headers manually rather than using credentials
// due to proxying issues, and with the 101-continue http verb
var authInfo = Convert.ToBase64String(
Encoding.Default.GetBytes(this._username + ":" + this._password));
var messageProperty = new HttpRequestMessageProperty();
messageProperty.Headers.Add("Authorization", "Basic " + authInfo);
request.Properties[HttpRequestMessageProperty.Name] = messageProperty;
return null;
}
}
So, this example is for anyone who is suffering with the MTOM issue, but also as a skeleton for you to implement something similar to authenticate your token generated by the primary WIF-secured token service.
Hope this helps.
(1) Large Data and Streaming
(2) Message Security in WCF (see "disadvantages.")
I am pretty new with web services and WSDLs.
What I want to do is to build a web service to read in a customer's SOAP message and process it.
The soap message sent to me is as follows (note I have trimmed the SOAP message right down)
<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope">
<soap2:Header>
<wsa:Action>http://htng.org/PWSWG/2010/12/ReservationSynch_SubmitRequest</wsa:Action>
<wsa:ReplyTo>
<wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address>
</wsa:ReplyTo>
</soap2:Header>
<Body>
<OTA_HotelResNotifRQ>
<POS>
//More tags
</POS>
<HotelReservations>
<HotelReservation RoomStayReservation="true">
<UniqueID Type="14" ID="59071IC000041" />
</HotelReservation>
</HotelReservations>
</OTA_HotelResNotifRQ>
</Body>
</Envelope>
This is my web service asmx (again I have trimmed it right down)
[WebMethod]
[SoapDocumentMethodAttribute("http://htng.org/PWSWG/2010/12/ReservationSynch_SubmitRequest", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Bare)]
public OTA_HotelResNotifRS ReservationSynch_SubmitRequest(OTA_HotelResNotifRQ OTA_HotelResNotifRQ)
{
}
Problem: When the message comes in, the method ReservationSynch_SubmitRequest gets fired but OTA_HotelResNotifRQ is null. The customer gave me the WSDL, as far as am concerned the class is correct. Though I notice the <Body> tag and is not <soap2:Body>. Does this make a difference?
I cannot change customer's message, I can only change my web service to read what they have sent to me. Am I missing something in my asmx?
If you are interested, here is their WSDL https://interface.synxis.com/interface/ota2010av2/OTA2010A.svc.wsdl
Found the problem!
I changed the namespace for a couple of the classes, which affected the schema files in the WSDL.
I'm using WCF to call a method on a Java web service (using basicHttp with <security mode="Transport">). The service returns some HTML back instead of a SOAPFault. WCF seems to implement some odd truncating of the content returned in the exception, so I can't see the entire error.
Is there a way to get the entire response? Perhaps some configuration I can change to pull back more then 660 bytes? I tried turning on service tracing, but it doesn't seem to capture the entire response. I'm unable to use Fiddler or Charles, because the service is using two-way SSL and it's on a secure network. Here's the exception:
The content type text/html of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 660 bytes of the response were: '<html><head><title>Server - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </he
It seems that an exception occurred on the server side. When exception occurs with httpBinding, HTTP status becomes 404 - NotFound.
It might be as a result of:
Incorrect signature of calling method and actual method, or order of parameters
Failure to serialize or deserialize the result
Some failure with SSL configuration/keys
Internal exception within WCF
In order to eliminate all the above try connecting to it using plain .NET client without SSL. Then add a level of complexity each time.
Hope this helped
Have you set IncludeExceptionDetailInFaults = True in ServiceDebugBehavior?
That might help.
You can try to capture outgoing SOAP request and send that request through HttpWebRequest class. This should allow you capturing whole response.