2017-01-02 122 views
2

我想压缩从客户端发送的请求。ServiceStack客户端压缩

我已经找到了Q/A: ServiceStack - How To Compress Requests From Client

但是使用这个代码时,我从服务器获取一个SerializationException内容应该与开始“{”而不是“\ u001F ......”

该解决方案是否仍然有效,或者有另一种方法来压缩客户端请求负载?


更新1:这是来自Fiddler的输出。要求:

POST http://xxxxxx:8104/entries HTTP/1.1 
Accept: application/json 
User-Agent: ServiceStack .NET Client 4,51 
Accept-Encoding: gzip,deflate 
Content-Encoding: gzip 
Content-Type: application/json 
Host: xxxxxx:8104 
Content-Length: 187 
Expect: 100-continue 

[binary data not shown here] 

和响应:

HTTP/1.1 400 Bad Request 
Transfer-Encoding: chunked 
Content-Type: application/json; charset=utf-8 
Server: Microsoft-HTTPAPI/2.0 
Date: Tue, 03 Jan 2017 07:22:57 GMT 

427 
{"ResponseStatus":{"ErrorCode":"SerializationException","Message":"Could not deserialize 'application/json' request using Namespace.NameOfDto'\nError: System.Runtime.Serialization.SerializationException: Type definitions should start with a '{', expecting serialized type 'NameOfDto', got string starting with: \u001F \b\u0000\u0000\u0000\u0000\u0000\u0004\u00005 \n @\u0010 e 1 P W :h\u001D :D M'YЙ \u001D B| F 7 \r\n at ServiceStack.Text.Common.DeserializeTypeRefJson.StringToType(TypeConfig typeConfig, String strType, EmptyCtorDelegate ctorFn, Dictionary`2 typeAccessorMap)\r\n at ServiceStack.Text.Common.DeserializeType`1.<>c__DisplayClass1_0.<GetParseMethod>b__1(String value)\r\n at ServiceStack.Text.JsonSerializer.DeserializeFromString(String value, Type type)\r\n at ServiceStack.Text.JsonSerializer.DeserializeFromStream(Type type, Stream stream)\r\n at ServiceStack.Serialization.JsonDataContractSerializer.DeserializeFromStream(Type type, S 
27e 
tream stream)\r\n at ServiceStack.Host.Handlers.ServiceStackHandlerBase.CreateContentTypeRequest(IRequest httpReq, Type requestType, String contentType)","StackTrace":" at ServiceStack.Host.Handlers.ServiceStackHandlerBase.CreateContentTypeRequest(IRequest httpReq, Type requestType, String contentType)\r\n at ServiceStack.Host.RestHandler.CreateRequest(IRequest httpReq, IRestPath restPath, Dictionary`2 requestParams)\r\n at ServiceStack.Host.RestHandler.CreateRequest(IRequest httpReq, IRestPath restPath)\r\n at ServiceStack.Host.RestHandler.ProcessRequestAsync(IRequest httpReq, IResponse httpRes, String operationName)"}} 
0 

客户:

public class GzipJsonServiceClient : JsonServiceClient 
{ 
    public GzipJsonServiceClient() 
    { 
     SetRequestFilter(); 
    } 

    public GzipJsonServiceClient(string baseUri) 
     : base(baseUri) 
    { 
     SetRequestFilter(); 
    } 

    public override void SerializeToStream(IRequest requestContext, object request, Stream stream) 
    { 
     using (var gzipStream = new GZipStream(stream, CompressionMode.Compress)) 
     { 
      base.SerializeToStream(requestContext, request, gzipStream); 
      gzipStream.Close(); 
     } 
    } 

    private void SetRequestFilter() 
    { 
     RequestFilter = req => 
     { 
      if (req.Method.HasRequestBody()) 
      { 
       req.Headers.Add(HttpRequestHeader.ContentEncoding, CompressionTypes.GZip); 
      } 
     }; 
    } 
} 

请求代码:

var client = new GzipJsonServiceClient(uri) { Timeout = TimeSpan.FromSeconds(10) }; 
var request = new NameOfDto(); 
client.Post(request); 

服务端是从Visual Studio模板,托管ServiceStack Windows内部的服务服务。这是相当香草,用一个方法,该方法没有达到:

public void Post(NameOfDto request) 
{ 
    var appHost = (AppHost)HostContext.AppHost; 
    ... 
} 
+0

您可以更新您的问题以显示您使用的代码以及使用Fiddler之类的原始HTTP请求/响应头。 – mythz

回答

1

支持客户端Gzip已+ Deflate压缩已被添加到ServiceStack HttpListener服务器和所有C#服务客户端在this commit

这可让您的客户端请求与新RequestCompressionType属性,e.g:

var client = new JsonServiceClient(baseUrl) 
{ 
    RequestCompressionType = CompressionTypes.GZip, 
}; 

var response = client.Post(new NameOfDto { ... }); 

此功能可从v4.5.5 +这就是现在available on MyGet

+0

有问题......在单元测试中,如果您向Hello类中添加“public List Dummy {get; set;}”并将其填充为字符串,则在HelloService中的Any方法中,它将作为null到达。有任何想法吗? –

+0

@MartinA请更新这个问题或要求有足够的代码来repro – mythz

+0

新增一个后续问题在这里:http://stackoverflow.com/questions/41466387/servicestack-client-compression-fails-with-generic-名单 –

0

OK,所以我想出了一个办法来解决我的问题,使用Newtonsoft JSON的NuGet。尽管我更喜欢使用ServiceStack的“开箱即用”解决方案,但我并不需要修改DTO。

我加入了IRequiresRequestStream接口到我的DTO:

[Route("/entries", "POST")] 
public class NameOfDto : IRequiresRequestStream 
{ 
    [ApiMember(IsRequired = true)] 
    public string OneOfManyProperties { get; set; } 

    public Stream RequestStream { get; set; } 
} 

然后创建新类:

public static class GZipRequestStreamParser 
{ 
    public static T ParseRequestStream<T>(Stream requestStream) 
    { 
     using (var gzipStream = new GZipStream(requestStream, CompressionMode.Decompress)) 
     using (var reader = new StreamReader(gzipStream)) 
     { 
      var serializedObject = reader.ReadToEnd(); 
      var deserializedObject = JsonConvert.DeserializeObject<T>(serializedObject); 
      return deserializedObject; 
     } 
    } 
} 

最后更新的终点:

public void Post(NameOfDto request) 
{ 
    request = GZipRequestStreamParser.ParseRequestStream<NameOfDto>(request.RequestStream); 

    var appHost = (AppHost)HostContext.AppHost; 

    // work with request object! 
}