Silverlight 2 Beta2 + WCF = 404 Error ?

大致情形是这样的:

  • Silverlight 2 beta2 (目前最新的支持 VS2008 中文版的开发包)
  • WCF (采用 SL2b2 安装后新增的那个模板创建的)
  • LINQ to SQL (对应 SQL 服务器中的四个表)

使用 DataGrid 控件来显示和编辑 SQL 中的 Component 表, 强大的LINQ帮我创建了一个对应的 Component 类, 查询和显示的过程很顺利.

可是到了更新数据这一步, 却碰上了莫名其妙的 404 错误… 少量可以, 大量数据就会出错.

The remote server returned an unexpected response: (404) Not Found.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[OperationContract]
public List<Component> QueryComponentList(Guid TowerID)
{

using (var db = new LINQDataContext())
{
var linq =
from l in db.Component
where l.TowerID.Equals(TowerID)
orderby l.Section, l.Number
select l;
return linq.ToList();
}
}

[OperationContract]
public void UpdateComponentList(Guid tid, List<Component> source)
{

using (var db = new LINQDataContext())
{
...
}
}

在官方论坛上我看到了N种解释, 总结如下:

跨域安全问题, 也就是传说中的 crossdomain.xml 和 clientaccesspolicy.xml 两个文件. 试试, 虽然我知道不会奏效的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- crossdomain.xml -->
<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
<!-- clientaccesspolicy.xml -->
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>

Silverlight 项目中的 ServiceReferences.ClientConfig 文件, 增大 maxBufferSize 和 maxReceivedMessageSize. 我加到了 2147483647, 也就是 2G, 结果不行.

1
<binding name="BasicHttpBinding_WCF" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"/>

网站中的 web.config 文件, 增大若干个 max 开头的属性. 我估计有几项是客户端根本无法识别的 设置了也没用…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_WCF" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxArrayLength="2147483647" maxDepth="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647"/>
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="WCFBehavior" name="WCF">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_WCF" contract="WCF" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>

在 web.config 文件中的 system.web/httpRuntime 节点下, 设置 POST 允许的最大长度, 以kb为单位, 那就是 int.MaxValue/1024=2097151. 早就知道问题不在这…

1
<httpRuntime maxRequestLength="2097151"/>

web.config 中关于 WCF 还有个秘密, 那就是 system.serviceModel/behaviors/serviceBehaviors/behavior/dataContractSerializer. 天啊, 连这个都有人挖出来啦! 兴奋了几秒钟, 发现还是没搞定!

1
2
3
4
5
6
7
8
9
<behaviors>
<serviceBehaviors>
<behavior name="WCFBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<dataContractSerializer maxItemsInObjectGraph="2147483647" ignoreExtensionDataObject="true" />
</behavior>
</serviceBehaviors>
</behaviors>

仔细回忆到底是哪里出了问题, 我发现当数据少于 176 行时是没有问题的, 只要一超过这个数量, 就会弹出异常, 而且感觉上是在异步传递数据之后立即发生的, 比能够上传成功的 176 行数据响应的还快许多, 更奇怪的是虽然 VS2008 跳出异常, 接收到了 404 错误, 但此时任务管理器的 WebDev.WebServer.EXE 和 sqlserver.exe 都正忙着, 查看 SQL 发现数据也是成功写入了…

那这 404 是哪里来的鬼东西? 无意中直接打开 IE 不经过调试, 结果我也没接收到 404 错误, 真的无奈了, 最后决定死马当活马医. 把上传数据那个函数从 void 类型改成 bool 类型, 让它具备一个布尔型的返回结果, 以确认上传是否成功(之前一直感觉这是多余的).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[OperationContract]
public bool UpdateComponentList(Guid tid, List<Component> source)
{

try
{
using (var db = new LINQDataContext())
{
...
}
return true;
}
catch (Exception)
{
return false;
}
}

古怪的问题就这样华丽的消失了… 别问我为什么, 我也不知道!