views:

654

answers:

3

We are trying to talk to a (possible)Java WebService from .NET 3.5 using WCF. The WebService defines a Timestamp object which seems to be a datetime without the decimal milliseconds.

WCF decided .NET would use a datatime as the object backing in the proxy class. When sending objects with the timestamp to the Java WebServer the datetime is serialized and includes the miliseconds. This results in a Fault.

How do we a) Cause .NET to select a custom class we implement (So we can format the message) or b) Cause WCF to generate the datetime based on the XSD files included with the WSDL?

Issue Definition: Timestamp needs to look like: 2010-01-01T01:01:01-07:00

Yet .NET generates a timestamp with decimal seconds like: 2010-01-01T01:01:01.1234-07:00

A: 

Can you modify the code to pass it as a string and format it in the .ToString() method as shown in the following snippet?

SomeTime.ToString("yyyy-MM-ddThh:mm:ss")
David Stratton
Actually, to get the timezone offset at the end, you need to do SomeTime.ToString("yyyy-MM-ddTHH:mm:ssZ"));
Tangurena
A: 

By "WCF decided .NET would use a datetime", I get the feeling you used visual studio to add a reference to the web service.

Instead I'd recommend using SvcUtil to generate a proxy, then add that to your project. This way you can edit the proxy directly and make it behave how you need (for example, serializing a string rather than a datetime, or formatting it differently).

Any time the service contract changes, you need to create a new proxy and merge your changes in, but this is normally a small price to pay for the additional control.

Philip Rieck
Yes you are correct. We used Visual Studio to add the service reference. We did modify the generated code to return a string, but wanted to avoid changing the proxy everytime the web service was updated. We don't have any control over the Web Service and also have many developers. Forcing us to update the code each time would not be the ideal solution, but definately is not our first choice.Is it posible to get the SvcUtil to choose a custom class for timestamp instead of the base class datetime?
Coach David
@unknown - I think you're missing the point on this one. The point of generating your own proxy is so that YOU can modify the proxy, rather than having the SvcUtil modify it for you.
David Stratton
Thanks for the answer. We will need to update the service reference more than a littlebit, so I was hoping (really hoping) for a way to force the proxy generator to create the proxy correctly the first time. We are currently using the method you specified as a work around.
Coach David
@Coach David - I don't believe you can. This is one of the reasons a constantly changing service contract sucks!
Philip Rieck
-1: You should never modify generated code. Also svcutil produces the same code as "Add Service Reference".
John Saunders
@John Saunders - I completely disagree. I believe you should almost never "Add Service Reference". My actual recommendation is to create your own proxy rather than do either, but using svcutil gives you a good starting point. After that, it's manual changes. Perhaps you mean "you should never modify code that is consistently regenerated"? In that case, I agree.
Philip Rieck
A: 

I figured out a few ways to handle this problem. The more complicated methods involve hooking of a custom MessageFormatter Endpoint.

We found a simple way to to this.

the Fraction of seconds are only generated if the datetime object has them.

What we did:

We created a static on propertychange event handler that uses reflection to detect datetime datatypes. When found we recreate the datetime without the fractions of seconds. In our case we didn't care about seconds at all. We wire the event up in a partial class constructor. Thats it.

Of course

public static class DateTimeSecondCatcher
{
    PropertyInfo dateTimePropertyInfo = sender.GetType().GetProperty(e.PropertyName);
        if ((dateTimePropertyInfo != null) && (dateTimePropertyInfo.PropertyType == typeof(DateTime)))
        {

            DateTime dteValue = (DateTime)dateTimePropertyInfo.GetValue(sender, null);
            if (dteValue.Millisecond > 0)
            {
                dateTimePropertyInfo.SetValue(sender, new DateTime(dteValue.Year,dteValue.Month,dteValue.Day, dteValue.Hour,dteValue.Minute,dteValue.Second,0,dteValue.Kind), null);
            }
        }

}


// This code goes in the partial class constructor
this.PropertyChanged += new PropertyChangedEventHandler(DateTimeSecondCatcher.OnPropertyChanged);
Coach David