环境:windowsxp sp3+IIS5.1+Arcgis server10
问题描述:WebService调用C++dll在XP下IIS5.1发布后始终没有返回值,但是在调试状态下一切正常。在网上泡了3天,总算解决了。
由于WebGis项目需求, 项目采取vs2010开发,语言采用C#及silverlight, GIS发布采用arcgis server10 , 通过arcgis silverlight api访问地图。
WebGis地图上的电力开关实时状态需要从另一套系统(配网监控系统,C++开发的)中获取,所有就用了webservice来实现,具体就是在配网监控系统中写了个webgis_service进程(守护的)和一个librealdata.dll(这两都是基于C/C++的),
其中在librealdata.dll提供了通过传入参数获取某些电力开关实时状态的接口,如下:
int LIBREALDATA_API __stdcall GetKgRealData(char *comenames, char** retval);
而webservice中调用如下(GisRealData.asmx.cs中):
#region 实时数据获取类
public class GisRealData : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
[WebMethod]
public byte[] GetKG_RealData(byte[] comenames)
{
IntPtr retptr;
int retval = 0;
try
{
retval = GetKgRealData(comenames, out retptr);
}
catch (Exception ex)
{
string str = ex.Message;
throw new Exception("获取数据失败!");
}
if (retval <= 0)
{
return null;
}
byte[] retdata = new byte[retval];
for (int i = 0; i < retval; i++) retdata[i] = Marshal.ReadByte(retptr, i);
FreeRealDataMem(retptr);
return retdata;
//return Convert.ToBase64String(retdata);
}
[DllImport("C:\\xxxx\\dll\\librealdata.dll", CharSet = CharSet.Ansi, EntryPoint = "GetKgRealData", ExactSpelling = false)]
public static extern int GetKgRealData(byte[] comenames, out IntPtr retval);
[DllImport("C:\\xxxx\\dll\\librealdata.dll", CharSet = CharSet.Ansi, EntryPoint = "FreeRealDataMem", ExactSpelling = false)]
public static extern void FreeRealDataMem(IntPtr retval);
}
#endregion
}
在silverlight中添加服务引用
在silverlight中调用(MainPage.xaml.cs)
MainPage函数中如下:
{
.....
public GisRealDataSoapClient m_soapclient;
//EndpointAddress real_address = new EndpointAddress(new Uri(Application.Current.Host.Source, "/GisRealData.asmx")); //VS2010调试用
EndpointAddress real_address = new EndpointAddress(new Uri(Application.Current.Host.Source, "/WebGis/GisRealData.asmx")); //IIS发布用
BasicHttpBinding real_BasicHttpBinding = new BasicHttpBinding();
real_BasicHttpBinding.MaxBufferSize = 2147483647;
real_BasicHttpBinding.MaxReceivedMessageSize = 2147483647;
real_BasicHttpBinding.OpenTimeout = new TimeSpan(0, 1, 0);
real_BasicHttpBinding.CloseTimeout = new TimeSpan(0, 1, 0);
#if DEBUG
real_BasicHttpBinding.SendTimeout = new TimeSpan(18, 10, 00);
real_BasicHttpBinding.ReceiveTimeout = new TimeSpan(18, 10, 00);
#else
real_BasicHttpBinding.SendTimeout = new TimeSpan(0, 5, 00);
real_BasicHttpBinding.ReceiveTimeout = new TimeSpan(0, 5, 00);
#endif
m_soapclient = new GisRealDataSoapClient(real_BasicHttpBinding, real_address);
m_soapclient.GetKG_RealDataCompleted += new EventHandler<GetKG_RealDataCompletedEventArgs>(GetKG_RealDataCompleted);
m_soapclient.HelloWorldCompleted += new EventHandler<HelloWorldCompletedEventArgs>(HelloWorldCompleted);
m_soapclient.HelloWorldAsync();
.....
}
//获取开关、刀闸实时数据,此函数在一个线程中调用
public void GetKgRealData()
{
if (m_soapclient == null || m_kgparabyte == null) return;
m_soapclient.GetKG_RealDataAsync(m_kgparabyte);
}
//WEB SERVICE测试
public void HelloWorldCompleted(object sender, HelloWorldCompletedEventArgs e)
{
try
{
if (e.Result != null)
{
HtmlPage.Window.Alert(e.Result.ToString());
}
}
catch (Exception error)
{
string errmsg = error.ToString();
}
}
//取得开关实时数据响应函数
public void GetKG_RealDataCompleted(object sender, GetKG_RealDataCompletedEventArgs e)
{
try
{
if (e.Result != null)
{
byte[] resultbyte = e.Result;
WEBGIS_RETKGPARAM retkgdata = null;
MyConvert.Byte2KGStruct(resultbyte, 0, out retkgdata);
//线程异步的委托更新UI用此种写法,不更新就不用了
this.Dispatcher.BeginInvoke(() =>
{
RenderPDKGSymbols(retkgdata);
});
}
}
catch (Exception error)
{
string errmsg = error.ToString();
}
}
web.config配置如下:
<?xml version="1.0"?>
<!--
有关如何配置 ASP.NET 应用程序的详细消息,请访问
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0">
</compilation>
<httpRuntime maxRequestLength="65535" executionTimeout="36000" useFullyQualifiedRedirectUrl="false" />
<webServices >
<protocols >
<add name="HttpSoap"/>
<add name="HttpPost"/>
<add name="HttpGet"/>
<add name="Documentation"/>
</protocols>
</webServices>
</system.web>
<appSettings>
<add key="SDE_SQLServerConnString" value="Data Source=10.1.1.57;UID=sa;PWD=xxxx;DATABASE=Esri_SDE "/>
<add key="SQLServerConnString" value="Data Source=10.1.1.57;UID=sa;PWD=xxxx;DATABASE=WebGIS "/>
<add key="MapServiceURL" value="http://10.1.1.57/ArcGIS/rest/services/webGIS_jx/MapServer"/>
<add key="MapFullExtent" value="113.764813|38.266093|114.404081|37.662598"/>
<add key="FeatureServiceURL" value="http://10.1.1.57/ArcGIS/rest/services/webGIS_layer"/>
</appSettings>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="mybehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_SymbolTableService" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"
receiveTimeout="00:10:00" sendTimeout="00:10:00" openTimeout="00:10:00" closeTimeout="00:10:00">
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxDepth="2147483647" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647"/>
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
<services>
<service name="WebGIS.Web.SymbolTableService" behaviorConfiguration="mybehavior">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_SymbolTableService" contract="WebGIS.Web.SymbolTableService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
</configuration>
ServiceReferences.ClientConfig配置如下:
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="GisRealDataSoap" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
<binding name="BasicHttpBinding_SymbolTableService" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://10.1.1.57/WebGis/GisRealData.asmx" binding="basicHttpBinding"
bindingConfiguration="GisRealDataSoap" contract="GisRealDataRef.GisRealDataSoap"
name="GisRealDataSoap" />
<endpoint address="http://10.1.1.57/WebGis/SymbolTableService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_SymbolTableService"
contract="SymbolTableRef.SymbolTableService" name="BasicHttpBinding_SymbolTableService" />
</client>
</system.serviceModel>
</configuration>
这样在IIS5.1下发布后, m_soapclient.GetKG_RealDataAsync(m_kgparabyte)始终没有返回值(没进GetKG_RealDataCompleted函数),但是调用 m_soapclient.HelloWorldAsync()一切正常,有返回值,直接访问webserivce也能看到,如下:
后来在网上查了好几天,网上有一篇文章《webservice发布问题,部署iis后调用不成功》
有这么一句话“对应的应用池,设置默认设置-->进程模型-->标识-->设置localsystem”
还有《C#的WebService调用VC++的DLL,VS2005程序运行DEBUG可行,但是其他机器访问就不行》中的“你可以在web.config里启用模拟,或者在iis6的应用程序池里的对应的网站的池的标识采用本地系统,或者将dll本身的安全性添加匿名账户访问权限”
最后试了半天,给dll目录添加匿名账户访问权限不行,IIS5.1没有应用程序池设置。
最后在web.config里启用模拟,问题解决了。
即在<system.web>中加上这句<identity impersonate="true" />。
N天后做别的测试,上传文件不行,于是然后设置了下虚拟目录属性为:写入等(全打上勾);
还有就是inetinfo.exe也报错。
莫名其妙的实时数据又取不到了(调试下没问题,上边提到的indentify也是true)。
后来在所调用的dll文件夹(上边提到的c:\xxxx\)属性中添加上匿名访问的用户,突然又可以了,如下:
真是无语了!