C# WCF服务,由于“错误”引发流异常;意外的文件结尾“;对于传入流
我编写了一个exchange传输代理,它将电子邮件正文上载到WCF服务。该服务与Exchange位于同一个框中,侦听localhost:1530以接收传入的TCP连接。传输代理使用.NET3.5框架实现,该服务在.NET4.0框架上实现的Windows服务中自托管 我的问题:为什么在读取完成之前终止流,以及如何修复它? 服务合同的定义如下:C# WCF服务,由于“错误”引发流异常;意外的文件结尾“;对于传入流,c#,wcf,stream,C#,Wcf,Stream,我编写了一个exchange传输代理,它将电子邮件正文上载到WCF服务。该服务与Exchange位于同一个框中,侦听localhost:1530以接收传入的TCP连接。传输代理使用.NET3.5框架实现,该服务在.NET4.0框架上实现的Windows服务中自托管 我的问题:为什么在读取完成之前终止流,以及如何修复它? 服务合同的定义如下: [ServiceContract] public interface IReceiveService { [OperationContract]
[ServiceContract]
public interface IReceiveService
{
[OperationContract]
Guid ImportMessage(DateTime dateTimeReceived, string from, IList<string> to, string subject, int attachmentCount, bool bodyEmpty, Guid clientID);
[OperationContract]
void ImportMessageBody(IMessageBody body);
[OperationContract]
void ImportMessageAttachment(IMessageAttachment attachment);
}
public void ImportMessageBody(IMessageBody body)
{
Task.Factory.StartNew(() =>
{
string fileName = GetFileNameFromMagicalPlace();
using (FileStream fs = new FileStream(fileName, FileMode.Append))
{
body.Data.CopyTo(fs); // <---- throws System.IOException right here
}
});
}
[MessageContract]
public class IMessageBody
{
[MessageHeader]
public Guid MessageID { get; set; }
[MessageHeader]
public string Format { get; set; }
[MessageBodyMember]
public System.IO.Stream Data { get; set; }
}
string queueUri = String.Format("net.tcp://localhost:{0}/{1}", port, serviceName);
try
{
host = new ServiceHost(typeof(ReceiveService), new Uri(queueUri));
host.AddDefaultEndpoints();
var endpoint = host.Description.Endpoints.First();
((NetTcpBinding)endpoint.Binding).TransferMode = TransferMode.Streamed;
trace.Log(Level.Debug,String.Format("Created service host: {0}", host));
host.Open();
trace.Log(Level.Debug,"Opened service host.");
}
catch (Exception e)
{
string message = String.Format("Threw exception while attempting to create ServiceHost for {0}:{1}\n{2}", queueUri, e.Message, e.StackTrace);
trace.Log(Level.Debug,message);
trace.Log(Level.Error, message);
}
异常错误为:“错误:读取流时引发异常。”堆栈跟踪:
at System.ServiceModel.Dispatcher.StreamFormatter.MessageBodyStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.Stream.CopyTo...
有一个内部异常:
System.Xml.XmlException: Unexpected end of file. Following elements are not closed: Address, IMessageBody, Body, Envelope.
at System.Xml.XmlExceptionHelper.ThrowXmlException(XmlDictionaryReader reader, String res, String arg1, String arg2, String arg3)
at System.Xml.XmlBufferReader.GetByteHard()
at System.Xml.XmlBufferReader.ReadMultiByteUInt31()
at System.Xml.XmlBinaryReader.ReadName(StringHandle handle)
at System.Xml.XmlBinaryReader.ReadNode()
at System.ServiceModel.Dispatcher.StreamFormatter.MessageBodyStream.Read(Byte[] buffer, Int32 offset, Int32 count)
其他细节如下
IMessageBody
的定义如下:
[ServiceContract]
public interface IReceiveService
{
[OperationContract]
Guid ImportMessage(DateTime dateTimeReceived, string from, IList<string> to, string subject, int attachmentCount, bool bodyEmpty, Guid clientID);
[OperationContract]
void ImportMessageBody(IMessageBody body);
[OperationContract]
void ImportMessageAttachment(IMessageAttachment attachment);
}
public void ImportMessageBody(IMessageBody body)
{
Task.Factory.StartNew(() =>
{
string fileName = GetFileNameFromMagicalPlace();
using (FileStream fs = new FileStream(fileName, FileMode.Append))
{
body.Data.CopyTo(fs); // <---- throws System.IOException right here
}
});
}
[MessageContract]
public class IMessageBody
{
[MessageHeader]
public Guid MessageID { get; set; }
[MessageHeader]
public string Format { get; set; }
[MessageBodyMember]
public System.IO.Stream Data { get; set; }
}
string queueUri = String.Format("net.tcp://localhost:{0}/{1}", port, serviceName);
try
{
host = new ServiceHost(typeof(ReceiveService), new Uri(queueUri));
host.AddDefaultEndpoints();
var endpoint = host.Description.Endpoints.First();
((NetTcpBinding)endpoint.Binding).TransferMode = TransferMode.Streamed;
trace.Log(Level.Debug,String.Format("Created service host: {0}", host));
host.Open();
trace.Log(Level.Debug,"Opened service host.");
}
catch (Exception e)
{
string message = String.Format("Threw exception while attempting to create ServiceHost for {0}:{1}\n{2}", queueUri, e.Message, e.StackTrace);
trace.Log(Level.Debug,message);
trace.Log(Level.Error, message);
}
显示相关位的传输代理的缩写版本(我希望):
嗯,代码太多了。您应该尽量将代码最小化到尽可能小的可复制示例。我想问题可能在这里:
public void ImportMessageBody(IMessageBody body)
{
Task.Factory.StartNew(() =>
{
string fileName = GetFileNameFromMagicalPlace();
using (FileStream fs = new FileStream(fileName, FileMode.Append))
{
body.Data.CopyTo(fs); // <---- throws System.IOException right here
}
});
}
public void导入消息体(IMessageBody)
{
Task.Factory.StartNew(()=>
{
字符串文件名=GetFileNameFromMagicalPlace();
使用(FileStream fs=newfilestream(fileName,FileMode.Append))
{
body.Data.CopyTo(fs);//问题本质上是我通过调用Task.Factory.StartNew
来执行不必要的并发操作,而不是通过servicebeaviorAttribute
来确保我的服务正确配置为并发。感谢Ladislav为我指明了正确的方向。Ladislav,谢谢你的回答(还有你另一个答案的链接!)我发布了这么多代码,因为我不知道问题出在哪里,这是我所关心的最小可能的可复制示例。这毕竟不是问题所在。我现在已将我的ImportMessageBody
操作与[OperationBehavior]降级(AutoDisposeparameters=false)
并实现了一个操作已完成
事件处理程序,但Stream.CopyTo
仍然以与以前相同的方式失败。不过,看起来您走对了方向,因为当我在ImportMessageBody
实现中同步执行Stream.CopyTo
时(也就是说,没有任务
),它可以工作……这很有意义,因为不需要像这样手动实现并发。WCF为您实现并发。我将此标记为答案,因为它为我指明了正确的方向,即使它最终不是答案。