Classic Asp Web Service Problem - web-services

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...

Related

SendGrid V3 api with C# not able to send mail from Console Application

I am not able to send email with SendGrid using the V3 API in a console application. It works fine in my Web Application. I created a test console project and used the sample code from the SendGrid site. When the command to send the message is called, the application simply exits. I cannot read any response from the call.
This is in VB.Net. Sorry, I think I am the only person on Earth who codes in VB.
If I execute this code in the sample sendgrid-csharp-main from GitHub, it works fine. I cannot find anything in the sample code that looks any different from my code in the section that actually calls the send message part (other than having to convert to VB).
Does anyone see ANYTHING wrong in this code? I am using the .Net 4.7.2 framework.
This is the entirety of the test code. I have been spinning my wheels searching for help for too long and I am desperate now.
Imports System.Net.Http
Imports SendGrid
Imports SendGrid.Helpers.Mail
Module Module1
Sub Main()
TryIt().ConfigureAwait(True)
End Sub
Private Async Function TryIt() As Task
Dim HttpClient As HttpClient = New HttpClient()
Dim apiKey = "my private api key"
Dim client = New SendGridClient(HttpClient, New SendGridClientOptions With {
.ApiKey = apiKey,
.HttpErrorAsException = True
})
Dim from = New EmailAddress("msie#msinvoiceExchange.com", "MSIE")
Dim subject = "Hello World from the Twilio SendGrid CSharp Library Helper!"
Dim toEmail = New EmailAddress("joe#invoicesanywhere.com", "Joe")
Dim plainTextContent = "Hello, Email from the helper [SendSingleEmailAsync]!"
Dim htmlContent = "<strong>Hello, Email from the helper! [SendSingleEmailAsync]</strong>"
Dim msg As New SendGridMessage With {
.From = from,
.Subject = subject,
.PlainTextContent = plainTextContent,
.HtmlContent = htmlContent
}
msg.AddTo(toEmail)
Dim myResponse As Response
myResponse = Await client.SendEmailAsync(msg)
Console.WriteLine(msg.Serialize())
Console.WriteLine(myResponse.StatusCode)
Console.WriteLine(myResponse.Headers)
Console.WriteLine(vbLf & vbLf & "Press <Enter> to continue.")
Console.ReadLine()
End Function
End Module
It figures. As soon as I get desperate enough to post a question, I figure out something that works.
I just hope that someone else has the same problem and finds this answer helpful.
This is the change I had to make to get this to work
Sub Main()
TryIt().Wait()
End Sub

GetHostedProfilePage not honouring hostedProfileBillingAddressOptions setting

I've been trying to update our API call to the CIM interface for Authorize.net to hide the Billing Address fields on the hosted profile page.
The documentation states that when call the token creation function, passing in a setting "hostedProfileBillingAddressOptions" with a value of "showNone" will hide the billing address part of the form, however when I pass in this setting I am still getting the billing address showing.
I've verified that I'm passing the setting correctly (added the same way as the "hostedProfileIFrameCommunicatorUrl" and "hostedProfilePageBorderVisible" settings) and if I pass an invalid value for the "hostedProfileBillingAddressOptions" option, the Token creation function will return an error
Is there something else that this option is dependent on, such as an account setting or another settings parameter?
For reference, I'm testing this in the Sandbox system and I'm using the dotNet SDK, my test code for calling the API function is as follows
Public Shared Function CreateHostFormToken(apiId As String, apiKey As String, branchId As Int64, nUser As Contact, iframeComURL As String) As String
Dim nCustProfile = GetCustomerProfile(apiId, apiKey, branchId, nUser)
Dim nHost = New AuthorizeNet.Api.Contracts.V1.getHostedProfilePageRequest()
nHost.customerProfileId = nCustProfile
' Set Auth
Dim nAuth = New Api.Contracts.V1.merchantAuthenticationType()
nAuth.ItemElementName = Api.Contracts.V1.ItemChoiceType.transactionKey
nAuth.name = apiId
nAuth.Item = apiKey
nHost.merchantAuthentication = nAuth
' Set Params
Dim settingList As New List(Of Api.Contracts.V1.settingType)
Dim nParam As New Api.Contracts.V1.settingType With {.settingName = "hostedProfileIFrameCommunicatorUrl",
.settingValue = iframeComURL}
settingList.Add(nParam)
nParam = New Api.Contracts.V1.settingType With {.settingName = "hostedProfilePageBorderVisible",
.settingValue = "false"}
settingList.Add(nParam)
nParam = New Api.Contracts.V1.settingType With {.settingName = "hostedProfileBillingAddressOptions",
.settingValue = "showNone"}
settingList.Add(nParam)
nHost.hostedProfileSettings = settingList.ToArray
Dim nX = New AuthorizeNet.Api.Controllers.getHostedProfilePageController(nHost)
Dim nRes = nX.ExecuteWithApiResponse(GetEnvironment())
Return nRes.token
End Function
I've looked through the SDK code as well, and I don't see anything there that would be preventing the setting from being passed through.
Has anyone come across this issue, or successfully set the card entry form to hide the billing address?
There turned out to be two parts to the solution to this problem:
In order to use the "hostedProfileBillingAddressOptions" option, you need to use a newer version of the capture page than I was using. I was using "https://secure2.authorize.net/profile/", while the new version is "https://secure2.authorize.net/customer/". Added bonus, the new URL provides a much nicer and modern looking form.
However, once this was working, I then had the problem that on entering the card, a validation message told me that "address and Zip code are required", despite not being visible. I did also make sure that I had the option "hostedProfileBillingAddressRequired" set to false (which is it's default value anyway)
The response from Authorize.net support is that in order to capture card without an address, the option "hostedProfileValidationMode" must be set to "testMode".
This is not mentioned in the documentation (at least as far as I could see), so may not be something that other people are aware of since it is a little counter-intuitive to use 'testMode' on a live environment.
It's not ideal since validating the card for a customer account will send a transaction email to the merchant, but it seems there is not another way around this just now.
In summary, to allow the customer to add a credit card to their profile without having to provide an address, you need to specify the following options:
Form URL for capture - https://secure2.authorize.net/customer/
getHostedProfilePageRequest -
hostedProfileIFrameCommunicatorUrl: *your URL*
hostedProfilePageBorderVisible: false //assuming you are using an iFrame
hostedProfileValidationMode: testMode
hostedProfileBillingAddressOptions: showNone

How can I add characters at the end of my xml response?

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.

Unable to access WMI on remote machine using vb.net

I've had a scout around and can't seem to find the answer anywhere, so need to ask.
I'm trying to query the WMI on a remote machine, but I need to do so as the admin account and I'm having problems doing so.
The code I am using is:
Public Sub OperatingSystem(ByVal computeritem As String)
'set Username and Password which system will access the network with.
Dim options As ConnectionOptions
options = New ConnectionOptions()
options.Authority = "ntdlmdomain:" & ipaddress
options.Username = "Username"
options.Password = "Password"
scope = New ManagementScope("\\" & ipaddress & "\root\cimv2", options)
scope.Connect()
Dim query As ObjectQuery
query = New ObjectQuery("SELECT * FROM Win32_OperatingSystem")
Dim searcher As ManagementObjectSearcher
searcher = New ManagementObjectSearcher(scope, query)
the query continues to go and pull all kinds of information through to a spradsheet.. well it would if it worked!
The line of code that is falling over is:
scope = New ManagementScope("\\" & ipaddress & "\root\cimv2", options)
scope.Connect()
It's giving me an error message that just says 'Invalid parameter'. When I go to view detail, there's nothing in inner exception and the only thing that I can see of any value is ErrorCode:ManagementStatus.InvalidParameter
I apologize if this is something really simple.. I am still fairly new to this but if someone could give me some guidance that would really be appreciated.
Many Thanks.
It looks like the reference to ipaddress is not initialized. Since computeritem is passed as a parameter to the sub, your code might work better with:
scope = New ManagementScope("\\" & computeritem & "\root\cimv2", options)

SBL-ODU-01007 The HTTP request did not contain a valid SOAPAction header

I am hoping someone can help get me in the right direction...
I am using Powerbuilder 12 Classic and trying to consume a Oracle CRM OnDemand web service.
Using Msxml2.XMLHTTP.4.0 commands, I have been able to connect using https and retrieve the session id, which I need to send back when I invoke the method.
When I run the code below, I get the SBL-ODU-01007 The HTTP request did not contain a valid SOAPAction header error message. I am not sure what I am missing??
OleObject loo_xmlhttp
ls_get_url = "https://secure-ausomxxxx.crmondemand.com/Services/Integration?command=login"
try
loo_xmlhttp = CREATE oleobject
loo_xmlhttp.ConnectToNewObject("Msxml2.XMLHTTP.4.0")
loo_xmlhttp.open ("GET",ls_get_url, false)
loo_xmlhttp.setRequestHeader("UserName", "xxxxxxx")
loo_xmlhttp.setRequestHeader("Password", "xxxxxxx")
loo_xmlhttp.send()
cookie = loo_xmlhttp.getResponseHeader("Set-Cookie")
sesId = mid(cookie, pos(cookie,"=", 1)+1, pos(cookie,";", 1)-(pos(cookie,"=", 1)+1))
ls_post_url = "https://secure-ausomxxxx.crmondemand.com/Services/Integration/Activity;"
ls_response_text = "jsessionid=" + sesId + ";"
ls_post_url = ls_post_url + ls_response_text
loo_xmlhttp.open ("POST",ls_post_url, false)
loo_xmlhttp.setRequestHeader("COOKIE", left(cookie,pos(cookie,";",1)-1) )
loo_xmlhttp.setRequestHeader("COOKIE", left(cookie,pos(cookie,";",1)-1) )
ls_post_url2 = "document/urn:crmondemand/ws/activity/10/2004:Activity_QueryPage"
loo_xmlhttp.setRequestHeader("SOAPAction", ls_post_url2)
loo_xmlhttp.send()
ls_get_url = "https://secure-ausomxxxx.crmondemand.com/Services/Integration?command=logoff"
loo_xmlhttp.open ("POST",ls_get_url, false)
loo_xmlhttp.send()
catch (RuntimeError rte)
MessageBox("Error", "RuntimeError - " + rte.getMessage())
end try
I believe you are using incorrect URL for Login and Logoff;
Here is the sample:
https://secure-ausomxxxx.crmondemand.com/Services/Integration?command=login
https://secure-ausomxxxx.crmondemand.com/Services/Integration?command=logoff
Rest of the code looks OK to me.
I have run into similar issues in PB with msxml through ole. Adding this may help:
loo_xmlhttp.setRequestHeader("Content-Type", "text/xml")
you need to make sure that the your value for ls_post_url2 is one of the values that is found in the wsdl file. Just search for "soap:operation soapAction" in the wsdl file to see the valid values for SOAPAction.