Using VBA to consume WCF web service, how to change binding? - ms-access

I am working on an Access 2010 'tool' that will hopefully allow me to sync our local Access database with an online one (hosted on a server that we have zero control over or direct access to). My background is not in VBA or VB.net so I am fairly new to this language so any help or suggestions would be appreciated. So far this is what I have written as a test to verify the ability to connect and to better understand what is returned when we do get a valid response.
Public Sub SendXML()
Dim myHTTP As MSXML2.ServerXMLHTTP60
Dim myDom As MSXML2.DOMDocument
Dim myXML As String
Set myHTTP = CreateObject("MSXML2.ServerXMLHTTP.6.0")
Set myDom = CreateObject("MSXML2.DOMDocument")
myDom.async = False
myXML = "<s:Envelope xmlns:a=" & Chr(34) & "http://www.w3.org/2005/08/addressing" & Chr(34) & "xmlns:s=" & Chr(34) & "http://www.w3.org/2003/05/soap-envelope" & Chr(34) & "><s:Header><a:Action s:mustUnderstand=" & Chr(34) & "1" & Chr(34) & ">http://tempuri.org/IWcfService/Get_InitiativeList_CSV</a:Action></s:Header><s:Body><Get_InitiativeList_CSV xmlns=" & Chr(34) & "http://tempuri.org/" & Chr(34) & "><userID>MYUSERID</userID></Get_InitiativeList_CSV></s:Body></s:Envelope>"
myDom.LoadXML (myXML)
myHTTP.Open "post", "https://server/WcfService/WcfService.svc", False
myHTTP.setRequestHeader "Content-Type", "application/xml"
'myHTTP.send (myDom.XML)
myHTTP.send (myXML)
MsgBox myHTTP.responseText
End Sub
I get back:
The server cannot service the request because the media type is unsupported.
A couple things to note above. I tried two different way to create the XML string. One creating it as you see above and sending that raw text to the server. And creating the string as you see above and using loadXML to create the string. I do not know why one would be better than the other but both returned the same error.
Now, I have tried SOA Cleaner Express and am able to connect successfully to the service and get data back. Since SOA Cleaner is able to connect I figured using the RAW SOAP/XML string SOA sends in VBA might be a good starting point. I noticed that using SOA cleaner it has a WCF Binding as WsHttpBinding and if I change this binding to BasicHttpBindingI get a similar error message as I am getting in VBA, to be exact:
Content Type text/xml; charset=utf-8 was not supported by service
Not even sure I am going in the right direction, but if I am, how do I set or change the 'binding' in VBA? Is there something else going on here? I am sure it is something simple, but like I said I do not have a VBA background, and WCF and SOAP are somewhat new to me as well.
I appreciate any assistance.

For starters, the binding from the client must match the service, so if the service only supports wsHttpBinding, the client must use that as well.
For added flexiblity calling a WCF service from VBA, including the ability to specify the binding, you may want to use monikers instead. Here is an example of service monkier being constructed and used in VBA:
Dim addr As String
addr = "service:mexAddress=""net.tcp://localhost:7891/Test/WcfService1/Service1/Mex"","
addr = addr + "address=""net.tcp://localhost:7891/Test/WcfService1/Service1/"","
addr = addr + "contract=""IService1"", contractNamespace=""http://tempuri.org/"","
addr = addr + "binding=""NetTcpBinding_IService1"", bindingNamespace=""http://tempuri.org/"""
Dim service1 As Object
Set service1 = GetObject(addr)
MsgBox service1.GetData(12)
Here are some links with more info, including the source of this code snippet:
http://msdn.microsoft.com/en-us/library/ms752245(v=vs.110).aspx
http://damianblog.com/2009/07/05/excel-wcf/

This may be far-fetched, but given that the second error is more descriptive than the first error, have you tried specifying the charset?
myHTTP.setRequestHeader "Content-Type", "application/xml; charset=utf-8"

Related

Error Handler Not working in Function VBA Access 2013

So I have a function that allows the user to email an updated picture for an asset which works fine and good except if the user closes the email before sending. I have an error handler set up but it doesn't seem to capture the error. Here is my function code:
Function Email()
Globals.Logging "Opened Email for updating picture"
On Error GoTo ErrorHandler:
Dim strTagNumber As String
strTagNumber = Me.txtTagNumber.Value
Dim varName As Variant
Dim varCC As Variant
Dim varSubject As Variant
Dim varBody As Variant
varName = "myAnon#email.test"
varCC = ""
varSubject = "Updated Picture for Asset Number " & strTagNumber
varBody = "Sent by MS Access"
DoCmd.SendObject , , , varName, varCC, , varSubject, varBody, True, False
Globals.Logging "Sent Email"
Cleanup:
varName = Nothing
varCC = Nothing
varSubject = Nothing
varBody = Nothing
Exit Function
ErrorHandler:
Select Case Err.Number
Case 2501
MsgBox "Email message was Cancelled."
Globals.Logging "Canceled Email"
Case Else
MsgBox Err.Number & ": " & Err.Description
Globals.Logging "Email Error " & Err.Number & ": " & Err.Description
End Select
Resume Cleanup
End Function
Any help would be appreciated. Thank you in advance.
As described in online documentation, DoCmd.SendObjects
... uses the Mail Applications Programming Interface (MAPI)
In other words, Access (or Excel) does not actually have its own email capability. It is dependent upon a properly installed and configured MAPI email client. Unless you have purposefully installed and setup another default email client on Windows, the default is likely Outlook if you have it installed with MS Office. Windows email clients have changed with the many version of Windows, but the default might also be a simple Windows email client.
It is very likely that the MAPI client could be showing the error message, then not actually throwing/raising the error before it returns program flow back to the VBA module which initiated the call.
I recall being aware at some point of an Outlook setting that dictated certain behavior for MAPI and/or COM Automation interfaces, whether it showed errors or not. I usually would not throw out such wishy-washy info on Stack Overflow before verifying, but from what I see of the discussion around this issue, nobody really addresses this aspect of SendObjects.
Besides using Automation to send email via Outlook as other have suggested, you could inspect the Windows default email client settings. Perhaps test another email client to see if you get different results.
Tested on Access 2016. The error is captured and I can see the message box saying "Email message was Cancelled.".
Maybe you can try to use Outlook object for sending the email too.

User management in Microsoft Access 2013 databases

I am building a system using Microsoft Access 2013 that uses MySQL as a backend. I am trying to figure out a way to do some kind of basic user management, ideally in such a way that users would have to "log in" when they launch the database, and then their username would be easily accessible by the system while they are using it. I've tried searching for solutions, but most of them just tell me to use Office 365 or sharepoint, which are not options at the moment. Does anyone have an idea of how to accomplish this? Thanks in advance!
I recommend building your own user storage and login system. You'll basically need to create your own users table (in MySQL in your case), make forms to manage users, make a Login form, and write code to control the login process.
Logging in usually consists of checking some kind of credentials they type in against existing data in your users table. You can usually do this in Access with DLookup or DCount statements but I usually end up using a DAO or ADO recordset instead since I like to pull out more than one value from the User's table and I also like to write things back to it right away, like the LastLogin datetime, LastLogin computername, etc.
I actually wrote an example database which you can download here. It needs a rewrite. I've changed quite a few of my practices since Jan, 2011. But give me another year and it would need another rewrite.
I usually program the login form so that the user enters their initials and then a password. If you go this route you need to have a unique index setup on the Initials field to prevent duplicates. If you're going to have a lot of users you need to use a Username instead, which could still theoretically be the users initials.
Here's what my code would look like to authenticate a user. Be aware that this is far from truly secure. This assumes that passwords are stored in plain text. Users could theoretically try to do SQL Inject from here because I'm not use a parametrized query or stripping out special characters from their input such as # or ;.
Private Function AuthenticateUser() As Boolean
Dim sInitials As String
Dim sPassword As String
sInitials = Trim(Nz(Me.txtInitials, ""))
sPassword = Trim(Nz(Me.txtPassword, ""))
If sInitials = "" Or sPassword = "" Then
'Logging in with blank passwords is not allowed
AuthenticateUser = False
Exit Function
End If
If DCount("EmployeeID", "tblEmployees", "[Initials] = '" & Replace(sInitials, "'", "''") & "' AND Password = '" & Replace(sPassword, "'", "''") & "'", True) = 0 Then
MsgBox "Invalid Credentials."
AuthenticateUser = False
Exit Function
Else
Dim rs As New DAO.Recordset
Dim sSQL As String
sSQL = "SELECT * FROM tblEmployees WHERE initials = '" & Replace(sInitials, "'", "''") & "'"
Set rs = CurrentDb.OpenRecordset(sSQL)
If Not (rs.EOF And rs.BOF) Then
'Config is an instance of a User Defined Type. It could also be a class object.
Config.UserInitials = rs("Initials")
Config.UserFullName = rs("EmployeeName")
Config.UserID = rs("EmployeeID")
rs.Edit
rs("LastLoginDateTime") = Now()
rs("LastLoginComputer") = "Function Required to Get Computer Name"
rs("ProgVersion") = "Your Program Version Number"
rs("CurrentDbPath") = Left(CurrentProject.path & "\" & CurrentProject.Name, 254)
rs.Update
End If
rs.Close
Set rs = Nothing
AuthenticateUser = True
End If
End Function
In my applications I use a global object, in this case an instance of a User Defined Type, which I call Config. I store any kind of application runtime related settings in there for the duration of the runtime of the application. Of course this object gets destroyed when the user closes out of the application or when a code reset happens (which cannot happen in Access runtime, but does happen frequently during development). You could use a class object instead of a User Defined Type. Or you could use individual global variables for everything, which I don't recommend (that's what I used to do). A User Defined Type simply allows you to group global variables together and gives you an easy way to refer to them in your code during design time by typing in Config., which then brings up every option using Intellisense (assuming you have it enabled).
If you want your settings to survive a code reset, you need to use TempVars. TempVars became available with Access 2007. I do not use them now (contrary to my example database) because they are not strongly typed. There's no Intellisense to help you get the correct TempVar and you can technically refer to a TempVar that doesn't even exist and Access won't throw an error. I think TempVars is really just a Dictionary object with all of it's shortcomings, and the single benefit of surviving a code reset. I can imagine storing a Connection String in there, but I wonder if it's worth using TempVars for anything at all. If a code reset happens, my entire application needs to be reloaded anyway since I setup a lot of global objects and variables when the application first opens and the user first logs in.
FYI, in previous versions of Access there was user security built in. I think Microsoft discontinued that starting in 2007. I never really used it so I didn't miss it when it got discontinued.

Trouble Adding Web Service to VS2010 for SSRS CLR Stored Proc

I am attempting to reference the SSRS web service and it is not going as expected, please let me know what I'm doing wrong.
In VS 2010:
Step 1) Add Service Reference
Address=http://myserver/reportserver/reportservice2005.asmx?wsdl (server does not have a named instance)
name = ReportingServices2005_BETA
Step 2) Then in my clr_sproc I write:
_
Public Shared Sub TestMonkey2(RptName As SqlString,
Params As SqlString,
FileName As SqlString)
Dim rs As New ReportingServices2005_BETA()
Result:
I get an error in the error list "Error 1 Type expected"
I can write these lines without error...
Dim rs As New ReportingServices2005_BETA.Job
Dim rs As New ReportingServices2005_BETA.Role
Dim rs As New ReportingServices2005_BETA.Task
but those to not match all of the tutorials on the web?
I know I'm missing something simple...
thanks
Found my problem, I was adding a Service Reference instead of a Web Reference, problem solved.
But in the long run, I found you cannot use ReportingServices2005 in a CLR due to security restrictions. I'm back to the drawing board.
dang.

MS Access 2010 now asks for parameters on form load

I've been writing MS Access apps for a long time. I just switched to Access 2010 and now wherever I open a form in which I'm creating the InputParameters in code, the app prompts me to enter the parameters. I'm baffled and can't figure this out.
The following code has worked on all previous versions of MS Access until Access 2010:
Dim strRS As String
Dim lngID as Long
Dim intSomethignElse as Integer
strRS = "dbo.StoredProcedureName"
lngID = 1
intSomethignElse = 2
Forms!SomeFormName.InputParameters = "#parameter1 = " & lngID & ", #parameter2 = " & intSomethignElse
'Verify the parameters do indeed exist and they do:
Debug.Print Forms!SomeFormName.InputParameters
Forms!SomeFormName.RecordSource = strRS
Now when the form loads I get prompted to enter #parameter1 and #parameter2.
How do I get this to work again in MS Access 2010?
Any help is appreciated.
I had the similar VBA code. It worked fine in Access 2010 until recently and I got the same issue as the pop up window asking for parameters.
After I change the code to simliar to
Forms!SomeFormName.RecordSource = "exec dbo.StoredProcedureName #parameter=" & lngID
as Remou suggested in the comments, my application works again.
May be the RecordSource is not empty. Make sure it is empty in design view.
EDIT:
msdn says: The stored procedure should be executed using a command string containing the {call } syntax with one ? marker for each non-default parameter in the InputParameters list.
I do not know the call syntax, but I would try something like this:
strRS = "exec dbo.StoredProcedureName ?, ?"

ADODB Connection String: Workgroup Information file is Missing?

I have a few data sources in access that I need to connect to programatically to do things with behind the scenes and keep visibility away from users.
Said datasource has a password 'pass' as I'm going to call it here. Using this connection method I get an error attempting to use the open method
Dim conn as ADODB.Connection
Set ROBBERS.conn = New ADODB.Connection
conn.open "Provider=Microsoft.Jet.OLEDB.4.0;" _
& "Data Source=\\pep-home\projects\billing\autobilling\DPBilling2.mdb;" _
& "Jet OLEDB:Database Password=pass;", "admin", "pass"
"Cannot start your application. The workgroup information file is missing or opened exclusively by another user."
Due to planning to move into 2007, we are not using nor have ever used a workgroup identification file through access. The database password on the data source was set through the Set Databa Password which had to be done on an exclusive open.
Ive spent a good while changing around my connection options, where to put the passwords etc and either cannot find the right format, or (why I'm asking here) I think there may be some other unknown that I must setup to do this. Anyone out there got some useful information?
Your connection string seems to be incorrect. Try:
conn.open "Provider=Microsoft.Jet.OLEDB.4.0;" _
& "Data Source=\\pep-home\projects\billing\autobilling\DPBilling2.mdb;" _
& "Jet OLEDB:Database Password=MyDbPassword;"
-- http://www.connectionstrings.com/access