2011-01-05 4 views
1

나는 왜 이것이 작동하지 않는지 알아 내려고 노력하면서 대부분의 시간을 보냈습니다. 개체를 클라이언트에 스트리밍하는 WCF 서비스가 있습니다. 클라이언트는 파일을 디스크에 기록합니다.WCF Stream.Read는 항상 클라이언트에서 0을 반환합니다.

namespace StreamServiceNS 
{ 
    [ServiceContract] 
    public interface IStreamService 
    { 
     [OperationContract] 
     Stream downloadStreamFile(); 
    } 
} 
class StreamService : IStreamService 
{ 
    public Stream downloadStreamFile() 
    { 
     ISSSteamFile sFile = getStreamFile(); 
     BinaryFormatter bf = new BinaryFormatter(); 
     MemoryStream stream = new MemoryStream(); 
     bf.Serialize(stream, sFile); 
     return stream; 
    } 
} 

서비스 설정 파일 :

<system.serviceModel> 
<services> 
    <service name="StreamServiceNS.StreamService"> 
    <endpoint address="stream" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IStreamService" 
       name="BasicHttpEndpoint_IStreamService" contract="SWUpdaterService.ISWUService" /> 
    </service> 
</services> 
<bindings> 
    <basicHttpBinding> 
    <binding name="BasicHttpBinding_IStreamService" transferMode="StreamedResponse" 
      maxReceivedMessageSize="209715200"></binding> 
    </basicHttpBinding> 
</bindings> 
<behaviors> 
    <serviceBehaviors> 
    <behavior> 
     <serviceThrottling maxConcurrentCalls ="100" maxConcurrentSessions="400"/> 
     <serviceMetadata httpGetEnabled="true"/> 
     <serviceDebug includeExceptionDetailInFaults="false"/> 
    </behavior> 
    </serviceBehaviors> 
</behaviors> 
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" /> 
</system.serviceModel> 

클라이언트 :

TestApp.StreamServiceRef.StreamServiceClient client = new StreamServiceRef.StreamServiceClient(); 
     try 
     { 
      Stream stream = client.downloadStreamFile(); 
      int bufferLength = 8 * 1024; 
      byte[] buffer = new byte[bufferLength]; 

      FileStream fs = new FileStream(@"C:\test\testFile.exe", FileMode.Create, FileAccess.Write); 
      int bytesRead; 
      while ((bytesRead = stream.Read(buffer, 0, bufferLength)) > 0) 
      { 
       fs.Write(buffer, 0, bytesRead); 
      } 
      stream.Close(); 
      fs.Close(); 
     } 
     catch (Exception e) { Console.WriteLine("Error: " + e.Message); } 

클라이언트의 app.config :

<system.serviceModel> 
    <bindings> 
     <basicHttpBinding> 
      <binding name="BasicHttpEndpoint_IStreamService" maxReceivedMessageSize="209715200" transferMode="StreamedResponse"> 
      </binding> 
     </basicHttpBinding> 
    </bindings> 
    <client> 
     <endpoint address="http://[server]/StreamServices/streamservice.svc/stream" 
      binding="basicHttpBinding" bindingConfiguration="BasicHttpEndpoint_IStreamService" 
      contract="StreamServiceRef.IStreamService" name="BasicHttpEndpoint_IStreamService" /> 
    </client> 
    </system.serviceModel> 
내가 stream.Read(buffer, 0, bufferLength) 전화는 항상 여기에 0을 반환하지만 내 코드입니다

(간결하게하기 위해 일부 코드 잘림)

나는 WCF 스트리밍 서비스를 만들 때 찾을 수있는 모든 것을 읽었으며 내 코드는 그 코드와 다르지 않습니다. 스트리밍을 버퍼링으로 대체하고 객체를 전송할 수 있지만 스트리밍하려고하면 클라이언트는 항상 스트림을 "비어있는"것으로 간주합니다. testFile.exe이 생성되지만 크기는 0KB입니다.

무엇이 누락 되었습니까?


UPDATE
흠 .... WCF 테스트 클라이언트가 스트림을 지원하지 않는다고 알려주기 때문에 디버깅 할 수 없습니다. 그러나 while 루프를 넣지 않고 fs.Write (...)가 하나만 있으면 스트림이 닫히면 8KB를 쓸 것이므로 스트림에서 스트림을 가로 지르는 무언가가 있다는 것을 알고 있습니다. 그래서 무언가가 가로 질러 가고 있습니다.

나는 귀하의 게시물을 보았고, 추가 :

[MessageContract] 
public class FileDownloadMessage 
{ 
    [MessageBodyMember(Order = 1)] 
    public MemoryStream FileByteStream; 
} 

을 내 IStreamService에. downloadStreamFile()은 이제 FileDownloadMessage 개체를 반환합니다.

그러나 내 클라이언트에서 서비스 참조를 업데이트 한 후 downloadStreamFile()TestApp.StreamServiceRef.MemoryStream 개체를 반환한다고 생각합니다.
downloadStreamFileRequest() 클래스도 만들었지 만, 그 클래스는 어디서 왔는지 모릅니다.

답변

2

우선 서비스를 디버그하고 스트림에 클라이언트에 전송되기 전에 스트림에 데이터가 있는지 확인할 수 있습니까?

WCF 서비스에서도 스트림을 반환합니다. 꽤 문제는 아니지만 문제도있었습니다. 다행히도 내가 찾은 해결책이 도움이되기를 바랍니다. 나는 해결책을 찾았다 here. 이 솔루션은 스트림 업로드를 처리하지만 다운로드 서비스의 구현은 정상적으로 작동합니다.
내 SO 질문/솔루션 here입니다

EDIT (내 자신의 대답은 당신이 아마 봐야 하나이며, 그와 같은하지 허용 대답은 AJAX에 따라 다릅니다) : 기본적인 차이가 나는 내 스트림을 감싸이다 MessageContract 어디에서 유일한 메시지의 멤버로 Stream을 지정했으며 basicHttp 바인딩 'transferMode'특성은 'Streamed'입니다. 나는 WCF를 처음 사용하기 때문에 이것이 도움이 될지 확신 할 수 없지만 그것이 이루어 지길 바란다.

편집 2 : 서비스 참조를 사용하지 않겠습니다. 'cmd'프롬프트에서 'svcutil.exe [mex url]'을 실행하면 서비스 참조에서 얻은 것보다 더 정확한 config 파일과 .cs 파일을 얻을 수 있습니다. 내 프로젝트에 서비스 참조가 없기 때문에 잘 작동합니다. 생성 된 .cs 파일을 프로젝트에 추가하고 이에 대한 'using'문을 추가하십시오. 또한 구성 설정을 클라이언트의 앱 또는 웹 구성 파일에 추가 할 수 있습니다. 생성 된 2 개의 파일은 svcutil 명령을 실행하는 디렉토리에 만들어집니다.

DownloadStreamFileRequest 클래스는 서비스 호출시 클라이언트가 base.Channel에 전달하는 요청 객체 일뿐입니다. 아래에있는 내 코드에서, 그것은 내 생성 된 .cs 파일에서

GetExportedFileRequest을라고, 나는 System.IO.MemoryStream를 반환하는 다음과 같은 방법을 가지고 있고 그것은 FileDownloadMessage 객체에서이 스트림을 가져옵니다

public System.IO.MemoryStream GetExportedFile() 
{ 
    GetExportedFileRequest inValue = new GetExportedFileRequest(); 
    FileDownloadMessage retVal = ((IDailyBillingParser)(this)).GetExportedFile(inValue); 
    return retVal.FileByteStream; 
} 
+0

위의 업데이트를 확인하십시오. – Marcus

+0

나는 서비스 레퍼런스를 사용하지 않을 것이다. "cmd"프롬프트에서 "svcutil.exe [mex url]"을 실행하면 서비스 참조에서 얻은 것보다 더 정확한 config 파일과 .cs 파일을 얻을 수 있습니다. 내 프로젝트에 서비스 참조가 없기 때문에 잘 작동합니다. 생성 된 .cs 파일을 프로젝트에 추가하고 이에 대한 'using'문을 추가하십시오. 수정 : 또한 클라이언트의 앱 또는 웹 설정 파일에 환경 설정을 추가 할 수 있습니다. 생성 된 2 개의 파일은 svcutil 명령을 실행하는 디렉토리에 만들어집니다. – norepro

+0

감사합니다. svcutil을 사용하여 "참조"를 만들고 코드에서 모든 설정 내용을 수행했습니다. 나는 또한 스트림을 memorystream이 아닌 파일 스트림으로 보내는 것을 끝내었고 어떤 이유로 도움이되는 것처럼 보였다. – Marcus

0

당신이 원하는 그 어떤 이유인가 "BinaryFormatter"을 사용 하시겠습니까? 아니,이

반환 새로운하여 FileStream처럼 WCF에서 스트림을 반환 할 수있는 경우 (@ "D : \ yourFileName.txt", FileMode.Open, FileAccess.Read)

+0

스트림에 넣고있는 객체가 메모리에 있기 때문에'BinaryFormatter'를 사용했습니다. 디스크에 기록되지 않았습니다. – Marcus

3

을 나는 또한이 문제와 무엇을했다 나를 위해 일한 클라이언트에 다시 보내기 전에 스트림의 위치를 ​​0으로 설정했다.

+0

나는 그 의견에 고맙다고 말하기로되어 있지 않다는 것을 안다. 그러나 심각하게, 너 정말 많이 고마워. 너는 전설이다 –

+0

그것의 항상 운이 좋게하는 재료는 너를 위로 여행한다. – MikeT

관련 문제