2012-05-04 19 views
17

संपीड़ित करें मैं वर्तमान में एमवीसी 4 एपी नियंत्रकों को अपने कुछ एमवीसी 3 नियंत्रकों को माइग्रेट करने पर काम कर रहा हूं। मैंने एमवीसी 3 नियंत्रक के लिए संपीड़न तंत्र लागू किया है ActionFilterAttribute विरासत और OnActionExecutiong विधि को ओवरराइड करके विधि प्रतिक्रियाएं प्राप्त करें। कुछ शोध के बाद मुझे पता चला कि मुझे System.Web.HttpFilters से उपयोग करने की आवश्यकता है। यह बहुत अच्छा होगा अगर कोई मुझे इस संपीड़ित HTTP प्रतिक्रिया के लिए GZipHTTP GET प्रतिक्रिया

+0

तरह नियंत्रक में या किसी एपीआई कार्रवाई विधि में निम्नलिखित विशेषता का उपयोग मैं एक ही समस्या हो रही है, हालांकि मेरे मामले में मैं पहले से ही आईआईएस संपीड़न सक्षम होना चाहिए। आपके मामले में, क्या यह आईआईएस संपीड़न था, या आपने कस्टम हैंडलर बनाया था? – Carvellis

+0

हां, मैंने इसके लिए कस्टम हैंडलर का उपयोग किया है जैसे कि डारिन ने यहां उल्लेख किया है। –

उत्तर

39

सबसे आसान आईआईएस स्तर पर enable compression है।

आप आवेदन के स्तर पर यह करने के लिए चाहते हैं के रूप में following post में दिखाया गया है आप एक कस्टम संदेश हैंडलर सौंपने लिख सकते हैं:

public class CompressHandler : DelegatingHandler 
{ 
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>((responseToCompleteTask) => 
     { 
      HttpResponseMessage response = responseToCompleteTask.Result; 

      if (response.RequestMessage.Headers.AcceptEncoding != null) 
      { 
       string encodingType = response.RequestMessage.Headers.AcceptEncoding.First().Value; 

       response.Content = new CompressedContent(response.Content, encodingType); 
      } 

      return response; 
     }, 
     TaskContinuationOptions.OnlyOnRanToCompletion); 
    } 
} 

public class CompressedContent : HttpContent 
{ 
    private HttpContent originalContent; 
    private string encodingType; 

    public CompressedContent(HttpContent content, string encodingType) 
    { 
     if (content == null) 
     { 
      throw new ArgumentNullException("content"); 
     } 

     if (encodingType == null) 
     { 
      throw new ArgumentNullException("encodingType"); 
     } 

     originalContent = content; 
     this.encodingType = encodingType.ToLowerInvariant(); 

     if (this.encodingType != "gzip" && this.encodingType != "deflate") 
     { 
      throw new InvalidOperationException(string.Format("Encoding '{0}' is not supported. Only supports gzip or deflate encoding.", this.encodingType)); 
     } 

     // copy the headers from the original content 
     foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers) 
     { 
      this.Headers.AddWithoutValidation(header.Key, header.Value); 
     } 

     this.Headers.ContentEncoding.Add(encodingType); 
    } 

    protected override bool TryComputeLength(out long length) 
    { 
     length = -1; 

     return false; 
    } 

    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) 
    { 
     Stream compressedStream = null; 

     if (encodingType == "gzip") 
     { 
      compressedStream = new GZipStream(stream, CompressionMode.Compress, leaveOpen: true); 
     } 
     else if (encodingType == "deflate") 
     { 
      compressedStream = new DeflateStream(stream, CompressionMode.Compress, leaveOpen: true); 
     } 

     return originalContent.CopyToAsync(compressedStream).ContinueWith(tsk => 
     { 
      if (compressedStream != null) 
      { 
       compressedStream.Dispose(); 
      } 
     }); 
    } 
} 

सब अब Application_Start में हैंडलर रजिस्टर करने के लिए बचा है है:

GlobalConfiguration.Configuration.MessageHandlers.Add(new CompressHandler()); 
+0

मुझे लगता है कि इस कोड में एक बग है (साथ ही साथ वेब पर पाए गए समान उदाहरणों में): सामग्री-लंबाई शीर्षलेख गलत तरीके से सेट किया गया है क्योंकि सामग्री-लंबाई शीर्षलेख को gzipped सामग्री से कॉपी किया गया है। संपीड़न हैंडलर के माध्यम से स्ट्रिंगकंटेंट पास करके इसे आसानी से पुन: उत्पन्न किया जा सकता है। इसे ठीक करने के लिए, 'originalContent.Headers' वाली रेखा को इस तरह से ठीक करने की आवश्यकता है: 'originalContent.Headers.Where (x => x.Key! =" सामग्री-लंबाई ")' –

+0

कोई स्वीकृति-एन्कोडिंग होने पर कोड विफल हो जाएगा उपलब्ध है। 'अगर (प्रतिक्रिया। ReequestMessage.Headers.AcceptEncoding! = null) 'होना चाहिए' अगर (प्रतिक्रिया। RequestMessage.Headers.AcceptEncoding.Any())' –

+0

मैं एन्कोडिंग टाइप और असाइनमेंट के असाइनमेंट के बीच SendAsync में निम्न जोड़ने की अनुशंसा करता हूं प्रतिक्रिया के बिना त्रुटि प्रतिक्रियाओं को संपीड़न के बिना वापस आने की अनुमति देने के लिए सामग्री 'अगर (प्रतिक्रिया। स्टेटस कोड! = HttpStatusCode.OK || प्रतिक्रिया। सामग्री == शून्य || string.IsNullOrWhiteSpace (एन्कोडिंग टाइप)) प्रतिक्रिया प्रतिक्रिया; ' – Paul

6

का उपयोग कर प्रारंभ करने के लिए नमूना कोड का हिस्सा साझा कर सकता है यदि आप आईआईएस 7+ का उपयोग कर रहे हैं, तो मैं कहूंगा कि आईआईएस को संपीड़न छोड़ दें क्योंकि यह जीजेआईपी संपीड़न का समर्थन करता है। बस turn it on

दूसरी तरफ, संपीड़न नियंत्रक के लिए धातु के बहुत करीब है। आदर्श रूप से नियंत्रक बाइट्स और धाराओं की तुलना में बहुत अधिक स्तर पर काम करना चाहिए।

+0

आम तौर पर मैं सहमत हूं, हालांकि आईआईएस स्तर संपीड़न के लिए किसी भी सर्वर के विन्यास की आवश्यकता होगी। – samosaris

3

एक वर्ग का प्रयोग करें और निम्न कोड

बारे में 210

अब एक और कक्षा बनाएं और निम्न कोड लिखें।

public class CompressedContent : HttpContent 
{ 
    private readonly string _encodingType; 
    private readonly HttpContent _originalContent; 
    public CompressedContent(HttpContent content, string encodingType = "gzip") 
    { 
     if (content == null) 
     { 
      throw new ArgumentNullException("content"); 
     } 
     _originalContent = content; 
     _encodingType = encodingType.ToLowerInvariant(); 
     foreach (var header in _originalContent.Headers) 
     { 
      Headers.TryAddWithoutValidation(header.Key, header.Value); 
     } 
     Headers.ContentEncoding.Add(encodingType); 
    } 
    protected override bool TryComputeLength(out long length) 
    { 
     length = -1; 
     return false; 
    } 
    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) 
    { 
     Stream compressedStream = null; 
     switch (_encodingType) 
     { 
      case "gzip": 
       compressedStream = new GZipStream(stream, CompressionMode.Compress, true); 
       break; 
      case "deflate": 
       compressedStream = new DeflateStream(stream, CompressionMode.Compress, true); 
       break; 
      default: 
       compressedStream = stream; 
       break; 
     } 
     return _originalContent.CopyToAsync(compressedStream).ContinueWith(tsk => 
     { 
      if (compressedStream != null) 
      { 
       compressedStream.Dispose(); 
      } 
     }); 
    } 
} 

अब इस

[Route("GetData")] 
[CompressFilter]   
public HttpResponseMessage GetData() 
{ 
} 
+0

में समाप्त होता है मेरे पास ओवीआईएन मिडलवेयर मेरे वेब एपीआई पर कॉन्फ़िगर किया गया है और यह एकमात्र समाधान है जो मेरे लिए काम करता है। इसके अलावा, आप वास्तव में लक्षित कर सकते हैं जिसे आप संपीड़ित करना चाहते हैं। अच्छा समाधान! – Elferone

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