我正在调用基于WCF(非REST)的异步(异步)二进制文件上传服务,我使用“MTOM”和“Streamed”web.config参数构建。环境是ASP.NET MVC 3,.NET 4,IIS 7.5,VS2010。
该服务尝试上传二进制文件,例如zip,pdf或doc。使用非异步方法一切正常。但是,当我调用此异步服务时,我在客户端收到此错误消息:
尝试序列化参数http://tempuri.org/:dataStream时出错。 InnerException消息是'Type'System.IO.FileStream',数据协定名称为'FileStream:http://schemas.datacontract.org/2004/07/System.IO'不是预期的。考虑使用DataContractResolver或将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用KnownTypeAttribute属性或将它们添加到传递给DataContractSerializer的已知类型列表中。有关详细信息,请参阅InnerException。
由于异步方法,我必须覆盖有关流的WCF约束:Stream类型的单个param或MessageContract类型的单个param将被接受为服务方法中的类型。这种方法在非同步方式下工作正常。
为了全面了解细节我到目前为止提出了所有(相关的)代码部分:
服务器
服务合同接口,IUploadService:
[ServiceContract]
public interface IUploadService
{
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginUpload(CompletedAsyncUploadResult dataStream, AsyncCallback callback, object state);
int EndUpload(IAsyncResult result);
}
包装流的容器类和元数据字段,例如文件名:
[DataContract]
[KnownType(typeof(Stream))]
public class StreamUploadContainer
{
[DataMember]
public string fileName;
[DataMember]
public Stream content;
}
将StreamUploadContainer作为Data成员嵌入的IAsyncResult派生类:
// Simple async result implementation.
public class CompletedAsyncUploadResult : IAsyncResult
{
private StreamUploadContainer data;
public StreamUploadContainer Data
{
get { return data; }
set { data = value; }
}
public object AsyncState
{ get { return (object)data; } }
public WaitHandle AsyncWaitHandle
{ get { throw new Exception("The method or operation is not implemented."); } }
public bool CompletedSynchronously
{ get { return true; } }
public bool IsCompleted
{ get { return true; } }
}
服务类UploadService.svc:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class UploadService : IUploadService
{
public IAsyncResult BeginUpload(CompletedAsyncUploadResult dataStream, AsyncCallback callback, object state)
{
string retVal = "All went ok.";
try
{
string docFolderPath = Path.Combine(HostingEnvironment.ApplicationPhysicalPath, @"App_Data/Scanning/");
using (FileStream outputStream = File.Create(Path.Combine(docFolderPath, dataStream.Data.fileName)))
{
dataStream.Data.content.CopyTo(outputStream);
}
dataStream.Data.content.Close();
}
catch (Exception)
{
dataStream.Data.content.Close();
retVal = "Somethin went wrong.";
}
CompletedAsyncUploadResult retValContract = new CompletedAsyncUploadResult();
retValContract.Data = new StreamUploadContainer();
retValContract.Data.fileName = retVal;
retValContract.Data.content = Stream.Null;
return retValContract;
}
public int EndUpload(IAsyncResult result)
{
return 0;
}
}
WCF服务标记文件:
的Web.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IUploadService" messageEncoding="Mtom" transferMode="Streamed" maxReceivedMessageSize="2147483647">
<security mode="None">
<transport clientCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="WcfUploadServiceProject.WcfServices.FileStreamUpload.UploadService" behaviorConfiguration="defaultBehaviour">
<endpoint binding="basicHttpBinding" contract="WcfUploadServiceProject.WcfServices.FileStreamUpload.IUploadService" bindingConfiguration="BasicHttpBinding_IUploadService"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="defaultBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
客户端:
异步调用服务
private void Upload()
{
UploadBinaryService.IUploadService client = new UploadBinaryService.UploadServiceClient();
UploadBinaryService.StreamUploadContainer contract = new UploadBinaryService.StreamUploadContainer();
contract.content = this.GetStreamSample(@"c:\temp\balloon.zip");
contract.fileName = "balloon.zip";
UploadBinaryService.CompletedAsyncUploadResult result = new UploadBinaryService.CompletedAsyncUploadResult();
result.Data = contract;
client.BeginUpload(result, FileStreamBinaryUploadAsyncServiceCallback, client);
}
public void FileStreamBinaryUploadAsyncServiceCallback(IAsyncResult result)
{
var proxy = result.AsyncState as UploadBinaryService.IUploadService;
if (proxy != null)
{
var value = proxy.EndUpload(result);
}
}
App.config中:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IUploadService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Mtom" textEncoding="utf-8" transferMode="Streamed" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<endpoint address="http://example.com/WcfServices/FileStreamUpload/UploadService.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IUploadService" contract="UploadBinaryService.IUploadService" name="BasicHttpBinding_IUploadService" />
</client>
</system.serviceModel>
</configuration>
答案 0 :(得分:0)
尝试使用TPL和TaskFactory.FromAsync方法系列:
TaskFactory.FromAsync(BeginUpload, EndUpload, ...);
.ContinueWith(result => ...);
似乎WCF不支持System.Stream
类型的序列化。对我来说看起来很合理。