2011-09-22 149 views
2

我正在嘗試構建一個WCF服務,該服務允許我的WPF桌面客戶端將文件上傳到服務器。WCF - 通過http上傳流文件上傳

我修改了代碼示例代碼項目(WCF Streaming: Upload/Download Files Over HTTP),我也查看了幾個SO帖子,但似乎無法得到這個工作。

當我執行代碼時,它在服務器嘗試讀取已通過接口傳遞的流的位置出現空引用異常時失敗。

在這一點上,我很遺憾,不知道如何解決這個問題。任何建議表示讚賞。

代碼示例如下:

CustomerDocumentModel是我通過WCF接口與流中讀取客戶端文件中的數據元素:

[DataContract] 
[KnownType(typeof(System.IO.FileStream))] 
public class CustomerDocumentModel : IDisposable 
{ 
    public CustomerDocumentModel() 
    { 
    } 

    public CustomerDocumentModel(string documentName, string path) 
    { 
     DocumentName = documentName; 
     Path = path; 
    } 

    [DataMember] 
    public string DocumentName; 

    [DataMember] 
    public string Path; 

    [DataMember] 
    public System.IO.Stream FileByteStream; 

    public void Dispose() 
    { 
     if (FileByteStream != null) 
     { 
      FileByteStream.Close(); 
      FileByteStream = null; 
     } 
    } 
} 

IBillingService是我的WCF服務的接口定義:

[ServiceContract] 
public interface IBillingService 
{ 
    // other methods redacted... 

    [OperationContract] 
    void UploadCustomerDocument(CustomerDocumentModel model); 
} 

類BillingService有實現WCF服務:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] 
public class BillingService : IBillingService 
{ 
    // Other methods redacted ... 

    public void UploadCustomerDocument(CustomerDocumentModel model) 
    { 
     string path = HttpContext.Current.Server.MapPath(
      String.Format("/Documents/{1}", 
       model.DocumentName)); 

     using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) 
     { 
      const int bufferSize = 4096; 
      byte[] buffer = new byte[bufferSize]; 

      int size = 0; 
      try 
      { 
       // The following Read() fails with a NullReferenceException 
       while ((size = model.FileByteStream.Read(buffer, 0, bufferSize)) > 0) 
       { 
        stream.Write(buffer, 0, size); 
       } 
      } 
      catch 
      { 
       throw; 
      } 
      finally 
      { 
      stream.Close(); 
      model.FileByteStream.Close(); 
      } 
     } 
    } 
} 

從web.config我的WCF Web服務器上的一些相關的位:

<system.web> 
    <compilation debug="true" targetFramework="4.0" /> 
    <httpRuntime maxRequestLength="2097151" useFullyQualifiedRedirectUrl="true" executionTimeout="360"/> 
</system.web> 

<system.serviceModel> 
    <serviceHostingEnvironment 
     aspNetCompatibilityEnabled="true" 
     multipleSiteBindingsEnabled="true" /> 
    <bindings> 
     <basicHttpBinding> 
      <binding name="userHttps" transferMode="Streamed" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"> 
       <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" /> 
       <security mode="None" /> 
      </binding> 
     </basicHttpBinding> 
    </bindings> 
    <behaviors> 
     <serviceBehaviors> 
      <behavior name=""> 
       <dataContractSerializer maxItemsInObjectGraph="2147483646"/> 
       <serviceDebug includeExceptionDetailInFaults="true" /> 
       <serviceMetadata httpGetEnabled="true" /> 
      </behavior> 
     </serviceBehaviors> 
    </behaviors> 
</system.serviceModel> 

客戶端是創建CustomerDocumentModel模型中的WPF/MVVM應用程序,使用一個OpenFileDialog來打開()文件流,然後將模型傳遞給WCF服務上的UploadCustomerDocument方法。

如果我錯過了任何相關的細節,請詢問。

+0

注意:解決方案不一定是WCF。我也會考慮其他C#/ ASP.NET解決方案。 –

回答

2

您的數據類型是什麼使流失敗。這是記錄在MSDN上的位置:http://msdn.microsoft.com/en-us/library/ms731913.aspx 有關段落是:

在流傳輸

使用流傳輸模式的限制將導致運行時執行 附加限制。

通過流式傳輸發生的操作可以具有至多一個輸入或輸出參數的合同 。該參數對應於消息的整個主體 ,並且必須是消息,衍生的 類型的Stream或IXmlSerializable實現。返回 操作值相當於具有輸出參數。

某些WCF功能(例如可靠的消息傳遞,事務和SOAP消息級安全性)依賴於傳輸緩衝消息。 使用這些功能可能會減少或消除使用流式傳輸獲得的性能優勢 。要確保流式傳輸的安全性,請僅使用傳輸級安全性或使用傳輸級安全性加 僅限於身份驗證的消息安全性。

即使將傳輸模式設置爲 以流式傳輸,SOAP標頭也始終被緩衝。郵件的標頭不得超過MaxBufferSize傳輸限額的大小。有關此 設置的更多信息,請參閱運輸配額。

4

我知道這個問題的答案太晚了,我相信你一定也解決了你的問題。這可能對其他人有所幫助:-)

通過Datacontract使用MessageContract,並且只有一個MessageBodyMember具有數據類型Stream和rest all參數均爲MessageHeader。 這裏是例子:

[MessageContract] 

    public class CustomerDocumentModel : IDisposable 
    { 

     public CustomerDocumentModel(string documentName, string path) 
     { 
      DocumentName = documentName; 
      Path = path; 
     } 

     [MessageHeader] 
     public string DocumentName{get;set;} 

     [MessageHeader] 
     public string Path{get;set;} 

     [MessageBodyMember] 
     public System.IO.Stream FileByteStream{get;set;} 

     public void Dispose() 
     { 
      if (FileByteStream != null) 
      { 
       FileByteStream.Close(); 
       FileByteStream = null; 
      } 
     } 
    } 

注意:請確保您在您的配置的傳輸模式是StreamedResponse,也可能要改變MessageEncoding MTOM的獲得更好的性能。

public void UploadCustomerDocument(CustomerDocumentModel model) 
{ 
     var filename = //your file name and path; 
     using (var fs = new FileStream(filename, FileMode.Create)) 

     { 
       model.FileByteStream.CopyTo(fs); 
     } 
}