WCF使用带Stream的MessageContract上传文件返回值报错如何解决
WCF文件上传接口报错解决方案
错误原因梳理
第一次报错原因
WCF有明确约定:如果操作的参数或返回值包含带[MessageContract]特性的类型,那么该操作只能有一个MessageContract类型的参数,返回值只能是void或者另一个MessageContract类型,不能返回string这类基础类型,你最初的实现违反了这个约定,所以抛出加载失败异常。
第二次报错原因
你修改服务端返回MessageContract类型后,客户端报错是因为WCF默认生成服务代理时,会把MessageContract的所有成员拆解为单独的ref/out参数,方法本身返回void,你尝试把void赋值给UploadStreamMessage类型变量,自然会触发类型转换异常。
解决方法
方案1:仅修改客户端适配现有服务端
方法1.1 直接使用拆解后的参数调用
你代码里的outputFile参数实际对应returnFileName属性,调用后直接读取该参数即可得到返回的FileId,不需要接收返回值:
static void Main(string[] args) { ServiceReferenceFile.FileServiceClient client = new ServiceReferenceFile.FileServiceClient(); string fileName = "DummyDataFile.xlsx"; string returnFileId = ""; Stream str = File.OpenRead("DummyDataFile.xlsx"); // 方法无返回值,调用后returnFileId会被自动赋值 client.UploadFile(ref fileName, ref returnFileId, ref str); // 后续直接用returnFileId调用ReturnFile即可 }
方法1.2 重新生成客户端代理保留MessageContract结构
重新添加服务引用时,点击【高级】按钮,勾选【始终生成消息协定】选项,生成的代理就会保留UploadStreamMessage作为参数和返回值,你原来的客户端调用代码就可以正常运行。
方案2:优化服务端实现(更简洁,推荐)
如果没有自定义消息结构的强制要求,可以去掉MessageContract,直接将文件名放在路由中,完全规避参数类型限制问题:
服务端接口修改
[OperationContract] [WebInvoke(UriTemplate = "/UploadFile/{fileName}", Method = "POST")] string UploadFile(string fileName, Stream fileContents);
服务端实现修改
public string UploadFile(string fileName, Stream fileContents) { string fileId = Guid.NewGuid().ToString(); // 这里写扩展名校验、文件保存、公式重计算逻辑 return fileId; }
补充配置注意事项
你现有的Web.config中定义了流传输的绑定和WebHttp行为,但缺少对应的服务端点绑定配置,需要补充如下配置确保流传输生效:
<system.serviceModel> <services> <service name="你的服务类全限定名(比如Namespace.FileService)"> <endpoint address="" binding="webHttpBinding" bindingConfiguration="webHttpBinding" contract="你的服务接口全限定名(比如Namespace.IFileService)" behaviorConfiguration="webHttpBehavior"/> </service> </services> <!-- 你原来的bindings、behaviors等配置保留即可 --> </system.serviceModel>
内容的提问来源于stack exchange,提问作者user2015
相关产品推荐
相关产品推荐

