
简介面向用友U8二次开发人员提供一套基于Webservice的API调用方案使外部系统无需安装U8客户端即可远程生成单据、处理审核等业务。资源包共1069个文件约22.64MB包含189个dll涵盖UFIDA.U8系列核心依赖库、107个cs源码、135个png及72个gif辅助资源另有asmx、config等Web服务工程文件结构清晰便于按模块查阅。已有5245人学习下载。内容以完整调用源码为主可直接参考服务封装与接口暴露方式理解U8API在Webservice中的调用链借助所附依赖dll与示例工程Java、Python等非C#语言平台也能快速对接U8实现单据创建、审核等操作有效降低集成门槛。1. 用友U8的Webservice二次开发被业务部门追着要接口的那些年做U8二次开发的工程师应该都遇到过这种场景业务部门拿着Excel说“帮我们跟OA打通一下”信息科说“我们这边是Java体系你的COM组件我们调不动”而U8的API本身是COM暴露的跨语言调用需要中间层。这个项目解决的就是这个问题——用Webservice把U8的二次开发API封装成标准SOAP接口让Java、Python、C#都能调不再被VB和COM绑死。它适合三类人要给U8做接口对接的开发、被异构系统集成折磨的ERP顾问、以及想从零搭一套U8 API调用链路的入门者。下面这份实战笔记我把环境、代码、参数和踩过坑全部拆开讲。2. 选型与初始化Webservice凭什么能接U8环境要准备到什么程度2.1 U8 API的暴露方式从COM到Webservice三种路线的取舍U8这套ERP从早期版本开始对外暴露接口的方式大致有三条路线。第一条是VB环境下直接引用COM组件调用U8的公共对象比如Voucher、CostObject这条路的问题是只适合Windows平台而且VB6的生态在今天已经非常冷门。第二条是用友U8EAI的XML数据交换通过配置消息格式做单据导入导出这条路能解决一部分标准场景但自定义业务逻辑的时候很别扭。第三条就是Webservice通过标准SOAP协议把U8的登录、单据查询、凭证生成等能力发布成接口任何语言只要支持HTTP和XML解析就能对接。选Webservice而不是直接调COM核心理由是跨语言和跨网络。我遇过不少客户现场是“U8在Windows服务器上业务系统跑在Linux的Tomcat里”如果只提供COM组件Java那边根本没法用。而Webservice走的是HTTP协议防火墙只要开放80端口就能通Java端通过Axis2或者原生HttpURLConnection都能调。对于U8二次开发来说Webservice不是性能最好的方式但它是兼容性最好的方式——大部分U8对接场景里业务量是单据级而不是数据仓库级SOAP的序列化开销完全能接受。2.2 开发环境准备U8客户端、VS2022与公共组件引用在动手之前环境准备是关键。这里说的是“常用做法”我一般会在开发机上先装U8客户端保证能正常登录U8应用服务器。为什么要先装客户端因为U8的公共组件比如登录代理那套DLL在客户端安装时才会注册到系统里只拿一个引用的DLL复制来复制去经常会出现运行时找不到类型的问题。开发工具方面VS2022创建Webservice有个坑默认新建项目里找不到“Web服务(ASMX)”模板需要安装“ASP.NET和Web开发”工作负载并且项目要选择.NET Framework 4.7.2不是.NET Core或.NET 6/8。装好后在解决方案里新建一个ASP.NET Web应用程序(.NET Framework)然后添加“Web 服务(ASMX)”项。下面是项目里需要引用的核心文件清单不同U8版本文件名略有差异引用文件所在位置用途UFSoft.U8.Framework.LoginProxy.dllU8安装目录\U8SOFT\Client\Bin登录代理负责建立U8上下文UFSoft.U8.Framework.PluginBase.dll同上插件基类封装常用操作System.Web.Services.dll系统程序集提供WebMethod机制System.Xml.dll系统程序集SOAP消息和XML序列化引用的时候注意U8的DLL有时候会依赖其他同目录文件所以引用的DLL不要单独拷走直接把整个Bin目录加入系统的PATH环境变量或者把依赖文件一起复制到项目的bin目录下否则部署到IIS上会报文件找不到。2.3 最小骨架一个能发布到IIS的asmx服务环境准备好后先写一个最简单的asmx服务验证链路。下面是骨架代码using System.Web.Services; using UFSoft.U8.Framework.LoginProxy; namespace U8ApiService { [WebService(Namespace http://tempuri.org/U8ApiService)] [WebServiceBinding(ConformsTo WsiProfiles.BasicProfile1_1)] public class U8Api : System.Web.Services.WebService { [WebMethod(Description 测试连通性)] public string Ping() { return U8 WebService is alive; } } }这段代码的逻辑很直白用[WebMethod]特性标记对外发布的方法外部系统通过SOAP协议调用Ping接口只要能拿到返回值就说明服务发布成功。Namespace参数是SOAP消息的默认命名空间如果不写客户端调用时会用http://tempuri.org/在跨语言调用时容易引起命名空间不匹配。ConformsTo的WsiProfiles.BasicProfile1_1是WebService互操作性的声明保证Java或Python客户端能正确解析WSDL这个最好保留。部署这一步我单独说一下右键项目发布到IIS应用程序池要选.NET Framework v4.0不要选“无托管代码”否则asmx的HTTP处理程序不会加载。发布完成后浏览器访问http://localhost/U8ApiService/U8Api.asmx能看到操作列表就说明部署成功。这个最小值验证过程一定要做因为后面所有U8相关代码都有外部依赖如果这一步没跑通你根本分不清问题是出在U8组件还是Webservice本身。3. 落地一篇能跑的接口服务端封装与跨语言调用完整步骤3.1 服务端实现把U8登录代理封装成可调用的业务方法U8 API调用的核心是登录代理。U8的逻辑是“先登录再操作”所有业务方法执行前都需要有一个已认证的上下文。我在服务端通常把登录过程和业务调用封装到一个类里而不是在每个WebMethod里都重写一遍登录逻辑。下面是封装登录代理的代码using UFSoft.U8.Framework.LoginProxy; public class U8Context { public static string Login(string server, string db, string user, string password, out string errMsg) { errMsg string.Empty; UFLoginProxy proxy new UFLoginProxy(); string token; bool success proxy.Login(server, db, user, password, out token, out errMsg); if (!success) { return null; } return token; } public static void Logout(string token) { UFLoginProxy proxy new UFLoginProxy(); proxy.Logout(token); } }这段代码里有三个关键点。UFLoginProxy是U8登录代理的核心类它的Login方法参数顺序是服务器名、数据库名、账号、密码返回的token是后续所有API调用的凭证。Login方法有多个重载版本这里用的是最常用的五参数版本不同U8版本比如16.0和18.0参数签名可能有差异以实际安装版本为准。Logout方法必须在业务处理完毕后调用否则U8的许可会被占用我遇到过因为忘记退出登录导致并发超过许可上限的情况现场直接被业务部门投诉。接下来看业务方法的封装。下面是一个封装U8凭证查询的示例实际业务里你可以替换成采购订单、销售订单等单据接口[WebMethod(Description 根据单号查询凭证信息)] public string GetVoucher(string token, string voucherType, string voucherNo) { try { // 通过token进入U8上下文 // 调用U8API的Voucher类常见做法是先获取业务对象再执行查询 // 这一步不同版本的API类名不同需要按实际引用的程序集调整 // 返回结果是XML字符串方便跨语言解析 return resultsuccess/result; } catch (Exception ex) { return resultfailed/result ex.Message; } }这里的voucherType是单据类型标识比如“SA”代表销售订单“PO”代表采购订单U8里不同类型走不同的API接口。voucherNo是业务单号。代码中调用的核心逻辑我用注释代替了具体类名因为U8API的程序集命名在不同版本间调整过多次——有的版本叫U8API.Voucher有的叫UFSoft.U8.Service.Voucher。我一般会在开发机上用反编译工具确认一下实际版本里的类名再替换进注释位置这比照着网上老代码抄要靠谱得多。服务端部署完成后一定要用浏览器访问U8Api.asmx页面点开方法名它会生成一个HTTP POST的表单测试页。先在这里跑通一次调用确认U8登录和业务方法都正常再通知外部系统对接。3.2 Java端调用用HttpURLConnection组装SOAP报文Java调用asmx有两种方式一种是用CXF或Axis2生成客户端代码这种方式维护方便但需要引入一堆依赖适合大规模对接另一种是用HttpURLConnection直接拼SOAP报文不引第三方库轻量快速。对于内部系统对接我倾向用第二种因为U8的接口数量通常不多没必要为了两三个接口引入一套SOAP框架。下面是Java端的HTTP调用示例import java.io.*; import java.net.*; public class U8SoapClient { public static String callU8Api(String endpoint, String soapAction, String soapBody) throws IOException { URL url new URL(endpoint); HttpURLConnection conn (HttpURLConnection) url.openConnection(); conn.setRequestMethod(POST); conn.setRequestProperty(Content-Type, text/xml; charsetutf-8); conn.setRequestProperty(SOAPAction, soapAction); conn.setDoOutput(true); try (OutputStream os conn.getOutputStream()) { byte[] input soapBody.getBytes(utf-8); os.write(input, 0, input.length); } int code conn.getResponseCode(); try (BufferedReader br new BufferedReader( new InputStreamReader( code 400 ? conn.getErrorStream() : conn.getInputStream(), utf-8))) { StringBuilder response new StringBuilder(); String line; while ((line br.readLine()) ! null) { response.append(line); } return response.toString(); } finally { conn.disconnect(); } } }这段代码有两个重点。第一是SOAPAction头asmx服务的每个方法都会生成一个SOAPAction格式通常是http://tempuri.org/U8ApiService/GetVoucher这个值可以通过浏览器打开asmx页面的方法说明看到如果写错会直接返回“请求因HTTP状态404失败”。第二是错误流处理getErrorStream()用于读取服务端返回的异常信息如果没有这一行服务端报错时你只能看到一个200以外的状态码排查问题全靠猜。实际调用时SOAP报文体的格式需要跟WSDL严格一致我惯用的方式是先把asmx页面的WSDL下载下来用SOAPUI生成一次请求示例再把这套结构固化到Java代码里而不是手抖去拼XML标签。用Java拼SOAP报文还有一个常见坑XML特殊字符没有转义比如单据备注里含“”符号直接拼字符串会破坏报文结构必须用StringEscapeUtils.escapeXml10()这类工具处理一下。3.3 Python端调用用requests十分钟快速验证接口Python做U8接口验证非常方便。相比Java要拼SOAPAction头、处理错误流Python的requests库配合内置的xml解析模块就能搞定适合做接口连通性验证和快速测试。很多制造业信息科会用Python写小程序把外部系统数据同步到U8下面是调用示例import requests import xml.etree.ElementTree as ET URL http://192.168.1.10/U8ApiService/U8Api.asmx SOAP_ACTION http://tempuri.org/U8ApiService/GetVoucher def call_get_voucher(token, voucher_type, voucher_no): body f?xml version1.0 encodingutf-8? soap:Envelope xmlns:soaphttp://schemas.xmlsoap.org/soap/envelope/ soap:Body GetVoucher xmlnshttp://tempuri.org/U8ApiService token{token}/token voucherType{voucher_type}/voucherType voucherNo{voucher_no}/voucherNo /GetVoucher /soap:Body /soap:Envelope resp requests.post(URL, databody.encode(utf-8), headers{Content-Type: text/xml; charsetutf-8, SOAPAction: SOAP_ACTION}) resp.raise_for_status() # 解析SOAP返回常见做法是定位到方法名对应的节点取XML内容 root ET.fromstring(resp.content) return root.text这段代码把SOAP报文用f-string拼出来然后POST到asmx地址。需要注意两点。第一SOAPAction头在Python里经常被忽略服务端对SOAPAction不敏感时确实能通但一旦IIS启用了严格的SOAPAction校验没有这个头就会返回500所以必须带上。第二返回的XML是标准的SOAP封装实际业务数据嵌在GetVoucherResponse节点下面的GetVoucherResult节点里用ET解析时要用namespace去匹配不能直接用标签名找。从效率上说Python适合联调和轻量同步如果业务量大还是建议用C#写Windows服务去调性能差距很明显。4. 避坑清单五个最常见的U8 Webservice翻车现场4.1 现象VS2022新建项目找不到“Web服务(ASMX)”模板VS2022默认的工作负载是面向.NET Core和.NET 6/8的ASMX这种老技术默认被隐藏了。我第一次搭环境时在“新建项目”里翻了三遍也没找到还以为是VS版本的问题。原因ASMX模板只存在于“.NET Framework”类的项目模板里而且需要额外安装“ASP.NET和Web开发”工作负载。VS2022的默认安装没有包含这项。解决打开Visual Studio Installer勾选“ASP.NET和Web开发”工作负载修改安装。新建项目时选择“ASP.NET Web应用程序(.NET Framework)”Framework选4.7.2创建后在“添加新项”里就能找到“Web服务(ASMX)”模板了。这条路径跟创建.NET Core的WebApi项目完全是两码事。4.2 现象发布到IIS后访问asmx页面返回HTTP 404服务本地调试能通发布到IIS后访问U8Api.asmx直接404。这个坑在.NET Framework 4.0以上环境特别容易踩。原因应用程序池没有使用.NET Framework的托管运行时。VS发布时默认可能生成的是无托管代码的应用池配置或者IIS的ISAPI筛选器没有加载。解决在IIS管理器里找到发布出来的站点右键“应用程序池”选择“.NET Framework v4.0.30319”托管管道模式选“集成”。如果还不行检查处理程序映射里有没有*.asmx对应System.Web.Services.Protocols.WebServiceHandlerFactory。这个配置不对的话后面的HTTP 401、404会变着花样来。4.3 现象登录U8代理时一直超时或者报“连接U8服务失败”通过WebMethod调用U8登录代理返回超时或“无法连接到U8服务”。这个时候直接调用asmx的Ping方法是正常的但登录就是不行。原因U8应用服务器上的后台服务没有启动。U8登录代理需要依赖U8应用服务器的调度服务常见的是“UFWDPl平台服务”和“U8服务管理”里的几个后台进程。服务端的防火墙也可能拦截了U8组件之间的DCOM通信。解决在U8应用服务器上打开“服务管理”确认所有U8相关服务都已启动。特别是登录代理依赖的UFWDPl服务如果没启动登录请求会一直挂起。开发机与U8服务器之间如果是跨网段还要在U8服务器的Windows防火墙里放行相关端口U8的端口一般是一段范围具体看防火墙日志客户端登录失败时报的端口号就是线索。4.4 现象Java/Python客户端调用报“请求因HTTP状态401失败”服务端发布好了用浏览器测试正常但Java或Python客户端调用时报401未授权。原因IIS站点的匿名认证默认是关闭的或者被配置成了Windows集成认证。浏览器访问时因为是本机或域环境自动带了Windows凭据所以能过但外部系统的HTTP请求不带Windows凭据就被拒了。解决在IIS的“身份验证”功能里把“匿名身份认证”设为启用其他认证方式按需关闭。如果你担心接口被任意调用更好的做法是在WebService内部加一层自己的Token校验而不是依赖IIS的Windows认证——因为外部系统不是你域里的机器Windows认证对它们就是一道过不去的坎。4.5 现象返回DataTable时客户端解析不出来SOAP报错服务端方法返回类型是DataTable调用端拿到的数据跟表格对不上甚至直接在SOAP序列化时报错。原因ASMX对DataTable的序列化支持有限DataTable在SOAP里会变成diffgram:diffgram格式客户端解析很麻烦而且某些字段类型比如TimeSpan在SOAP序列化时会直接失效。解决不要把DataTable直接作为返回值统一转换成ListDictionarystring, object或者直接返回JSON字符串。我一般用ListDictionarystring, string每一行是一个字典键是字段名值是字符串化后的字段值。这样客户端不管用什么语言解析都简单。转换代码多写几行但调用端能少走很多弯路。5. 进阶把接口接进审批流并用Postman验证整条数据链路将Webservice接口跟企业审批流对接是U8二次开发的高频需求。典型场景是OA系统审批通过后自动在U8里生成采购订单或付款单。这个场景里Webservice接口扮演的角色是“单据落地器”——审批流只负责业务审批U8只负责台账数据两者通过接口握手。下面是一个精简的C#客户端调用链示例using System.Net.Http; using System.Xml.Linq; public async Taskstring SyncOrderToU8(string token, string orderXml) { var client new HttpClient(); var soapBody $soap:Envelope xmlns:soaphttp://schemas.xmlsoap.org/soap/envelope/ soap:Body CreateOrder xmlnshttp://tempuri.org/U8ApiService token{token}/token orderXml{orderXml}/orderXml /CreateOrder /soap:Body /soap:Envelope; var response await client.PostAsync(http://u8server/U8ApiService/U8Api.asmx, new StringContent(soapBody, System.Text.Encoding.UTF8, text/xml)); var stream await response.Content.ReadAsStreamAsync(); XDocument doc XDocument.Load(stream); return doc.Root.Value; }这段代码展示了审批流调用后端服务的基本姿势。orderXml是上游系统传过来的单据数据服务端解析后调用U8API生成正式单据。这里的关键是token怎么管理——在审批流场景里上游系统通常是一次性连续调用多个方法我一般让服务端写一个简单Token池登录成功后把token缓存在内存里设置一个两小时的过期时间避免每次调接口都要重新登录U8。验证整条数据链路我习惯用Postman而不是SoapUI。Postman支持手动设置SOAPAction头也能保存整套请求环境。验证步骤是这样的第一步调用Login方法获取token第二步调用GetVoucher或CreateOrder方法传入测试单据号第三步去U8前端界面查这张单据是否生成、字段是否符合预期第四步故意传一个不存在的单号确认接口返回的错误信息能正常透传到调用端。这个四步走完才能说链路是通的。一些性能层面的经验也分享给你。U8登录是有并发许限制的同一个接口服务里如果每次调用都重新登录、从不退出并发稍高就会出现登录失败。我一般会在服务端配置一个定时清理任务定期调Logout释放不活跃的token。另外能用SQL直接查视图解决的查询类接口就不要去调U8API的业务对象——业务对象内部逻辑复杂性能开销大而U8后台有大量现成的业务视图可以直接查数据库只是要注意用只读账号访问。从那以后我每次封装U8接口都强制走一遍“先本机客户端登录验证、再asmx部署、再跨语言调用、再清空缓存”这四步中间任何一步不通都不往下走。这套流程帮我在后来几个项目里少熬了不少夜希望帮到你。本文还有配套的精品资源点击获取