ATLServer WebService 如何返回任意内容的 SOAP 消息给客户
2007-3-24
(上篇文章存在问题,这里是可用的版本。)
如果想在下面的WebService方法中返回任意SOAP错误消息给客户,应该这样做:
// 宏定义,错误信息只支持英文半角
#define SOAP_FAULT(errCode, wszDetail) m_fault.m_soapErrCode = errCode; m_fault.m_strDetail = wszDetail
[ soap_method ]
HRESULT HelloWorld(/*[in]*/ BSTR bstrInput, /*[out, retval]*/ BSTR *bstrOutput)
{
CComBSTR bstrOut(L"Hello ");
bstrOut += bstrInput;
*bstrOutput = bstrOut.Detach();
SOAP_FAULT(SOAP_E_SERVER, L"Do you love me, my girl");
return E_FAIL;
}
然而,m_fault参数未定义,我们需要把它加入到atlsoap.h文件中。打开atlsoap.h,加入下面的代码,注意红色部分是我加的,其他地方不要改变:
template
<
typenameTHandler
>
class CSoapHandler:
public CSoapRootHandler,
public CComObjectRootEx < CComMultiThreadModel > ,
public IRequestHandlerImpl < THandler >
{
protected :
HTTP_CODEm_hcErr;
CHttpResponse * m_pHttpResponse;
// heapforSOAPrequests
CWin32Heapm_heap;
// defaultheapisCOMheap(SOAPServerscandoubleasCOMobjects)
CComHeapm_comHeap;
//CL2:这里添加成员用来返回用户定制的错误,而不是根据HRESULT值生成错误
CSoapFaultm_fault;
public :
BEGIN_COM_MAP(CSoapHandler < THandler > )
COM_INTERFACE_ENTRY(ISAXContentHandler)
COM_INTERFACE_ENTRY(IRequestHandler)
END_COM_MAP()
CSoapHandler()
:m_pHttpResponse(NULL),m_hcErr(HTTP_SUCCESS)
{
SetMemMgr( & m_comHeap);
}
void SetHttpError(HTTP_CODEhcErr)
{
m_hcErr = hcErr;
}
HRESULTSoapFault(
SOAP_ERROR_CODEerrCode,
const wchar_t * wszDetail,
int cchDetail)
{
ATLASSUME(m_pHttpResponse != NULL);
SetHttpError(AtlsHttpError( 500 ,SUBERR_NO_PROCESS));
m_pHttpResponse -> ClearHeaders();
m_pHttpResponse -> ClearContent();
m_pHttpResponse -> SetContentType( " text/xml " );
m_pHttpResponse -> SetStatusCode( 500 );
if(m_fault.m_soapErrCode== SOAP_E_UNK)
{
if (wszDetail != NULL)
{
if (cchDetail < 0 )
{
cchDetail = ( int )wcslen(wszDetail);
}
_ATLTRY
{
m_fault.m_strDetail.SetString(wszDetail,cchDetail);
}
_ATLCATCHALL()
{
ATLTRACE(_T( " CSoapHandler::SoapFault--outofmemory. " ));
return E_OUTOFMEMORY;
}
}
m_fault.m_soapErrCode = errCode;
}
m_fault.GenerateFault(m_pHttpResponse);
return S_OK;
}
class CSoapHandler:
public CSoapRootHandler,
public CComObjectRootEx < CComMultiThreadModel > ,
public IRequestHandlerImpl < THandler >
{
protected :
HTTP_CODEm_hcErr;
CHttpResponse * m_pHttpResponse;
// heapforSOAPrequests
CWin32Heapm_heap;
// defaultheapisCOMheap(SOAPServerscandoubleasCOMobjects)
CComHeapm_comHeap;
//CL2:这里添加成员用来返回用户定制的错误,而不是根据HRESULT值生成错误
CSoapFaultm_fault;
public :
BEGIN_COM_MAP(CSoapHandler < THandler > )
COM_INTERFACE_ENTRY(ISAXContentHandler)
COM_INTERFACE_ENTRY(IRequestHandler)
END_COM_MAP()
CSoapHandler()
:m_pHttpResponse(NULL),m_hcErr(HTTP_SUCCESS)
{
SetMemMgr( & m_comHeap);
}
void SetHttpError(HTTP_CODEhcErr)
{
m_hcErr = hcErr;
}
HRESULTSoapFault(
SOAP_ERROR_CODEerrCode,
const wchar_t * wszDetail,
int cchDetail)
{
ATLASSUME(m_pHttpResponse != NULL);
SetHttpError(AtlsHttpError( 500 ,SUBERR_NO_PROCESS));
m_pHttpResponse -> ClearHeaders();
m_pHttpResponse -> ClearContent();
m_pHttpResponse -> SetContentType( " text/xml " );
m_pHttpResponse -> SetStatusCode( 500 );
if(m_fault.m_soapErrCode== SOAP_E_UNK)
{
if (wszDetail != NULL)
{
if (cchDetail < 0 )
{
cchDetail = ( int )wcslen(wszDetail);
}
_ATLTRY
{
m_fault.m_strDetail.SetString(wszDetail,cchDetail);
}
_ATLCATCHALL()
{
ATLTRACE(_T( " CSoapHandler::SoapFault--outofmemory. " ));
return E_OUTOFMEMORY;
}
}
m_fault.m_soapErrCode = errCode;
}
m_fault.GenerateFault(m_pHttpResponse);
return S_OK;
}
... ...
以上就这些就可以了,运行就看到返回的错误信息“<Detail>Do you love me, my girl</Detail>”。
我使用VS2005+ATL8来写WebService。用其他语言写的WebService不知道存在这些问题不。如果要用好ATL Server,对它的代码做些修改是很正常的。我修改了它很多默认的实现,比如CSessionStateService、CPerfMon等类。