Silverlight 2 beta2 + WCF = 404 error ?

标签 Silverlight WCF

大致情形是这样的:

  • 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.

#!csharp
[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 两个文件. 试试, 虽然我知道不会奏效的.

#!xml
<!-- 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, 结果不行.

#!xml
<binding name="BasicHttpBinding_WCF" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"/>

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

#!xml
<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. 早就知道问题不在这…

#!xml
<httpRuntime maxRequestLength="2097151"/>

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

#!xml
<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 类型, 让它具备一个布尔型的返回结果, 以确认上传是否成功(之前一直感觉这是多余的).

#!csharp
[OperationContract]
public bool UpdateComponentList(Guid tid, List<Component> source)
{
    try
    {
        using (var db = new LINQDataContext())
        {
            ...
        }
        return true;
    }
    catch (Exception)
    {
        return false;
    }
}

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