【发布时间】:2017-05-15 18:05:44
【问题描述】:
我正在使用 WCF 服务和 Quickbooks Web 连接器将 Quickbooks 桌面与 opencart 集成。但是我在调用验证方法时遇到了这个错误。
这是我的 .cs 代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using Interop.QBPOSXMLRPLIB;
namespace QuickBookWebConnector
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
// NOTE: In order to launch WCF Test Client for testing this service, please select Service1.svc or Service1.svc.cs at the Solution Explorer and start debugging.
public class Service1 : IService1
{
//public const string DATE_FORMAT = "yyyy-MM-ddTHH\\:mm\\:sszzz";
System.Diagnostics.EventLog evLog = new System.Diagnostics.EventLog();
public int count = 0;
public ArrayList req = new ArrayList();
public const string URL = "http://developer.intuit.com/";
public Service1()
{
initEvLog();
}
public string clientVersion(string strVersion)
{
string evLogTxt = "WebMethod: clientVersion() has been called " +
"by QBWebconnector" + "\r\n\r\n";
evLogTxt = evLogTxt + "Parameters received:\r\n";
evLogTxt = evLogTxt + "string strVersion = " + strVersion + "\r\n";
evLogTxt = evLogTxt + "\r\n";
string retVal = null;
double recommendedVersion = 1.5;
double supportedMinVersion = 1.0;
double suppliedVersion = Convert.ToDouble(this.parseForVersion(strVersion));
evLogTxt = evLogTxt + "QBWebConnector version = " + strVersion + "\r\n";
evLogTxt = evLogTxt + "Recommended Version = " + recommendedVersion.ToString() + "\r\n";
evLogTxt = evLogTxt + "Supported Minimum Version = " + supportedMinVersion.ToString() + "\r\n";
evLogTxt = evLogTxt + "SuppliedVersion = " + suppliedVersion.ToString() + "\r\n";
if (suppliedVersion < recommendedVersion)
{
retVal = "W:We recommend that you upgrade your QBWebConnector";
}
else if (suppliedVersion < supportedMinVersion)
{
retVal = "E:You need to upgrade your QBWebConnector";
}
evLogTxt = evLogTxt + "\r\n";
evLogTxt = evLogTxt + "Return values: " + "\r\n";
evLogTxt = evLogTxt + "string retVal = " + retVal;
logEvent(evLogTxt);
return retVal;
}
public string[] authenticate(string strUserName, string strPassword)
{
string evLogTxt = "WebMethod: authenticate() has been called by QBWebconnector" + "\r\n\r\n";
evLogTxt = evLogTxt + "Parameters received:\r\n";
evLogTxt = evLogTxt + "string strUserName = " + strUserName + "\r\n";
evLogTxt = evLogTxt + "string strPassword = " + strPassword + "\r\n";
evLogTxt = evLogTxt + "\r\n";
string[] authReturn = new string[4];
// Code below uses a random GUID to use as session ticket
// An example of a GUID is {85B41BEE-5CD9-427a-A61B-83964F1EB426}
authReturn[0] = System.Guid.NewGuid().ToString();
// For simplicity of sample, a hardcoded username/password is used.
// In real world, you should handle authentication in using a standard way.
// For example, you could validate the username/password against an LDAP
// or a directory server
string pwd = "test";
evLogTxt = evLogTxt + "Password locally stored = " + pwd + "\r\n";
if (strUserName.Trim().Equals("Sysadmin") && strPassword.ToUpper().Trim().Equals(pwd.ToUpper()))
{
// An empty string for authReturn[1] means asking QBWebConnector
// to connect to the company file that is currently openned in QB
authReturn[1] = "technics";
}
else
{
authReturn[1] = "nvu";
}
// You could also return "none" to indicate there is no work to do
// or a company filename in the format C:\full\path\to\company.qbw
// based on your program logic and requirements.
authReturn[2] = "10";
authReturn[3] = "20";
evLogTxt = evLogTxt + "\r\n";
evLogTxt = evLogTxt + "Return values: " + "\r\n";
evLogTxt = evLogTxt + "string[] authReturn[0] = " + authReturn[0].ToString() + "\r\n";
evLogTxt = evLogTxt + "string[] authReturn[1] = " + authReturn[1].ToString();
evLogTxt = evLogTxt + "string[] authReturn[2] = " + authReturn[2].ToString();
evLogTxt = evLogTxt + "string[] authReturn[3] = " + authReturn[3].ToString();
logEvent(evLogTxt);
return authReturn;
}
public string connectionError(string ticket, string hresult, string message)
{
//if (Session["ce_counter"] == null)
//{
// Session["ce_counter"] = 0;
//}
string evLogTxt = "WebMethod: connectionError() has been called by QBWebconnector" + "\r\n\r\n";
evLogTxt = evLogTxt + "Parameters received:\r\n";
evLogTxt = evLogTxt + "string ticket = " + ticket + "\r\n";
evLogTxt = evLogTxt + "string hresult = " + hresult + "\r\n";
evLogTxt = evLogTxt + "string message = " + message + "\r\n";
evLogTxt = evLogTxt + "\r\n";
string retVal = null;
//-2147418113 = Can't connect to the database
const string CANT_CONNECT_TO_DB = "0x8000FFFF";
// Add more as you need...
if (hresult.Trim().Equals(CANT_CONNECT_TO_DB))
{
evLogTxt = evLogTxt + "HRESULT = " + hresult + "\r\n";
evLogTxt = evLogTxt + "Message = " + message + "\r\n";
retVal = "DONE";
}
else
{
//// Depending on various hresults return different value
//if ((int)Session["ce_counter"] == 0)
//{
// // Try again with this company file
// evLogTxt = evLogTxt + "HRESULT = " + hresult + "\r\n";
// evLogTxt = evLogTxt + "Message = " + message + "\r\n";
// evLogTxt = evLogTxt + "Sending connection string as \"Company Data=\" to QBWebConnector.";
// retVal = "Company Data=";
//}
//else
//{
// evLogTxt = evLogTxt + "HRESULT = " + hresult + "\r\n";
// evLogTxt = evLogTxt + "Message = " + message + "\r\n";
// evLogTxt = evLogTxt + "Sending DONE to stop.";
// retVal = "DONE";
//}
// Try again with this company file
evLogTxt = evLogTxt + "HRESULT = " + hresult + "\r\n";
evLogTxt = evLogTxt + "Message = " + message + "\r\n";
evLogTxt = evLogTxt + "Sending connection string as \"Company Data=\" to QBWebConnector.";
retVal = "Company Data=";
}
evLogTxt = evLogTxt + "\r\n";
evLogTxt = evLogTxt + "Return values: " + "\r\n";
evLogTxt = evLogTxt + "string retVal = " + retVal + "\r\n";
logEvent(evLogTxt);
// Session["ce_counter"] = ((int)Session["ce_counter"]) + 1;
return retVal;
}
public string sendRequestXML(string ticket, string strHCPResponse, string strCompanyFileName,
string qbXMLCountry, int qbXMLMajorVers, int qbXMLMinorVers)
{
//if (Session["counter"] == null)
//{
// Session["counter"] = 0;
//}
string evLogTxt = "WebMethod: sendRequestXML() has been called by QBWebconnector" + "\r\n\r\n";
evLogTxt = evLogTxt + "Parameters received:\r\n";
evLogTxt = evLogTxt + "string ticket = " + ticket + "\r\n";
evLogTxt = evLogTxt + "string strHCPResponse = " + strHCPResponse + "\r\n";
evLogTxt = evLogTxt + "string strCompanyFileName = " + strCompanyFileName + "\r\n";
evLogTxt = evLogTxt + "string qbXMLCountry = " + qbXMLCountry + "\r\n";
evLogTxt = evLogTxt + "int qbXMLMajorVers = " + qbXMLMajorVers.ToString() + "\r\n";
evLogTxt = evLogTxt + "int qbXMLMinorVers = " + qbXMLMinorVers.ToString() + "\r\n";
evLogTxt = evLogTxt + "\r\n";
ArrayList req = buildRequest();
string request = "";
int total = req.Count;
// count = Convert.ToInt32(Session["counter"]);
if (count < total)
{
request = req[count].ToString();
evLogTxt = evLogTxt + "sending request no = " + (count + 1) + "\r\n";
//Session["counter"] = ((int)Session["counter"]) + 1;
}
else
{
count = 0;
// Session["counter"] = 0;
request = "";
}
evLogTxt = evLogTxt + "\r\n";
evLogTxt = evLogTxt + "Return values: " + "\r\n";
evLogTxt = evLogTxt + "string request = " + request + "\r\n";
logEvent(evLogTxt);
return request;
}
public int receiveResponseXML(string ticket, string response, string hresult, string message)
{
string evLogTxt = "WebMethod: receiveResponseXML() has been called by QBWebconnector" + "\r\n\r\n";
evLogTxt = evLogTxt + "Parameters received:\r\n";
evLogTxt = evLogTxt + "string ticket = " + ticket + "\r\n";
evLogTxt = evLogTxt + "string response = " + response + "\r\n";
evLogTxt = evLogTxt + "string hresult = " + hresult + "\r\n";
evLogTxt = evLogTxt + "string message = " + message + "\r\n";
evLogTxt = evLogTxt + "\r\n";
int retVal = 0;
if (!hresult.ToString().Equals(""))
{
// if there is an error with response received, web service could also return a -ve int
evLogTxt = evLogTxt + "HRESULT = " + hresult + "\r\n";
evLogTxt = evLogTxt + "Message = " + message + "\r\n";
retVal = -101;
}
else
{
evLogTxt = evLogTxt + "Length of response received = " + response.Length + "\r\n";
ArrayList req = buildRequest();
int total = req.Count;
// int count = Convert.ToInt32(Session["counter"]);
int percentage = (count * 100) / total;
if (percentage >= 100)
{
count = 0;
// Session["counter"] = 0;
}
retVal = percentage;
}
evLogTxt = evLogTxt + "\r\n";
evLogTxt = evLogTxt + "Return values: " + "\r\n";
evLogTxt = evLogTxt + "int retVal= " + retVal.ToString() + "\r\n";
logEvent(evLogTxt);
return retVal;
}
public string getLastError(string ticket)
{
string evLogTxt = "WebMethod: getLastError() has been called by QBWebconnector" + "\r\n\r\n";
evLogTxt = evLogTxt + "Parameters received:\r\n";
evLogTxt = evLogTxt + "string ticket = " + ticket + "\r\n";
evLogTxt = evLogTxt + "\r\n";
int errorCode = 0;
string retVal = null;
if (errorCode == -101)
{
retVal = "QuickBooks was not running!"; // This is just an example of custom user errors
}
else
{
retVal = "Error!";
}
evLogTxt = evLogTxt + "\r\n";
evLogTxt = evLogTxt + "Return values: " + "\r\n";
evLogTxt = evLogTxt + "string retVal= " + retVal + "\r\n";
logEvent(evLogTxt);
return retVal;
}
public string closeConnection(string ticket)
{
string evLogTxt = "WebMethod: closeConnection() has been called by QBWebconnector" + "\r\n\r\n";
evLogTxt = evLogTxt + "Parameters received:\r\n";
evLogTxt = evLogTxt + "string ticket = " + ticket + "\r\n";
evLogTxt = evLogTxt + "\r\n";
string retVal = null;
retVal = "OK";
evLogTxt = evLogTxt + "\r\n";
evLogTxt = evLogTxt + "Return values: " + "\r\n";
evLogTxt = evLogTxt + "string retVal= " + retVal + "\r\n";
logEvent(evLogTxt);
return retVal;
}
#region UtilityMethods
private void initEvLog()
{
try
{
string source = "WCWebService";
if (!System.Diagnostics.EventLog.SourceExists(source))
System.Diagnostics.EventLog.CreateEventSource(source, "Application");
evLog.Source = source;
}
catch(Exception ex)
{
};
return;
}
private void logEvent(string logText)
{
try
{
evLog.WriteEntry(logText);
}
catch { };
return;
}
public ArrayList buildRequest()
{
string strRequestXML = "";
XmlDocument inputXMLDoc = null;
// CustomerQuery
inputXMLDoc = new XmlDocument();
inputXMLDoc.AppendChild(inputXMLDoc.CreateXmlDeclaration("1.0", null, null));
inputXMLDoc.AppendChild(inputXMLDoc.CreateProcessingInstruction("qbposxml", "version=\"1.0\""));
XmlElement qbposXML = inputXMLDoc.CreateElement("QBPOSXML");
inputXMLDoc.AppendChild(qbposXML);
XmlElement qbposXMLMsgsRq = inputXMLDoc.CreateElement("QBPOSXMLMsgsRq");
qbposXML.AppendChild(qbposXMLMsgsRq);
qbposXMLMsgsRq.SetAttribute("onError", "stopOnError");
XmlElement customerQueryRq = inputXMLDoc.CreateElement("CustomerQueryRq");
qbposXMLMsgsRq.AppendChild(customerQueryRq);
customerQueryRq.SetAttribute("requestID", "1");
XmlElement maxReturned = inputXMLDoc.CreateElement("MaxReturned");
customerQueryRq.AppendChild(maxReturned).InnerText = "1";
strRequestXML = inputXMLDoc.OuterXml;
req.Add(strRequestXML);
// Clean up
strRequestXML = "";
inputXMLDoc = null;
qbposXML = null;
qbposXMLMsgsRq = null;
maxReturned = null;
// ItemInventoryQuery
inputXMLDoc = new XmlDocument();
inputXMLDoc.AppendChild(inputXMLDoc.CreateXmlDeclaration("1.0", null, null));
inputXMLDoc.AppendChild(inputXMLDoc.CreateProcessingInstruction("qbposxml", "version=\"1.0\""));
qbposXML = inputXMLDoc.CreateElement("QBPOSXML");
inputXMLDoc.AppendChild(qbposXML);
qbposXMLMsgsRq = inputXMLDoc.CreateElement("QBPOSXMLMsgsRq");
qbposXML.AppendChild(qbposXMLMsgsRq);
qbposXMLMsgsRq.SetAttribute("onError", "stopOnError");
XmlElement itemInventoryQueryRq = inputXMLDoc.CreateElement("ItemInventoryQueryRq");
qbposXMLMsgsRq.AppendChild(itemInventoryQueryRq);
itemInventoryQueryRq.SetAttribute("requestID", "2");
maxReturned = inputXMLDoc.CreateElement("MaxReturned");
itemInventoryQueryRq.AppendChild(maxReturned).InnerText = "1";
strRequestXML = inputXMLDoc.OuterXml;
req.Add(strRequestXML);
// Clean up
strRequestXML = "";
inputXMLDoc = null;
qbposXML = null;
qbposXMLMsgsRq = null;
maxReturned = null;
// PurchaseOrderQuery
inputXMLDoc = new XmlDocument();
inputXMLDoc.AppendChild(inputXMLDoc.CreateXmlDeclaration("1.0", null, null));
inputXMLDoc.AppendChild(inputXMLDoc.CreateProcessingInstruction("qbposxml", "version=\"1.0\""));
qbposXML = inputXMLDoc.CreateElement("QBPOSXML");
inputXMLDoc.AppendChild(qbposXML);
qbposXMLMsgsRq = inputXMLDoc.CreateElement("QBPOSXMLMsgsRq");
qbposXML.AppendChild(qbposXMLMsgsRq);
qbposXMLMsgsRq.SetAttribute("onError", "stopOnError");
XmlElement purchaseOrderQueryRq = inputXMLDoc.CreateElement("PurchaseOrderQueryRq");
qbposXMLMsgsRq.AppendChild(purchaseOrderQueryRq);
purchaseOrderQueryRq.SetAttribute("requestID", "3");
maxReturned = inputXMLDoc.CreateElement("MaxReturned");
purchaseOrderQueryRq.AppendChild(maxReturned).InnerText = "1";
strRequestXML = inputXMLDoc.OuterXml;
req.Add(strRequestXML);
return req;
}
private string parseForVersion(string input)
{
// This method is created just to parse the first two version components
// out of the standard four component version number:
// <Major>.<Minor>.<Release>.<Build>
//
// As long as you get the version in right format, you could use
// any algorithm here.
string retVal = "";
string major = "";
string minor = "";
Regex version = new Regex(@"^(?<major>\d+)\.(?<minor>\d+)(\.\w+){0,2}$", RegexOptions.Compiled);
Match versionMatch = version.Match(input);
if (versionMatch.Success)
{
major = versionMatch.Result("${major}");
minor = versionMatch.Result("${minor}");
retVal = major + "." + minor;
}
else
{
retVal = input;
}
return retVal;
}
#endregion
}
}
还有这个配置文件代码:
<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings/>
<!--
For a description of web.config changes see http://go.microsoft.com/fwlink/?LinkId=235367.
The following attributes can be set on the <httpRuntime> tag.
<system.Web>
<httpRuntime targetFramework="4.5.2" />
</system.Web>
-->
<system.web>
<compilation debug="true" targetFramework="4.5.2"/>
<!--
The <authentication> section enables configuration
of the security authentication mode used by
ASP.NET to identify an incoming user.
-->
<authentication mode="Windows"/>
<!--
The <customErrors> section enables configuration
of what to do if/when an unhandled error occurs
during the execution of a request. Specifically,
it enables developers to configure html error pages
to be displayed in place of a error stack trace.
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/>
</system.web>
<!--
The system.webServer section is required for running ASP.NET AJAX under Internet
Information Services 7.0. It is not necessary for previous version of IIS.
-->
<system.webServer>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
<system.serviceModel>
<services>
<service name="QuickBookWebConnector.Service1" behaviorConfiguration="QuickBookWebConnector.Service1Behavior">
<!-- Service Endpoints -->
<endpoint address="" binding="basicHttpBinding" contract="QuickBookWebConnector.IService1">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="QuickBookWebConnector.Service1Behavior">
<!-- To avoid disclosing metadata information, set the value below to false before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
这是网络连接器的日志文件:
20170517.16:20:49 UTC : QBWebConnector.CompanyFileLock.initialize() : Company file has been initialized with AppLock = UNLOCKED:MSIDDIQUI-LAPTO for ownerID = <{C4DD1DB4-E7DE-4B1E-B33D-D7F3EDC7D613}>
20170517.16:20:49 UTC : QBWebConnector.SOAPWebService.AddToQuickBooks() : Application DebuggingService has been added to QuickBooks.
20170517.16:20:49 UTC : QBWebConnector.SOAPWebService.DisconnectFromQB() : Session ended and connection closed
20170517.16:20:50 UTC : : ~SingleInstanceHandler() - usingInstanceChannel = false. Returning without any Registry key delete or unmarshalling.
20170517.16:20:56 UTC : QBWebConnector.WebServiceManager.DoUpdateSelected() : updateWS() for application = 'DebuggingService' has STARTED
20170517.16:20:56 UTC : QBWebConnector.RegistryManager.getUpdateLock() : HKEY_CURRENT_USER\Software\Intuit\QBWebConnector\UpdateLock = FALSE
20170517.16:20:56 UTC : QBWebConnector.RegistryManager.setUpdateLock() : HKEY_CURRENT_USER\Software\Intuit\QBWebConnector\UpdateLock has been set to True
20170517.16:20:56 UTC : QBWebConnector.RegistryManager.setUpdateLock() : ********************* Update session locked *********************
20170517.16:20:56 UTC : QBWebConnector.SOAPWebService.instantiateWebService() : Initiated connection to the following application.
20170517.16:20:56 UTC : QBWebConnector.SOAPWebService.instantiateWebService() : AppName: DebuggingService
20170517.16:20:56 UTC : QBWebConnector.SOAPWebService.instantiateWebService() : AppUniqueName (if available): DebuggingService
20170517.16:20:56 UTC : QBWebConnector.SOAPWebService.instantiateWebService() : AppURL: http://localhost:3318/Service1.svc
20170517.16:20:56 UTC : QBWebConnector.SOAPWebService.do_serverVersion() : *** Calling serverVersion().
20170517.16:20:57 UTC : QBWebConnector.SOAPWebService.do_serverVersion() : Actual error received from web service for serverVersion call: <The message with Action 'http://developer.intuit.com/serverVersion' 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).>. For backward compatibility of all webservers, QBWC will catch all errors under app-not-supporting-serverVersion.
20170517.16:20:57 UTC : QBWebConnector.SOAPWebService.do_serverVersion() : This application does not contain support for serverVersion. Allowing update operation for backward compatibility.
20170517.16:20:57 UTC : QBWebConnector.SOAPWebService.do_clientVersion() : *** Calling clientVersion() with following parameter:<productVersion="2.1.0.30">
20170517.16:21:00 UTC : QBWebConnector.SOAPWebService.do_clientVersion() : Received from clientVersion() following parameter:<clientVersionRet="">
20170517.16:21:00 UTC : QBWebConnector.SOAPWebService.do_clientVersion() : This application agrees with the current version of QBWebConnector. Allowing update operation.
20170517.16:21:00 UTC : QBWebConnector.SOAPWebService.do_authenticate() : Authenticating to application 'DebuggingService', username = 'Sysadmin'
20170517.16:21:01 UTC : QBWebConnector.SOAPWebService.do_authenticate() : *** Calling authenticate() with following parameters:<userName="Sysadmin"><password=<MaskedForSecurity>
20170517.16:21:08 UTC : QBWebConnector.SOAPWebService.do_authenticate() : QBWC1012: Authentication failed due to following error message.
Index was outside the bounds of the array.
More info:
StackTrace = at QBWebConnector.WebService.do_authenticate(String& ticket, String& companyFileName)
Source = QBWebConnector
20170517.16:21:08 UTC : QBWebConnector.RegistryManager.setUpdateLock() : HKEY_CURRENT_USER\Software\Intuit\QBWebConnector\UpdateLock has been set to False
20170517.16:21:08 UTC : QBWebConnector.RegistryManager.setUpdateLock() : ********************* Update session unlocked *********************
20170517.16:21:08 UTC : QBWebConnector.WebServiceManager.DoUpdateSelected() : Update completed with errors. See log (QWClog.txt) for details.
【问题讨论】:
-
在没有查看更多日志和了解一些上下文的情况下无法为您提供帮助。你的代码是什么样的?您的代码返回的 SOAP 响应是什么样的?这几乎可以肯定是您的编码错误。
-
这些是 Web 连接器内部日志。我的代码如下所示:forums.asp.net/t/… 这是 quickbooks 提供的 Web 连接器示例应用程序。当 Web 连接器点击身份验证方法时出现此问题。
-
@KeithPalmerJr。你能帮我解决这个问题吗?
-
您将需要发布您的代码,发布日志文件的其余部分,并发布您的代码正在生成的 SOAP 响应,我很乐意提供帮助。如果没有这些信息,很遗憾,我真的没有足够的信息来帮助您。
-
@KeithPalmerJr。我已经更新了帖子,请看这个,提前谢谢
标签: wcf authentication quickbooks