2014-02-24 49 views
1

ServiceStack会忽略Accept头文件的任何原因?该服务托管在ASP.NET应用程序中,并在IDE中进行调试。前40个左右的服务调用,使用System.Web.WebRequest对象导致服务正确响应。大约50次调用后,客户端检测到404错误(断点在服务中未命中)。从那时起,Accept头被忽略。所有后续请求始终返回XML。ServiceStack忽略Accept头文件

正在使用的客户端...

var client = (HttpWebRequest)WebRequest.Create(uri); 
client.Method = WebRequestMethods.Http.Post; 
client.AllowWriteStreamBuffering = false;  
client.SendChunked = true;      
client.ContentType = "multipart/form-data;";  
client.Timeout = int.MaxValue;     // HACK:REMOVE 
client.Accept = "application/json"; 

电话是有点乱,现在(尝试调试失败)...

using (FileStream fileStream = File.OpenRead(filePaths[i])) 
{ 
    fileStream.Copy(client.GetRequestStream()); 
} 

var responseString = string.Empty; 
try { responseString = new StreamReader(client.GetResponse().GetResponseStream()).ReadToEnd(); } 
catch (Exception ex) { Debug.WriteLine(ex.Message); } 
if (String.IsNullOrWhiteSpace(responseString)) { continue; } 

PutFileResponse response = null; 
try { response = responseString.FromJson<PutFileResponse>(); } 
catch (Exception ex) { Debug.WriteLine(ex.Message); } 
if (response == null) 
{ 
    try { response = responseString.FromXml<PutFileResponse>(); } 
    catch (Exception ex) { Debug.WriteLine(ex.Message); } 
    if (response == null) 
    { 
     continue; 
    } 
} 

我离开这个作为,是显示回应。根据要求,前50(约)个调用返回JSON。 404之后的所有后续调用总是返回XML。

有什么想法?

编辑(2014年2月25日10:35 EST):

看着提琴手后这是一个比较奇怪的比我想象。在559个请求中,其中34个导致404错误。但是,该服务在错误发生前后都会继续响应。 404错误是第一个令人费解的部分。第二项(XML和JSON之间的切换有点不那么令人费解,但奇怪无害)

该应用程序是一个文件存储应用程序,正在递归测试目录以将文件推送到服务。是实际的XML文件,所有的文件都是在一个Stream中发送的,嵌套在一个DTO中,客户端为每个请求添加一个“application/json”的Accept头,如果发送了XML文件,即使Accept头已经发送中,服务用XML响应

实施例请求报头(会话94):

POST 
http://localhost:50205/Files/Put/8178F94DBDBC4AB18F42118AFD01D1A2/AA10C004D624DA892171F8A7E8CD8D05/201760/ServiceStack.xml HTTP/1.1 
Content-Type: multipart/form-data; 
Accept: application/json 
Host: localhost:50205 
Transfer-Encoding: chunked 
Expect: 100-continue 

1000 
<?xml version="1.0"?> 
<doc> 
    [SNIP] 
</doc> 

0 

实施例响应Heade R(会话#94):

HTTP/1.1 200 OK 
Cache-Control: private 
Content-Type: application/xml 
Server: Microsoft-IIS/8.0 
X-Powered-By: ServiceStack/4.011 Win32NT/.NET 
Access-Control-Allow-Origin: * 
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS 
Access-Control-Allow-Headers: Content-Type 
X-AspNet-Version: 4.0.30319 
X-SourceFiles: =?UTF-8?B?RDpcX1NvdXJjZVxGSUwwMVx0cnVua1xTcG90bGVzc1xGcmFtZXdvcmtzXEZpbGVNYW5hZ2VtZW50XFByb2plY3RzXEZNRi5TdG9yYWdlU2VydmVyLkhvc3RpbmcuUHVibGljXEZpbGVzXFB1dFw4MTc4Rjk0REJEQkM0QUIxOEY0MjExOEFGRDAxRDFBMlxBQTEwQzAwNEQ2MjREQTg5MjE3MUY4QTdFOENEOEQwNVwyMDE3NjBcU2VydmljZVN0YWNrLnhtbA==?= 
X-Powered-By: ASP.NET 
Date: Tue, 25 Feb 2014 15:19:06 GMT 
Content-Length: 563 

<?xml version="1.0" encoding="utf-8"?><PutFileResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/FMF.StorageServer.Services.Messages.Files"><ResponseStatus xmlns:d2p1="http://schemas.servicestack.net/types" i:nil="true" /><Status><FileSignature><Checksum>AA10C004D624DA892171F8A7E8CD8D05</Checksum><SizeBytes>201760</SizeBytes></FileSignature><IsAvailable i:nil="true" /><IsKnown i:nil="true" /><IsOnDisk i:nil="true" /><IsSuccessful i:nil="true" /><StatusMessage i:nil="true" /></Status></PutFileResponse> 

这不幸的是,我将不得不把它发送到服务器之前,检测每一个文件的内部结构,并可能永远不要相信文件扩展名。无论是或者总是假设服务器可能会决定发回XML,当我没有想到它。

更迫切的问题是,为什么只有一些请求才能检测到404错误。在559个请求中,产生404错误的项目是77,232,235,238,246,275等等......所以服务或客户端只是在随机请求上失败。

编辑(2014年2月25日12:20 EST):

它看起来好像所有的失败(404错误)的文件进行基于文本。例如...

示例请求报头(会话#560):

POST http://localhost:50205/Files/Put/060C976372174F51BEB84FE524E57C57/1931975CE8E1090A6D66738A560888AD/1426/AssemblyInfo.cs HTTP/1.1 
Content-Type: multipart/form-data; 
Accept: application/json 
Host: localhost:50205 
Transfer-Encoding: chunked 
Expect: 100-continue 

592 
using System.Reflection; 
using System.Runtime.CompilerServices; 
using System.Runtime.InteropServices; 

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information 
// associated with an assembly. 
[assembly: AssemblyTitle("Utility")] 
[assembly: AssemblyDescription("")] 
[assembly: AssemblyConfiguration("")] 
[assembly: AssemblyCompany("")] 
[assembly: AssemblyProduct("Utility")] 
[assembly: AssemblyCopyright("Copyright © 2012")] 
[assembly: AssemblyTrademark("")] 
[assembly: AssemblyCulture("")] 

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components. If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type. 
[assembly: ComVisible(false)] 

// The following GUID is for the ID of the typelib if this project is exposed to COM 
[assembly: Guid("1071992e-2d4c-49df-9526-6d4d29f979b4")] 

// Version information for an assembly consists of the following four values: 
// 
//  Major Version 
//  Minor Version 
//  Build Number 
//  Revision 
// 
// You can specify all the values or you can default the Build and Revision Numbers 
// by using the '*' as shown below: 
// [assembly: AssemblyVersion("1.0.*")] 
[assembly: AssemblyVersion("1.0.0.0")] 
[assembly: AssemblyFileVersion("1.0.0.0")] 

0 

实施例响应头(会话#560):

HTTP/1.1 404 Not Found 
Cache-Control: private 
Content-Type: text/html; charset=utf-8 
Server: Microsoft-IIS/8.0 
X-SourceFiles: =?UTF-8?B?RDpcX1NvdXJjZVxGSUwwMVx0cnVua1xTcG90bGVzc1xGcmFtZXdvcmtzXEZpbGVNYW5hZ2VtZW50XFByb2plY3RzXEZNRi5TdG9yYWdlU2VydmVyLkhvc3RpbmcuUHVibGljXEZpbGVzXFB1dFwwNjBDOTc2MzcyMTc0RjUxQkVCODRGRTUyNEU1N0M1N1wxOTMxOTc1Q0U4RTEwOTBBNkQ2NjczOEE1NjA4ODhBRFwxNDI2XEFzc2VtYmx5SW5mby5jcw==?= 
X-Powered-By: ASP.NET 
Date: Tue, 25 Feb 2014 15:24:10 GMT 
Connection: close 
Content-Length: 5106 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<title>IIS 8.0 Detailed Error - 404.7 - Not Found</title> 
<style type="text/css"> 
<!-- 
body{margin:0;font-size:.7em;font-family:Verdana,Arial,Helvetica,sans-serif;} 
code{margin:0;color:#006600;font-size:1.1em;font-weight:bold;} 
.config_source code{font-size:.8em;color:#000000;} 
pre{margin:0;font-size:1.4em;word-wrap:break-word;} 
ul,ol{margin:10px 0 10px 5px;} 
ul.first,ol.first{margin-top:5px;} 
fieldset{padding:0 15px 10px 15px;word-break:break-all;} 
.summary-container fieldset{padding-bottom:5px;margin-top:4px;} 
legend.no-expand-all{padding:2px 15px 4px 10px;margin:0 0 0 -12px;} 
legend{color:#333333;;margin:4px 0 8px -12px;_margin-top:0px; 
font-weight:bold;font-size:1em;} 
a:link,a:visited{color:#007EFF;font-weight:bold;} 
a:hover{text-decoration:none;} 
h1{font-size:2.4em;margin:0;color:#FFF;} 
h2{font-size:1.7em;margin:0;color:#CC0000;} 
h3{font-size:1.4em;margin:10px 0 0 0;color:#CC0000;} 
h4{font-size:1.2em;margin:10px 0 5px 0; 
}#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS",Verdana,sans-serif; 
color:#FFF;background-color:#5C87B2; 
}#content{margin:0 0 0 2%;position:relative;} 
.summary-container,.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;} 
.content-container p{margin:0 0 10px 0; 
}#details-left{width:35%;float:left;margin-right:2%; 
}#details-right{width:63%;float:left;overflow:hidden; 
}#server_version{width:96%;_height:1px;min-height:1px;margin:0 0 5px 0;padding:11px 2% 8px 2%;color:#FFFFFF; 
background-color:#5A7FA5;border-bottom:1px solid #C1CFDD;border-top:1px solid #4A6C8E;font-weight:normal; 
font-size:1em;color:#FFF;text-align:right; 
}#server_version p{margin:5px 0;} 
table{margin:4px 0 4px 0;width:100%;border:none;} 
td,th{vertical-align:top;padding:3px 0;text-align:left;font-weight:normal;border:none;} 
th{width:30%;text-align:right;padding-right:2%;font-weight:bold;} 
thead th{background-color:#ebebeb;width:25%; 
}#details-right th{width:20%;} 
table tr.alt td,table tr.alt th{} 
.highlight-code{color:#CC0000;font-weight:bold;font-style:italic;} 
.clear{clear:both;} 
.preferred{padding:0 5px 2px 5px;font-weight:normal;background:#006633;color:#FFF;font-size:.8em;} 
--> 
</style> 

</head> 
<body> 
<div id="content"> 
<div class="content-container"> 
    <h3>HTTP Error 404.7 - Not Found</h3> 
    <h4>The request filtering module is configured to deny the file extension.</h4> 
</div> 
<div class="content-container"> 
<fieldset><h4>Most likely causes:</h4> 
    <ul> <li>Request filtering is configured for the Web server and the file extension for this request is explicitly denied.</li> </ul> 
</fieldset> 
</div> 
<div class="content-container"> 
<fieldset><h4>Things you can try:</h4> 
    <ul> <li>Verify the configuration/system.webServer/security/requestFiltering/fileExtensions settings in applicationhost.config and web.config.</li> </ul> 
</fieldset> 
</div> 

<div class="content-container"> 
<fieldset><h4>Detailed Error Information:</h4> 
    <div id="details-left"> 
    <table border="0" cellpadding="0" cellspacing="0"> 
    <tr class="alt"><th>Module</th><td>&nbsp;&nbsp;&nbsp;RequestFilteringModule</td></tr> 
    <tr><th>Notification</th><td>&nbsp;&nbsp;&nbsp;BeginRequest</td></tr> 
    <tr class="alt"><th>Handler</th><td>&nbsp;&nbsp;&nbsp;ServiceStack.Factory</td></tr> 
    <tr><th>Error Code</th><td>&nbsp;&nbsp;&nbsp;0x00000000</td></tr> 

    </table> 
    </div> 
    <div id="details-right"> 
    <table border="0" cellpadding="0" cellspacing="0"> 
    <tr class="alt"><th>Requested URL</th><td>&nbsp;&nbsp;&nbsp;http://localhost:50205/Files/Put/060C976372174F51BEB84FE524E57C57/1931975CE8E1090A6D66738A560888AD/1426/AssemblyInfo.cs</td></tr> 
    <tr><th>Physical Path</th><td>&nbsp;&nbsp;&nbsp;D:\_Source\FIL01\trunk\Spotless\Frameworks\FileManagement\Projects\FMF.StorageServer.Hosting.Public\Files\Put\060C976372174F51BEB84FE524E57C57\1931975CE8E1090A6D66738A560888AD\1426\AssemblyInfo.cs</td></tr> 
    <tr class="alt"><th>Logon Method</th><td>&nbsp;&nbsp;&nbsp;Not yet determined</td></tr> 
    <tr><th>Logon User</th><td>&nbsp;&nbsp;&nbsp;Not yet determined</td></tr> 
    <tr class="alt"><th>Request Tracing Directory</th><td>&nbsp;&nbsp;&nbsp;C:\Users\Fred\Documents\IISExpress\TraceLogFiles\FMF.STORAGESERVER.HOSTING.PUBLIC</td></tr> 
    </table> 
    <div class="clear"></div> 
    </div> 
</fieldset> 
</div> 

<div class="content-container"> 
<fieldset><h4>More Information:</h4> 
    This is a security feature. Do not change this feature unless the scope of the change is fully understood. If the file extension for the request should be allowed, remove the denied file extension from configuration/system.webServer/security/requestFiltering/fileExtensions. 
    <p><a href="http://go.microsoft.com/fwlink/?LinkID=62293&amp;IIS70Error=404,7,0x00000000,9200">View more information &raquo;</a></p> 

</fieldset> 
</div> 
</div> 
</body> 
</html> 

编辑(2014年2月25日14:27 EST):

继续测试并发现忽略Accept头的ServiceStack是一个比我希望的更大的问题。由于所有文件都必须持久保存,并且由于这些文件必须同时包含HTML和XML文件,因此我需要确保ServiceStack只发回请求的响应。在我上次测试中发送的一些文件包含HTML文件,很不幸,ServiceStack发回了一个HTML文档作为响应。

临时文件夹包含一堆随机文件。而且,正如您所预料的那样,因为我手头上有大量源文件,临时文件夹中包含一些C#/ VS2K12解决方案。例如,我复制了DoFactory解决方案的源代码,其中一些.Config,.cs,.csproj文件失败,而其他相同类型的文件则通过。

正在使用的DTO ...

//[Route("/Files/Put/{Token}/{Checksum}/{SizeBytesText}/{FileNameOrExtension}", "POST")] 
[Route("/Files/Put/{PathInfo*}", "POST")] 
public class PutFileRequest : IReturn<PutFileResponse>, IRequiresRequestStream 
{ 
    public string Token { get; set; } 
    public string Checksum { get; set; } 
    public string SizeBytesText { get; set; } 
    public string FileNameOrExtension { get; set; } 

    public System.IO.Stream RequestStream { get; set; } 
} 

我故意包括我用的是原来的路线。请注意,URI是使用一组变量和文件的名称构造的。该文件的名称在服务器上用于方便使用原始文件扩展名来保持该文件。

以下是测试应用程序中的主要方法,该方法一致失败。任何尝试发布此文件都将导致404错误。 请注意,该文件完好无损,并且FileSteam能够成功打开并复制文件的内容。如果文件存在问题,则应该失败。

static void Main(string[] args) 
{ 
    var filePath = @"D:\Temp\_Source\DoFactory\CS_4.5\Spark\Art.Web\Areas\Shop\Models\ProductsModel.cs"; 
    var fileInfo = Files.GetInfo(filePath, calculateChecksum: true); 


    var uri = @"http://localhost:50205/Files/Put/" + 
       Guid.NewGuid().ToString("N") + "/" + 
       fileInfo.Checksum + "/" + 
       fileInfo.SizeBytes.Value + "/" + 
       System.IO.Path.GetFileName(filePath); 

    var client = (HttpWebRequest) WebRequest.Create(uri); 
    client.Method = WebRequestMethods.Http.Post; 
    client.AllowWriteStreamBuffering = false;  
    client.SendChunked = true;      
    client.ContentType = "multipart/form-data;";  
    client.Timeout = int.MaxValue;     
    client.Accept = "application/json";    

    using (FileStream fileStream = File.OpenRead(filePath)) 
    { 
     fileStream.CopyTo(client.GetRequestStream()); 
    } 

    var responseString = string.Empty; 
    try { responseString = new StreamReader(client.GetResponse().GetResponseStream()).ReadToEnd(); } 
    catch (Exception ex) { Debug.WriteLine(ex.Message); } 
    if (String.IsNullOrWhiteSpace(responseString)) { Environment.Exit(1); } 

    PutFileResponse response = null; 
    try { response = responseString.FromJson<PutFileResponse>(); } 
    catch (Exception ex) { Debug.WriteLine(ex.Message); } 

    if (response == null) 
    { 
     try { response = responseString.FromXml<PutFileResponse>(); } 
     catch (Exception ex) { Debug.WriteLine(ex.Message); } 
    } 

    if (response == null) 
    { 
     try { response = responseString.FromJsv<PutFileResponse>(); } 
     catch (Exception ex) { Debug.WriteLine(ex.Message); } 
    } 

    if (response == null) { Environment.Exit(2); } 

    Console.ReadLine(); 
} 
+0

您是否也可以提供原始HTTP请求和HTTP响应,因为它从JSON更改为XML? – mythz

回答

4

一天的测试+,以及地方约1000的测试后,我已经找到解决问题的方法。但是,在调查结果中,我向ServiceStack团队发出了一个请求,以寻找解决方法。

如果文件发布到最终包含文件名的路径,ServiceStack将响应一个匹配RequestStream中包含的项目内容的结果。如果该项目是HTML,则该响应将是HTML响应。如果该项目是XML,则响应将是XML响应。在这些情况下,Accept头始终被忽略。

要解决这个问题,我已经把文件名分成了URL中的不同部分。将原本作为解决路径:

http://localhost:1234/Files/Put/ABC123/MyFile.xml

...现在发布,因为这...

http://localhost:1234/Files/Put/ABC123/F/MyFile/X/xml

...或者,如果我只是需要扩展,延伸的部分被破坏...

http://localhost:1234/Files/Put/ABC123/X/tar/gz

在这些示例中,服务知道如何重新组合文件名和/或扩展名。

此更改的最终结果是XML和HTML文件按预期发布,并且ServiceStack服从Accept标头。在此更改之后的所有测试中,ServiceStack都以所需的JSON对象进行响应。此外,没有遇到404错误。

+0

Fred,你能否接受你的回答,所以这个问题不会在[ServiceStack]标签中打开。谢谢 :) – Scott