具有值“0000-00-00”的DateTime对象的SOAP反序列化失败

时间:2013-06-03 09:18:26

标签: c# wcf datetime soap

我有一个简单的应用程序,通过SOAP获取数据记录。 SOAP Web服务通过“服务引用”添加到项目中。通话工作正常。当数据为参考代码存储到0000-00-00 - 对象的日期保存值DateTime时,我遇到了问题。 DateTime类已经预见到0001-0-01的最小值,这最终会在反序列化SOAP调用的响应时导致错误。

执行以通过SOAP提取数据的代码如下:

TopixSOAP.TOPIXRPCClient soap = new TopixSOAP.TOPIXRPCClient();
soap.GetProjekt(out error_code, out start_date, out end_date, instance, user, passwd, project_number);

所以我向SOAP调用提供了必要的信息,如果start_date和end_date是=>它会表现良好。 0001-01-01。但由于数据有时包含0000-00-00日期的值,因此应用程序在将值反序列化为DateTime对象时会自然崩溃。

我试图将所有out参数包装到一个名为TopixProject的单独类中:

public class TOPIXProject
{

    public TOPIXProject()
    {
    }
    public string ErrorCode
    {
        get
        {
            return ErrorCode;
        }
        set
        {
            ErrorCode = value;
        }
    }

    public DateTime StartDate
    {
        get
        {
            return StartDate; 
        }
        set
        {
            StartDate = DateTime.MinValue;
        }
    }

    public DateTime EndDate
    {
        get
        {
            return EndDate;
        }
        set
        {
            EndDate = DateTime.MinValue;
        }
    }

这里是修改过的电话:

soap.SOAP_GetProject(out p.ErrorCode, out p.StartDate, out p.EndDate, instance, user, passwd, project_number);

该类应将值设置为DateTime.MinValue,以便我不再收到错误。它不能按我的意图工作:类TOPIXProject的成员不能用作函数的out或ref参数。

如果我提供我在SOAP调用之前声明的“原始”变量,那么如果日期在0001-01-01类定义的有效范围(=&gt; DateTime)中,它就会起作用:< / p>

string error_code = "";
DateTime start_date, end_date;
soap.GetProjekt(out error_code, out start_date, out end_date, instance, user, passwd, project_number);

但我有很多数据记录,其中日期为0000-00-00并且无法更改(它是无法终止项目的内部标记)。 那么我需要做些什么来获得有效的SOAP响应呢?

  • 主要是如果数据集的日期为0000-00-00我想获得DateTime.MinValue
  • 或者我可以告诉服务引用将所有内容解释为字符串吗? (因为服务引用构建代码本身并尝试将xsd:date类型解析为DateTime,这在我的情况下非常糟糕)

修改

我现在使用来自服务引用的部分SOAP调用(基本上所有没有传递日期的地方)。其余的我实现了一个SOAPHelper类,它提供对SOAP端点的必要调用,并主要返回字符串或XML。代码示例here

2 个答案:

答案 0 :(得分:1)

您最好的选择是手动生成客户端(或使用Svcutil工具) 并修改合同以接收消息,而不是datetime。这样您就可以与消息本身进行交互并处理无效的日期时间值。关于在msdn上使用here更多关于Using Message Contracts的功能有一篇很好的帖子。

答案 1 :(得分:0)

我们想出了一个不同的解决方案:由于Web服务并不是在考虑XML中的xsi:type属性,我们认为它是代理流量和操纵WSDL文件以及进出XML消息的最简单方法。

因此我们编写了一个通过$ _GET变量控制的PHP脚本:

  • 返回WSDL文件(操作)
  • 过滤xml内容并替换某些字符串,因此我们将所有xsi:date节点作为xsi:string nodes

这不是最干净的方式,而是规避问题的唯一方法。

<?php
/** A simple HTTP/SOAP proxy server with response manipulation
*
*  @author: Dipl.-Ing. (FH) Tom Gottschalk, tom.gottschalk@gmail.com
*
*  Usage:
*  1.  proxy.php?wsdl:
*      - gets the original WSDL file content from the SOAP server
*      - manipulates the types `date` and `time` to `string`
*      - manipulates the SOAP service URI binding to `proxy.php?proxy`
*  2.  proxy.php?proxy
*      - forwards the original HTTP request to the SOAP server
*      - fetches the HTTP response
*      - manipulates the types `date` and `time` to `string` in the HTTP response
*      - returns the manipulated SOAP (HTTP) response
*/

// suppress deprecated and strict standard messages
error_reporting(E_ALL & ~E_STRICT & ~E_NOTICE & ~E_DEPRECATED);

// what to do: serve WSDL or work as Proxy server
if(array_key_exists("proxy", $_GET)) {
proxy();
}
elseif(array_key_exists("wsdl", $_GET))
{
wsdl();
}

// manipulate data types in the XML WSDL or SOAP response
function manipulate($xml)
{
$xml = str_replace('type="xsd:date"', 'type="xsd:string"', $xml);
$xml = str_replace('type="xsd:time"', 'type="xsd:string"', $xml);
return $xml;
}

function proxy()
{
// fetch all HTTP request headers from the current request
$headers = apache_request_headers();
// get all raw POST data
$rawPostData = file_get_contents("php://input"); # alternatively:       $HTTP_RAW_POST_DATA

// URI to request
$uri = "http://<server:port>/INCOMING_PORT/";

// do request and get response
$request = new HttpRequest($uri, HttpRequest::METH_POST);
$request->addHeaders($headers);
$request->setRawPostData($rawPostData);
$response = $request->send();

// send headers
foreach($response->getHeaders() as $key => $value) {
    header(sprintf("%s: %s", $key, $value));
}

// edit response body
$body = $response->getBody();
$body = manipulate($body);

// return response
echo $body;
}

function wsdl()
{
// get original WSDL file
$uri = "http://<server:port>/WSDL/";
$wsdl = file_get_contents($uri);
// manipulate data types
$wsdl = manipulate($wsdl);
// manipulate SOAP service URI binding
$wsdl = str_replace('http://<server:port>/INCOMING_PORT/', 'http://url_to_php_proxy_script/proxy.php?proxy', $wsdl);
// return result
header("Content-Type: text/xml");
echo $wsdl;
}
?>

TL,DR:我们使用了代理的WSDL,因为服务器没有注意到xsi:type。