2012-03-16 9 views
5

मुझे वर्तमान में एचटीएमएल से मेरी बाकी सेवा (डब्ल्यूसीएफ आरईएसटी) में फ़ाइल अपलोड करते समय कोई समस्या है। फ़ाइल अपलोड करते समय, मैं फ़ाइल की सामग्री के साथ शीर्षक और विवरण जैसी जानकारी भेजना चाहता हूं।एचटीएमएल फॉर्म (मल्टीपार्ट/फॉर्म-डेटा) से डब्लूसीएफ आरईएसटी सेवा से फ़ाइल को पूरे फॉर्म के इनपुट स्ट्रीम किए बिना स्ट्रीम के रूप में अपलोड करें?

[OperationContract] 
     [WebInvoke(
      BodyStyle = WebMessageBodyStyle.Bare, 
      Method = "POST", 
      UriTemplate = "/Note/{noteId}/Attachment")] 
     [Description("Add an attachment to a Note.")] 
     void AddAttachmentToNote(string noteId, AttachmentRequestDto attachmentRequestDto); 

AttachmentRequestDto साथ

के रूप में परिभाषित:

<form id="testForm" action="http://localhost.:1576/NotepadService.svc/Note/91f6413c-4d72-42ca-a0f3-38df15759fc9/Attachment" method="POST" enctype="multipart/form-data"> 
     <table> 
      <tr><td>Title:</td><td><input type="text" name="Title"></td></tr> 
      <tr><td>Description:</td><td><input type="text" name="Description"></td></tr> 
      <tr><td>Filename:</td><td><input type="text" name="Filename"></td></tr> 
      <tr><td>File:</td><td><input type="file" name="Contents"></td></tr> 
      <tr><td/><td><input type="submit" value="Send"></td></tr> 
     </table> 
    </form> 

सर्वर साइड, मैं इस विधि में अनुवाद करना चाहते हैं:

तो, मैं इस तरह एक परीक्षण प्रपत्र बना लिया है

[DataContract] 
    public class AttachmentRequestDto 
    { 
     [DataMember] 
     public string Title { get; set; } 
     [DataMember] 
     public string Description { get; set; } 
     [DataMember] 
     public string Filename { get; set; } 
     [DataMember] 
     public Stream Contents { get; set; } 
    } 

तो, लंबी कहानी छोटी है, मैं शीर्षक और विवरण को स्ट्रिंग मान के रूप में प्राप्त करना चाहता हूं, जबकि conte प्राप्त करना एक धारा के रूप में फ़ाइल के एनटीएस। यह काम नहीं प्रतीत होता है, क्योंकि HTML फॉर्म फ़ाइल की सामग्री के साथ फ़ॉर्म की सभी सामग्री (इसलिए शीर्षक और विवरण) को स्ट्रीम में रखेगा। वजह,

[OperationContract] 
     [WebInvoke(
      BodyStyle = WebMessageBodyStyle.Bare, 
      Method = "POST", 
      UriTemplate = "/Note/{noteId}/Attachment")] 
     [Description("Add an attachment to a Note.")] 
     void AddAttachmentToNote(string noteId, Stream formContents); 

काम करता है के रूप में मेरे बाकी विधि को परिभाषित करने, लेकिन फिर मैं (क्या मैं वास्तव में क्या करना चाहते हैं की तुलना में जो एक अच्छा तरीका नहीं है,) अपने डेटा के सभी प्राप्त करने के लिए धारा पार्स करने के लिए की जरूरत है।

शायद मुझे 2 अलग-अलग सेवा विधियों को परिभाषित करने की आवश्यकता है, केवल एक फ़ाइल स्वीकार कर रहा है, और दूसरा फ़ाइल के विवरण स्वीकार कर रहा है? हालांकि, इसका मतलब यह होगा कि मेरे व्यवसाय के नियम (शीर्षक आवश्यक + फाइलकंट्स आवश्यक) को अलग-अलग मान्य किया जाना चाहिए (जैसा कि आरईएसटी स्टेटलेस है)।

कुछ ऐसा जो उल्लेखनीय हो सकता है: मुझे फ़ाइल की सामग्री को फ़ाइल सिस्टम पर नहीं, डेटाबेस में सहेजने की आवश्यकता है।

क्या किसी के पास इस पर कुछ इनपुट है? मैं इस पर फंस गया हूं ...

धन्यवाद!

उत्तर

6

कृपया कुछ कोड है कि आप बाकी सेवा करने के लिए एक कॉल में अपनी विवरण के साथ एक फ़ाइल पारित करने के लिए मदद कर सकता है लगता है: जैसा कि नीचे दिखाया

सबसे पहले आप कुछ एक MultipartParser कहा जाता है की आवश्यकता होगी:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Text; 
using System.Text.RegularExpressions; 

namespace SampleService 
{ 
    public class MultipartParser 
    { 
     private byte[] requestData; 
     public MultipartParser(Stream stream) 
     { 
      this.Parse(stream, Encoding.UTF8); 
      ParseParameter(stream, Encoding.UTF8); 
     } 

     public MultipartParser(Stream stream, Encoding encoding) 
     { 
      this.Parse(stream, encoding); 
     } 

     private void Parse(Stream stream, Encoding encoding) 
     { 
      this.Success = false; 

      // Read the stream into a byte array 
      byte[] data = ToByteArray(stream); 
      requestData = data; 

      // Copy to a string for header parsing 
      string content = encoding.GetString(data); 

      // The first line should contain the delimiter 
      int delimiterEndIndex = content.IndexOf("\r\n"); 

      if (delimiterEndIndex > -1) 
      { 
       string delimiter = content.Substring(0, content.IndexOf("\r\n")); 

       // Look for Content-Type 
       Regex re = new Regex(@"(?<=Content\-Type:)(.*?)(?=\r\n\r\n)"); 
       Match contentTypeMatch = re.Match(content); 

       // Look for filename 
       re = new Regex(@"(?<=filename\=\"")(.*?)(?=\"")"); 
       Match filenameMatch = re.Match(content); 

       // Did we find the required values? 
       if (contentTypeMatch.Success && filenameMatch.Success) 
       { 
        // Set properties 
        this.ContentType = contentTypeMatch.Value.Trim(); 
        this.Filename = filenameMatch.Value.Trim(); 

        // Get the start & end indexes of the file contents 
        int startIndex = contentTypeMatch.Index + contentTypeMatch.Length + "\r\n\r\n".Length; 

        byte[] delimiterBytes = encoding.GetBytes("\r\n" + delimiter); 
        int endIndex = IndexOf(data, delimiterBytes, startIndex); 

        int contentLength = endIndex - startIndex; 

        // Extract the file contents from the byte array 
        byte[] fileData = new byte[contentLength]; 

        Buffer.BlockCopy(data, startIndex, fileData, 0, contentLength); 

        this.FileContents = fileData; 
        this.Success = true; 
       } 
      } 
     } 

     private void ParseParameter(Stream stream, Encoding encoding) 
     { 
      this.Success = false; 

      // Read the stream into a byte array 
      byte[] data; 
      if (requestData.Length == 0) 
      { 
       data = ToByteArray(stream); 
      } 
      else { data = requestData; } 
      // Copy to a string for header parsing 
      string content = encoding.GetString(data); 

      // The first line should contain the delimiter 
      int delimiterEndIndex = content.IndexOf("\r\n"); 

      if (delimiterEndIndex > -1) 
      { 
       string delimiter = content.Substring(0, content.IndexOf("\r\n")); 
       string[] splitContents = content.Split(new[] {delimiter}, StringSplitOptions.RemoveEmptyEntries); 
       foreach (string t in splitContents) 
       { 
        // Look for Content-Type 
        Regex contentTypeRegex = new Regex(@"(?<=Content\-Type:)(.*?)(?=\r\n\r\n)"); 
        Match contentTypeMatch = contentTypeRegex.Match(t); 

        // Look for name of parameter 
        Regex re = new Regex(@"(?<=name\=\"")(.*)"); 
        Match name = re.Match(t); 

        // Look for filename 
        re = new Regex(@"(?<=filename\=\"")(.*?)(?=\"")"); 
        Match filenameMatch = re.Match(t); 

        // Did we find the required values? 
        if (name.Success || filenameMatch.Success) 
        { 
         // Set properties 
         //this.ContentType = name.Value.Trim(); 
         int startIndex; 
         if (filenameMatch.Success) 
         { 
          this.Filename = filenameMatch.Value.Trim(); 
         } 
         if(contentTypeMatch.Success) 
         { 
          // Get the start & end indexes of the file contents 
          startIndex = contentTypeMatch.Index + contentTypeMatch.Length + "\r\n\r\n".Length; 
         } 
         else 
         { 
          startIndex = name.Index + name.Length + "\r\n\r\n".Length; 
         } 

         //byte[] delimiterBytes = encoding.GetBytes("\r\n" + delimiter); 
         //int endIndex = IndexOf(data, delimiterBytes, startIndex); 

         //int contentLength = t.Length - startIndex; 
         string propertyData = t.Substring(startIndex - 1, t.Length - startIndex); 
         // Extract the file contents from the byte array 
         //byte[] paramData = new byte[contentLength]; 

         //Buffer.BlockCopy(data, startIndex, paramData, 0, contentLength); 

         MyContent myContent = new MyContent(); 
         myContent.Data = encoding.GetBytes(propertyData); 
         myContent.StringData = propertyData; 
         myContent.PropertyName = name.Value.Trim(); 

         if (MyContents == null) 
          MyContents = new List<MyContent>(); 

         MyContents.Add(myContent); 
         this.Success = true; 
        } 
       } 
      } 
     } 

     private int IndexOf(byte[] searchWithin, byte[] serachFor, int startIndex) 
     { 
      int index = 0; 
      int startPos = Array.IndexOf(searchWithin, serachFor[0], startIndex); 

      if (startPos != -1) 
      { 
       while ((startPos + index) < searchWithin.Length) 
       { 
        if (searchWithin[startPos + index] == serachFor[index]) 
        { 
         index++; 
         if (index == serachFor.Length) 
         { 
          return startPos; 
         } 
        } 
        else 
        { 
         startPos = Array.IndexOf<byte>(searchWithin, serachFor[0], startPos + index); 
         if (startPos == -1) 
         { 
          return -1; 
         } 
         index = 0; 
        } 
       } 
      } 

      return -1; 
     } 

     private byte[] ToByteArray(Stream stream) 
     { 
      byte[] buffer = new byte[32768]; 
      using (MemoryStream ms = new MemoryStream()) 
      { 
       while (true) 
       { 
        int read = stream.Read(buffer, 0, buffer.Length); 
        if (read <= 0) 
         return ms.ToArray(); 
        ms.Write(buffer, 0, read); 
       } 
      } 
     } 

     public List<MyContent> MyContents { get; set; } 

     public bool Success 
     { 
      get; 
      private set; 
     } 

     public string ContentType 
     { 
      get; 
      private set; 
     } 

     public string Filename 
     { 
      get; 
      private set; 
     } 

     public byte[] FileContents 
     { 
      get; 
      private set; 
     } 
    } 

    public class MyContent 
    { 
     public byte[] Data { get; set; } 
     public string PropertyName { get; set; } 
     public string StringData { get; set; } 
    } 
} 
दिखाया गया है

अब आप अपने बाकी विधि को परिभाषित:

[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest)] 
AttachmentRequestDto AddAttachmentToNote(Stream stream); 
अब

उपरोक्त विधि के implemenation दिखाया गया है:

दिखाया गया है ग्राहक मैं एक पोस्ट प्रदर्शन कर से अब

[DataContract] 
    public class AttachmentRequestDto 
    { 
     [DataMember] 
     public string Title { get; set; } 
     [DataMember] 
     public string Description { get; set; } 
     [DataMember] 
     public string Filename { get; set; } 
    } 

:

public AttachmentRequestDto AddAttachmentToNote(Stream stream) 
     { 
      MultipartParser parser = new MultipartParser(stream); 
      if(parser != null && parser.Success) 
      { 
       foreach (var content in parser.MyContents) 
       { 
        // Observe your string here which is a serialized version of your file or the object being passed. Based on the string do the necessary action. 
        string str = Encoding.UTF8.GetString(content.Data); 

       } 
      } 

      return new AttachmentRequestDto(); 
     } 

मेरे AttachmentRequestDto दिखाया गया है लग रहा है

Image image = Image.FromFile("C:\\Users\\Guest\\Desktop\\sample.png"); 
MemoryStream ms = new MemoryStream(); 
image.Save(ms, System.Drawing.Imaging.ImageFormat.Png); 
byte[] imageArray = ms.ToArray(); 
ms.Close(); 

AttachmentRequestDto objAttachmentRequestDto = new AttachmentRequestDto(); 
objAttachmentRequestDto.Title = "Sample"; 
objAttachmentRequestDto.Description = "Sample book"; 
objAttachmentRequestDto.FileName = "SampleBook.png"; 

var serializer = new DataContractSerializer(typeof(AttachmentRequestDto)); 
var ms = new MemoryStream(); 
serializer.WriteObject(ms, objAttachmentRequestDto); 
ms.Position = 0; 
var reader = new StreamReader(ms); 
string requestBody = reader.ReadToEnd(); 

var client = new RestClient();    
client.BaseUrl = "http://localhost/SampleService/Service1.svc"; 
var request = new RestRequest(method) { DateFormat = DataFormat.Xml.ToString(), Resource = resourceUrl }; 
if(requestBody !=null) 
     request.AddParameter("objAttachmentRequestDto", requestBody); 
request.AddFile("stream", image, "Array.png"); 
var response = client.Execute(request); 

मैं कहा जाता है ऊपर कोड के लिए एक तीसरी पार्टी dll का उपयोग करते हैं RESTSharp।(फ़ाइल, डाटाबेस, आदि के लिए बचाने के लिए ..)

एक बार सर्वर पर MultipartParser आपके अनुरोध सीमा को दिखाता है आवश्यक सामग्री विभाजित करने के लिए और फिर तुम क्या विभाजन सामग्री में से प्रत्येक के साथ क्या करना है पर तय कर सकते हैं

बस सुनिश्चित करें कि आपके पास उपरोक्त के लिए कॉन्फ़िगरेशन कॉन्फ़िगरेशन प्रविष्टियां हैं, साथ ही डेटा कंट्रैक्टसेरियलाइज़र प्रॉपर्टी के साथ और webHttp बाइंडिंग के लिए readerQuotas सेट है।

नोट: यदि आवश्यक हो तो मल्टीपार्ट पार्सर को फिर से संसाधित किया जा सकता है।

+0

बहुत बहुत धन्यवाद। यह वास्तव में जाने वाली विधि थी क्योंकि मैंने अपनी मूल पोस्ट में वर्णन करने की कोशिश की थी ("... लेकिन फिर मुझे अपने सभी डेटा प्राप्त करने के लिए स्ट्रीम को पार्स करने की आवश्यकता है (जो वास्तव में मैं चाहता हूं की तुलना में एक अच्छा दृष्टिकोण नहीं है करने के लिए) "। मैं क्या कर रहा था, अटैचमेंट हैंडलर नामक HTTPHandler बना रहा था, जिसके लिए मैंने अपनी फॉर्म सामग्री पोस्ट की थी। इस तरह, मुझे स्ट्रीम पार्सिंग का सहारा लेने के बिना मेरा मेटाडाटा और फ़ाइल सामग्री अलग-अलग मिली। संपादित करें (क्योंकि रिटर्न वास्तव में मेरे लिए पोस्ट बनाता है): हालांकि, मैं इसे एक उत्तर के रूप में चिह्नित कर रहा हूं, क्योंकि यह केवल स्ट्रीम पार्सिंग करने के लिए समझ में आता है। – StriVa

+0

मैंने पहले restsharp का उपयोग नहीं किया है। क्या आप समझा सकते हैं कि आप इसे ऊपर क्यों उपयोग करते हैं? – Hoppe

+0

@ होपपे: रेस्टशर्प सिर्फ एक तृतीय पक्ष रीस्ट क्लाइंट लाइब्रेरी है जो आपको वेब अनुरोध करने में मदद करती है। उपयोग करने में आसान और कम देव कार्य। – Rajesh

संबंधित मुद्दे