I have a restful web service that's returning results like this:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Some Text</string>
However, the people on the receiving end need this text to be terminated w/ a special character such as "\r". How can I add that text to the end of my serialized response?
I'm sending this response from inside of a WCF service in C# like this:
[WebGet(UriTemplate = "/MyMethod?x={myId}"), OperationContract]
string GetSomeText(Guid myId);
I can think of three solutions:
1. Http Module (least code but most confusing for maintenance)
Assuming you're hosting your WCF in ASP.Net, you can create an Http module to add a \r to the end of all responses in your application.
This could be the code of the Http module. I've used 'End' as a suffix here because it's easier to read in a browser than \r, but for \r you would change the "End" in context_PostRequestHandlerExecute to "\r".
public class SuffixModule : IHttpModule
{
private HttpApplication _context;
public void Init(HttpApplication context)
{
_context = context;
_context.PostRequestHandlerExecute += context_PostRequestHandlerExecute;
}
void context_PostRequestHandlerExecute(object sender, EventArgs e)
{
// write the suffix if there is a body to this request
string contentLengthHeaderValue = _context.Response.Headers["Content-length"];
string suffix = "End";
if (!String.IsNullOrEmpty(contentLengthHeaderValue))
{
// Increase the content-length header by the length of the suffix
_context.Response.Headers["Content-length"] =
(int.Parse(contentLengthHeaderValue) + suffix.Length)
.ToString();
// and write the suffix!
_context.Response.Write(suffix);
}
}
public void Dispose()
{
// haven't worked out if I need to do anything here
}
}
Then you need to set up your module up in your web.config. The below assumes you have IIS running in Integrated Pipeline mode. If you haven't, you need to register the modules in the <system.web><httpModules> section.
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<!-- 'type' should be the fully-qualified name of the type,
followed by a comma and the name of the assembly-->
<add name="SuffixModule" type="WcfService1.SuffixModule,WcfService1"/>
</modules>
</system.webServer>
This option has the problems that it would affect all requests in your application by default and it would probably fall over if you decided to use chunked encoding.
2. Use ASP.NET MVC (changes technology but good maintainability)
Use MVC instead of WCF. You'd have far better control over your output.
3. Custom Serializer (lots of code, but less hacky than option 1)
You could write your own custom serializer. This StackOverflow question gives you pointers on how to do this. I didn't write a prototype for this because it looked as though there were many, many methods which needed to be overridden. I daresay most of them would be pretty simple delegations to the standard serializer.
Related
I am trying to pass a to URI value dynamically with a property value. That property value will be configured already in the cfg file.
When the file name is extracted using CamelFileNameOnly header, it has to get passed to the to Uri endpoint. So that the same name is referred in the code.
Please find my code below:
I have dropped a file with name KevinFile.txt in my server location= D:\Servers\jboss-fuse-6.2.0.redhat-133\data\myLocalFTP (file://data/myLocalFTP)
Config File
local.folder.url=file://data/myLocalFTP
KevinFile=file://data/KevinFileDirectory
Camel Route
<route id="awsRoute">
<from uri="{{local.folder.url}}"/>
<bean ref="processorClass" method="process"/>
<log message="myProperty value is ${exchangeProperty.myProperty}"/> <---Gives the fileName
<to uri="{{${exchangeProperty.myProperty}}}"/> <--This is the spot i am getting error :(
</route>
ProcessorClass.java
public class ProcessorClass implements Processor{
#Override
public void process(Exchange exchange) throws Exception {
String fileName = (String) exchange.getIn().getHeader("CamelFileNameOnly");
exchange.setProperty("myPropertyNew", fileName);
}
}
If I understand correctly, you need to specify "dynamic" vlue for the constant part of the producer. Instead of <to uri="{{${exchangeProperty.myProperty}}}"/> you can use recipientList or routingSlip:
<recipientList>
<simple>${exchangeProperty.myProperty}</simple>
</recipientList>
or
<routingSlip>
<simple>${exchangeProperty.myProperty}</simple>
</routingSlip>
Ah what your looking for is simply setting the header as a property. You can do that like this:
from("direct:start")
.setHeader("CamelFileNameOnly").simple("{{myPropertyName}}")
.to("file://data/myLocalDisk");
You can also simplify this by using the uri syntax available on the file component in this case (Thanks to Sergii for the recommendation). Just make sure you check the camel documentation for each component certain components rely on exchange headers, while others can leverage URI properties.
from("direct:start")
.to("file://data/myLocalDisk?fileName={{myPropertyName}}");
Its also worth noting that if you have logic that you want to use before setting the header you can have the setHeader call a bean.
from("direct:start")
.setHeader("CamelFileNameOnly").bean(MyPropertyLogicBean.class, "someMethod({{myPropertyName}})")
.to("file://data/myLocalDisk");
Use the camel properties component to get this property to resolve.
Reference: http://camel.apache.org/properties.html
OK, I think there's no easy (make that lazy) way to do what I want but given the Perl SOAP::Transport::HTTP::CGI code fragment below what I am looking to do is intercept all SOAP operation passing through the service and log the result of an operation or fault...
SOAP::Transport::HTTP::CGI
-> dispatch_to(
#first arg needs to be the directory holding the PackageName.pm modules with no trailing "/". The args aftre the first are name of SPECIFIC packages to be loaded as needed by SOAP requests
#Failure to call out specific moudules below will allow the external SOAP modules to be loaded, but the overall module #INC path for other Perl modules will be blocked for security reasons
SOAP_MODULE_INCULDE, #name of the directory holding the PackageName.pm modules with no trailing "/"
"TechnicalMetaDataExtraction", #prod - wrapper for EXIFTool
"Ingest", #module (package) name
"ImageManipulation", #module (package) name
"FacebookBroadcast", #unfinished
"CompressDecompress", #unfinished
"ImageOCR", #prod - tesseract
"HandleDotNet", #prod
"Pipeline", #prod (needs work)
"TwitterBroadcast", #prototype
"Messaging", #prototype but text format email works
"Property", #development
"FileManager", #prototype
"PassThrough" #prod - module to do location conversion (URL -> Fedora Obj+DS, Fedora Obj+DS -> file, URL -> InlineBase64, etc.) but format conversion
) #done with the dispacth_to section
-> on_action(sub {
#on_action method lets you specify SOAPAction understanding. It acceptsreference to subroutine that takes three parameters: SOAPAction, method_uri and method_name.
#'SOAPAction' is taken from HTTP header and method_uri and method_name are extracted from request's body. Default behavior is match 'SOAPAction' if present and ignore it otherwise.
#die SOAP::Data->type('string')->name('debug')->value("Intercepted call, SOAP request='".shift(#_)."'");
if($Debug) {
##_ notes:
#[0] - "http://www.example.org/PassThrough/NewOperation"
#[1] - http://www.example.org/PassThrough/
#[2] - NewOperation
#[3] - "undefined"
my %DataHash=(
message => #_[0]
);
#SendMessageToAMQTopic(localtime()." - ".#_[0]);
SendDebugMessage(\%DataHash, "info");
} #there's only one element passed at this level
}) #end on_action
#-> on_debug() #not valid for SOAP::Transport::HTTP::CGI
#-> request() #valid, but does not fire - request method gives you access to HTTP::Request object which you can provide for Server component to handle request.
#-> response() #does not fire - response method gives you access to HTTP::Response object which you can access to get results from Server component after request was handled.
#-> options({compress_threshold => 10000}) #causes problems for the JavaScript soap client - removed for the moment
-> handle() #fires but ignores content in sub - handle method will handle your request. You should provide parameters with request() method, call handle() and get it back with response().
;
Initially I thought I could get the information I needed from the "on_action" method, but that only contains the destination of the SOAP call (before it is sent?) and I'm looking for data in the operation result that will be sent back to the SOAP client. The documentation of "SOAP::Transport::HTTP::CGI" is a bit thin and there are few examples online.
Anyone know if this is possible give the what the code above is set up? If not, then the only other option is to alter each method of my SOAP service code modules to include the "SendDebugMessage" function.
I would suggest subclassing SOAP::Transport::HTTP::CGI and hooking into the handle() method. An untested and probably non-working example would be:
package MySoapCGI;
use Data::Dumper;
use SOAP::Transport::HTTP;
use base 'SOAP::Transport::HTTP::CGI';
sub handle {
my $self = shift;
$self->SUPER::handle(#_);
warn Dumper($self->request);
warn Dumper($self->response);
}
Replace the dumpers with whatever logging you want. You may need to do some XML parsing, because these will be the raw HTTP::Request and HTTP::Response.
I am trying to receive data from the Web Service and I am getting the Data from Web Service back but it is form of [object Object]. Can anybody help me on this.
Below is the code for my web service:
public class WebServiceAccess
{
private var webService:WebService;
private var serviceOperation:AbstractOperation;
private var myValueObjects:ValueObjects;
private var method:String;
[Bindable]
public var employeeData:ArrayCollection;
[Bindable]
public var employees:ArrayCollection;
public function WebServiceAccess(url:String, method:String)
{
webService = new WebService();
this.method = method;
webService.loadWSDL(url);
webService.addEventListener(LoadEvent.LOAD, ServiceRequest);
}
public function ServiceRequest():void
{
serviceOperation = webService.getOperation(method);
serviceOperation.addEventListener(FaultEvent.FAULT, DisplayError);
serviceOperation.addEventListener(ResultEvent.RESULT, DisplayResult);
serviceOperation.send();
}
public function DisplayError(evt:FaultEvent):void
{
Alert.show(evt.fault.toString());
}
public function DisplayResult(evt:ResultEvent):void
{
employeeData = evt.result as ArrayCollection;
Alert.show(employeeData.toString());
}
}
First of all, evt.result is not an ArrayCollection, it is an Object (unless your SOAP service/WSDL are completely screwed up/malformed XML).
Second, you can't just display an Array or ArrayCollection (or generic Object, even) as a String (even though the .toString() method always seems to imply that) anyway, you have to parse the data to get what you want from it.
Now, the WebService class is nice in that it automatically parses the XML file that a SOAP service returns into a single usable Object. So that is actually the hard part.
What you need to do is call various properties of the object to get the data you need.
So if the XML return (look at your WSDL to see what the return should be, I also highly suggest soapUI) is this:
<employee name="Josh">
<start date="89384938984"/>
<photo url="photo.jpg"/>
</employee>
And you wanted to display "Josh" and the photo, you would do this.
var name:String = e.result.employee.name;
var url:String = e.result.employee.photo.url;
It does get more complicated. If the WSDL allows for multiple nodes with the same name at the same level, it does return an ArrayCollection. Then you have to loop through the array and find the exact item you need.
Just remember: The WSDL is god. Period. If it says there can be multiple "employee" nodes, you have to code accordingly, even if you don't see more than one in your tests. The issue is that there always could be multiple nodes.
I'm trying to implement simple web service client for PayPal Express Checkout API using JAX WS. PayPal Express Checkout API provides WSDL file, from which I was able to generate Java classes using CXF's wsdl2java utility.
From authentication reasons, it demands adding SOAP Header to each request. This header is quite simple and should look like here:
https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECSOAPAPIBasics#id09C3I0CF0O6
Generated from WSDL classes include ebay.apis.eblbasecomponents.CustomSecurityHeaderType class which represents header which I need to add to each request.
So the question is: how can I add manually created instance of CustomSecurityHeaderType class to SOAP request's header taking into account following conditions:
I'm not very eager to use classes from com.sun.* package as mentioned in answer here: JAX-WS - Adding SOAP Headers (mainly because of possible portability issues between different JDK's)
I don't want to manually marshal that object into nested javax.xml.soap.SOAPElement instances as mentioned in answer here:
How do I add a SOAP Header using Java JAX-WS
So, it looks like I've found possible answer while combining JAX-WS & JAXB related answers from SO (I would really appreciate if somebody experienced in these technologies can check whether following is correct):
The obvious thing for me is to add SOAP message handler and alter header of SOAPMessage instance in it:
import javax.xml.ws.Binding;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.Handler;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.soap.SOAPHeader;
import ebay.api.paypalapi.ObjectFactory; // class generated by wsdl2java
// following class is generated by wsdl2java utility Service class
final PayPalAPIInterfaceService payPalService = new PayPalAPIInterfaceService();
final PayPalAPIAAInterface expressCheckoutPort = payPalService.getPayPalAPIAA();
final Binding binding = ((BindingProvider) expressCheckoutPort).getBinding();
List<Handler> handlersList = new ArrayList<Handler>();
// now, adding instance of Handler to handlersList which should do our job:
// creating header instance
final CustomSecurityHeaderType headerObj = new CustomSecurityHeaderType();
final UserIdPasswordType credentials = new UserIdPasswordType();
credentials.setUsername("username");
credentials.setPassword("password");
credentials.setSignature("signature");
headerObj.setCredentials(credentials);
// bookmark #1 - please read explanation after code
final ObjectFactory objectFactory = new ObjectFactory();
// creating JAXBElement from headerObj
final JAXBElement<CustomSecurityHeaderType> requesterCredentials = objectFactory.createRequesterCredentials(headerObj);
handlersList.add(new SOAPHandler<SOAPMessageContext>() {
#Override
public boolean handleMessage(final SOAPMessageContext context) {
try {
// checking whether handled message is outbound one as per Martin Strauss answer
final Boolean outbound = (Boolean) context.get("javax.xml.ws.handler.message.outbound");
if (outbound != null && outbound) {
// obtaining marshaller which should marshal instance to xml
final Marshaller marshaller = JAXBContext.newInstance(CustomSecurityHeaderType.class).createMarshaller();
// adding header because otherwise it's null
final SOAPHeader soapHeader = context.getMessage().getSOAPPart().getEnvelope().addHeader();
// marshalling instance (appending) to SOAP header's xml node
marshaller.marshal(requesterCredentials, soapHeader);
}
} catch (final Exception e) {
throw new RuntimeException(e);
}
return true;
}
// ... default implementations of other methods go here
});
// as per Jean-Bernard Pellerin's comment setting handlerChain list here, after all handlers were added to list
binding.setHandlerChain(handlersList);
Explanation of bookmark #1:
one should marshal not the header object itself, but JAXBElement representing that object, because otherwise one will get an exception. One should use one of ObjectFactory classes which are generated from WSDL for creating needed JAXBElement instances from original objects.
(Thanks #skaffman for answer: No #XmlRootElement generated by JAXB )
One should also refer to Martin Straus answer which extends this one
This solution works great, but there's a catch. It generates this error when the inbound message is processed:
dic 19, 2012 7:00:55 PM com.sun.xml.messaging.saaj.soap.impl.EnvelopeImpl addHeader
SEVERE: SAAJ0120: no se puede agregar una cabecera si ya hay una
Exception in thread "main" javax.xml.ws.WebServiceException: java.lang.RuntimeException: com.sun.xml.messaging.saaj.SOAPExceptionImpl: Can't add a header when one is already present.
at com.sun.xml.ws.handler.ClientSOAPHandlerTube.callHandlersOnResponse(ClientSOAPHandlerTube.java:167)
at com.sun.xml.ws.handler.HandlerTube.processResponse(HandlerTube.java:174)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:1074)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:979)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:950)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:825)
at com.sun.xml.ws.client.Stub.process(Stub.java:443)
at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:174)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:119)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:102)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:154)
at $Proxy38.wsRdyCrearTicketDA(Unknown Source)
at ar.com.fit.fides.remedy.api.ws.ServicioCreacionTickets.crearTicket(ServicioCreacionTickets.java:55)
at ar.com.fit.fides.remedy.api.ws.ConectorRemedyWS.crearTicket(ConectorRemedyWS.java:43)
at ar.com.fit.fides.remedy.api.ws.ConectorRemedyWS.main(ConectorRemedyWS.java:90)
Caused by: java.lang.RuntimeException: com.sun.xml.messaging.saaj.SOAPExceptionImpl: Can't add a header when one is already present.
at ar.com.fit.fides.remedy.api.ws.AuthenticationHandler.handleMessage(AuthenticationHandler.java:50)
at ar.com.fit.fides.remedy.api.ws.AuthenticationHandler.handleMessage(AuthenticationHandler.java:23)
at com.sun.xml.ws.handler.HandlerProcessor.callHandleMessageReverse(HandlerProcessor.java:341)
at com.sun.xml.ws.handler.HandlerProcessor.callHandlersResponse(HandlerProcessor.java:214)
at com.sun.xml.ws.handler.ClientSOAPHandlerTube.callHandlersOnResponse(ClientSOAPHandlerTube.java:161)
... 14 more
Caused by: com.sun.xml.messaging.saaj.SOAPExceptionImpl: Can't add a header when one is already present.
at com.sun.xml.messaging.saaj.soap.impl.EnvelopeImpl.addHeader(EnvelopeImpl.java:128)
at com.sun.xml.messaging.saaj.soap.impl.EnvelopeImpl.addHeader(EnvelopeImpl.java:108)
at ar.com.fit.fides.remedy.api.ws.AuthenticationHandler.handleMessage(AuthenticationHandler.java:45)
So, the solution is to check whether the message being handled if the outbound message, like this:
public boolean handleMessage(SOAPMessageContext context) {
try {
Boolean outbound = (Boolean) context.get("javax.xml.ws.handler.message.outbound");
if (outbound != null && outbound) {
// obtaining marshaller which should marshal instance to xml
final Marshaller marshaller = JAXBContext.newInstance(AuthenticationInfo.class).createMarshaller();
// adding header because otherwise it's null
final SOAPHeader soapHeader = context.getMessage().getSOAPPart().getEnvelope().addHeader();
// marshalling instance (appending) to SOAP header's xml node
marshaller.marshal(info, soapHeader);
}
} catch (final Exception e) {
throw new RuntimeException(e);
}
return true;
}
I created a web service exposing method with params user and password as header like this:
#WebService(serviceName="authentication")
public class WSAuthentication {
String name = null;
String password = null;
public WSAuthentication() {
super();
}
public WSAuthentication(String name, String password) {
this.name = name;
this.password = password;
}
private static String getData(WSAuthentication sec) {
System.out.println("********************* AUTHENTICATION ********************" + "\n" +
"**********USER: " + sec.name + "\n" +
"******PASSWORD: " + sec.password + "\n" +
"******************************** AUTHENTICATION ****************************");
return sec.name + " -- " + sec.password;
}
#WebMethod(operationName="security", action="authenticate")
#WebResult(name="answer")
public String security(#WebParam(header=true, mode=Mode.IN, name="user") String user, #WebParam(header=true, mode=Mode.IN, name="password") String password) {
WSAuthentication secure = new WSAuthentication(user, password);
return getData(secure);
}
}
Try compiling it and testing generated from WSDL class. I hope this helps.
I found this answer:
JAX-WS - Adding SOAP Headers
Basically you add -XadditionalHeaders to the compiler options and objects in the headers also appear in your generated code as parameters of the method.
If you are using maven, and the jaxws-maven-plugin all you have to do is add the xadditionalHeaders flag to true and the client will be generated with the methods that have the headers as input.
https://jax-ws-commons.java.net/jaxws-maven-plugin/wsimport-mojo.html#xadditionalHeaders
I'm trying to create a code to allow an existing classic asp program to use an asp.net web service. Updating from the classic asp is not an option, as I'm working in a big company and things are the way they are.
I've been browsing through a chunk of tutorials supposedly helping in this, but I haven't managed to get them to work yet. As a beginner I might've made some real obvious mistakes but I just don't know what.
First, the web service is located on an external server. The method "Greeting" needs a String parameter by which it determines which String is sent back. Inputting "g" to it procudes this xml:
<?xml version="1.0" encoding="utf-8" ?>
<string xmlns="http://server1/Logger_WebService/">Greetings and welcome!</string>
I assume the xpath for getting the contents is either "string/*" or "*"?
Next, my web service itself looks like this:
<WebMethod()> _
Public Function Greeting(ByVal stringel As String) As String
If stringel.ToLower = "g" Then
Return "Greetings and welcome!"
Else
Return "Bye then!"
End If
End Function
The web service works fine from a regular asp.net solution.
Now here's the problem, the classic asp code looks like this (4 different ways I've tried to get this to work, SOAP toolkit is installed on the web service server, all examples taken and modified from tutorials):
'******* USING GET METHOD
Dim wsurl="http://server1/Logger_WebService/service.asmx/Greeting?g"
Dim xmlhttp
Set xmlhttp=Server.CreateObject("MSXML2.ServerXMLHTTP")
xmlhttp.open "GET",wsurl,false
xmlhttp.send
Dim rValue
'rValue=xmlhttp.responseXML.selectSingleNode("string") 'use XPATH as input argument
' or you can get response XML
rValue=xmlhttp.responseXML
Set xmlhttp=nothing
'------------------------------------------------------
'******* USING POST METHOD
Dim wsurl="http://server1/Logger_WebService/service.asmx/Greeting"
Dim xmlhttp
Set xmlhttp=Server.CreateObject("MSXML2.ServerXMLHTTP")
xmlhttp.open "POST",wsurl,false
xmlhttp.send "stringeli=g"
Dim rValue
rValue=xmlhttp.responseXML.selectSingleNode("string")
' or you can get response XML
' rValue=xmlhttp.responseXML
Set xmlhttp=nothing
'------------------------------------------------------
Response.Write consumeWebService()
Function consumeWebService()
Dim webServiceUrl, httpReq, node, myXmlDoc
webServiceUrl = "http://server1/Logger_WebService/service.asmx/Greeting?stringel=g"
Set httpReq = Server.CreateObject("MSXML2.ServerXMLHTTP")
httpReq.Open "GET", webServiceUrl, False
httpReq.Send
Set myXmlDoc =Server.CreateObject("MSXML.DOMDocument")
myXmlDoc.load(httpReq.responseBody)
Set httpReq = Nothing
Set node = myXmlDoc.documentElement.selectSingleNode("string/*")
consumeWebService = " " & node.text
End Function
'------------------------------------------------------
Response.Write(Helou())
Public Function Helou()
SET objSoapClient = Server.CreateObject("MSSOAP.SoapClient")
objSoapClient.ClientProperty("ServerHTTPRequest") = True
' needs to be updated with the url of your Web Service WSDL and is
' followed by the Web Service name
Call objSoapClient.mssoapinit("http://server1/Logger_WebService/service.asmx?WSDL", "Service")
' use the SOAP object to call the Web Method Required
Helou = objSoapClient.Greeting("g")
End Function
I seriously have no idea why nothing works, I've tried them every which way with loads of different settings etc. One possible issue is that the web service is located on a server which in ASP.Net required me to input this "[ServiceVariableName].Credentials = System.Net.CredentialCache.DefaultCredentials". I do this from within company network, and there are some security and authorization issues.
I only need to be able to send information anyhow, not receive, as the actual method I will be using is going to insert information into a database. But for now, just getting the Hello World thingie to work seems to provide enough challenge. :)
Thx for all the help. I'll try to check back on holiday hours to check and reply to the comments, I've undoubtedly left out needed information.
Please, talk as you would to an idiot, I'm new to this so chances are I can understand better that way. :)
You might consider writing a bit of .NET wrapper code to consume the web service. Then expose the .NET code as a COM object that the ASP can call directly. As you've seen, there is no tooling to help you in classic ASP, so consider using as much .NET as possible, for the tooling. Then, use COM to interoperate between the two.
A colleague finally got it working after putting a whole day into it. It was decided that it's easier by far to send information than it is to receive it. Since the eventual purpose of the web service is to write data to the DB and not get any message back, we attempted the thing by simply writing a file in the web service.
The following changes were needed:
First, in order to get it to work through the company networks, anonymous access had to be enabled in IIS.
The web service needed the following change in the web.config:
<webServices>
<protocols>
<add name="HttpGet"/>
</protocols>
</webServices>
And the web service code-behind was changed like so:
<WebMethod()> _
Public Function Greeting(ByVal stringel As String) As String
Dim kirj As StreamWriter
'kirj = File.CreateText("\\server1\MyDir\Logger_WebService\test.txt")
'if run locally, the line above would need to be used, otherwise the one below
kirj = File.CreateText("C:\Inetpub\serverroot\MyDir\Logger_WebService\test.txt")
kirj.WriteLine(stringel)
kirj.Close()
kirj.Dispose()
Return stringel
End Function
As we got the above to work, it was a simple matter of applying the same to the big web method that would parse and check the info and insert it into the database.
The classic asp code itself that needs to be added to the old page, which was the biggest problem, turned out to be relatively simple in the end.
function works()
message = "http://server1/mydir/logger_webservice/service.asmx/Greeting?" & _
"stringel=" & "it works"
Set objRequest = Server.createobject("MSXML2.XMLHTTP")
With objRequest
.open "GET", message, False
.setRequestHeader "Content-Type", "text/xml"
.send
End With
works = objRequest.responseText
end function
works()
Took about a week's worth of work to get this solved. :/ The hardest part was simply not ever knowing what was wrong at any one time.
You might be missing the SOAPAction header. Here's a working example:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class GreetingService : WebService
{
[WebMethod]
public string Greet(string name)
{
return string.Format("Hello {0}", name);
}
}
And the calling VBS script:
Dim SoapRequest
Set SoapRequest = CreateObject("MSXML2.XMLHTTP")
Dim myXML
Set myXML = CreateObject("MSXML.DOMDocument")
myXML.Async=False
SoapRequest.Open "POST", "http://localhost:4625/GreetingService.asmx", False
SoapRequest.setRequestHeader "Content-Type","text/xml;charset=utf-8"
SoapRequest.setRequestHeader "SOAPAction", """http://tempuri.org/Greet"""
Dim DataToSend
DataToSend= _
"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:tem=""http://tempuri.org/"">" & _
"<soapenv:Header/>" & _
"<soapenv:Body>" & _
"<tem:Greet>" & _
"<tem:name>John</tem:name>" & _
"</tem:Greet>" & _
"</soapenv:Body>" & _
"</soapenv:Envelope>"
SoapRequest.Send DataToSend
If myXML.load(SoapRequest.responseXML) Then
Dim Node
Set Node = myXML.documentElement.selectSingleNode("//GreetResult")
msgbox Node.Text
Set Node = Nothing
End If
Set SoapRequest = Nothing
Set myXML = Nothing
Might want to double-check the version of the MSXML components. Are you using Windows Authentication? I've noticed some odd XML parsing problems with IIS 7, Classic ASP, and MSXML.
It would also help to get a useful error. Check the ** myXML.parseError.errorCode** and if its not 0 write out the error.
Reference Code:
If (myXML.parseError.errorCode <> 0) then
Response.Write "XML error: " & myXML.parseError.reason
Else
'no error, do whatever here
End If
'You get the idea...