ASP.NET调用开源ip地址库ip2region小记
最近在做一个asp.net的项目,其中有个功能是根据输入的ip地址得到相对应的省市信息。目前网上有很多相关的服务,但是要么是收费的要么就是使用上有限制(每秒查询次数限制)。经过一番搜索,终于在github上发现了一个开源的准确率99.9%的ip地址定位库ip2region。它目前提供了java,php,c,python,nodejs,golang查询绑定,竟然没有提供C#查询绑定…不过还好,我们有P/Invoke调用。
封装生成动态库
首先,下载ip2region源码。创建一个C++的动态库工程,将ip2region.h和ip2region.cpp(对ip2region.c直接改名)文件包含进来,直接编译生成动态库ip2region.dll。
P/Invoke调用
应用P/Invoke Interop Assistant GUI Tool工具,生成对应的C#导出类。
|
|
这里需要注意的是,函数的调用方式需设置为CallingConvention = CallingConvention.Cdecl。同时,对于导出函数的名称最好用dependens工具查看一下。因为C++对于有些调用方式为了实现重载会重命名导出函数名。
写代码进行调用:
动态库路径限制
在将工程部署到测试环境中时发现,必须将ip2region.dll放在固定的目录下才行。因为System.Runtime.InteropServices.DllImportAttribute要求路径必须是固定的,不可动态去指定。可是,这样的话就会给维护和部署带来不便,有没有什么办法可以动态的去获得ip2region.dll路径并将它load起来呢?在参考了几篇网文之后找到了一种方法,就是调用windows加载动态库的api(LoadLibrary, GetProcAddress, FreeLibrary)并通过C#的委托来实现调用。代码如下:
细心的网友可能已经发现,在funcExport类中我会进行两次加载尝试,分别是32位和64位ip2region动态库。为什么会有如此操作呢?因为,在我将ASP.NET的工程部署到测试环境中时发现程序不再work了,甚至还抛出了异常…
通过调试发现,原本加载32位的ip2region.dll没有成功,可是为什么在我调试的时候是可以正常load的呢?
原来,我是部署在64位的Win server 2008上,默认的应用程序池是运行在64位模式下的,是不允许调用32位的dll的。
在 IIS 7.x 中,要“启用 32bit 应用程序支持”,需要对“应用程序池”进行配置。将“enable32BitAppOnWin64”设置为“True”。这样便将应用程序池的工作进程设置为 WOW64 模式,而在 WOW64 模式下,工作进程将仅加载 32 位应用程序的 32 位进程。
而本地调试之所以可以load是因为设置的开发模式是Any CPU并且是设置的IIS express进行调试,那么也就没有IIS application中的限制了。
可是也不能为了这个而让整个网站程序运行在WoW64模式呀,这样肯定会影响性能的。所以就有了以上两次加载尝试,先加载64位的动态库,若失败的话则再加载32位的动态库。这里有一点需要注意的是,由于这种方式不能指定函数调用方式,而.NET的默认调用方式是Stdcall,所以在生成动态库的时候将调用约定设置为stdcall。
至此本篇完。总结如下:
- .NET调用C/C++动态库时除了用Framework提供的方法DllImportAttribute外还可通过调用kernel32.dll中的(LoadLibrary, GetProcAddress, FreeLibrary)来实现。
- P/Invoke调用时需注意函数的调用约定一致。
- 若要64位系统上的IIS支持跑32位的程序或调用32位的动态库,需要启用32bit应用程序支持.