views:

201

answers:

4

I have a set of web service methods returning a ActionResult class holding the following properties:

object returnValue
bool success
string message

the returnValue is used to hold different types of return values depending on the web methods used.

The problem I have on the client is that if a web method is returning an internal class in the returnValue I can't cast it due to the client don't recognize the type.

I can fejk methods to be able to expose the class "Issue" I need.

Ex:

Issue ExposeIssueType()
{
    return null;
}

But isn't there any other way?

A: 

Create your type in a shared DLL (mark it as Serializable), reference both sides of the wire.

Mitch Wheat
I wonder if he really meant "internal"?
John Saunders
That would only work with WCF, and doesn't exactly encourage SOA.
Marc Gravell
@Marc: true, but poster said WCF service. I had (possibly incorrectly) assumed that this was internal rather than publicly consumable.
Mitch Wheat
+1  A: 

While I'm waiting for your answer to my comment, I'll tell you that this is a very bad web service design. Each web service operation should return the data it is meant to return. There is no point in creating a class that can hold all possible return values.

Additionally, you should not be using a string message to return errors from a web service. The SOAP protocol has a "SOAP Fault" mechanism for that purpose.

Since you're using WCF, you have complete support for SOAP Faults. Example:

In the service contract:

[FaultContract(typeof(GeneralFault))]
[OperationContract]
int Divide(int a, int b);

In the service:

public int Divide(int a, int b)
{
    if (b == 0)
    {
        throw new FaultException<GeneralFault>(
            new GeneralFault {Message = "Attempt to divide by zero"});
    }

    return a / b; // Note - operation can focus on its job
}

Data contract for the data returned in the fault:

[DataContract]
public class GeneralFault
{
    [DataMember]
    public string Message {get;set;}
}
John Saunders
Not all clients support SOAP faults. Namely Flash.
Sklivvz
Then don't use Flash. SOAP is a standard, and faults are a part of that standard. The standard is from 1998. What possible excuse could Flash have for not supporting faults?
John Saunders
The reason for the ActionResult class thas to have the possibility to return different error messages depending on what went wrong in the web service method.Is it possible if the method is returning only the data type we expect if the methods execute ok?
Again, that's what SOAP Faults are for. The idea is that the web method can return the correct type if all goes well. If there's a problem, then a fault is returned instead of the "normal" data.
John Saunders
Your solution is to at the server side throw a Soap exception holding the fault?
I will try this, I get back with the result. Thank so far =)
It works great. =)I only had to add fault reason to -> new FaultException<GeneralFault>(new GeneralFault {Message = "Attempt to divide by zero"}, new FaultReason("<text>"));Else the client did not recived the Message.One other question: Is this backward compatible to older .NET versions? I know that I have one client running .Net 2.0 can it use this functionality?
Yes, though it's not as pretty. ASMX only just barely supported faults. The client will see the fault as a `SoapException`. The `Detail` property of the exception will be an `XmlElement` containing the serialized `GeneralFault`.
John Saunders
A: 

Having an object value is never a good idea on a web-service; when you have only xml (or similar), how can it stand a chance?

There are some sneaky tricks you might try with multiple subclasses; not sure if this is a good idea, though.

Marc Gravell
A: 

You cannot use object in a webmethod signature because it is not simply serializable like you think. What you can do is use a generic type:

public class ActionResult<T>
{
  public T returnValue
  public bool success
  public string message
}

and then your webmethods should return ActionResult<Issue>


To address the concern to the comments and the (unjustified!) -1, run and invoke.

 [WebMethod]
 public object example()
 {
  return new foo
      {
       bar = "bar",
       baz = "baz"
      };
 }

 public class foo
 {
  public string bar { get; set; }
  public string baz { get; set; }
 }

result:

System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type Test+foo was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.

In other words, you have to specify all the non-primitive types that can be returned -- which pretty much goes against what you are trying to achieve.

I have changed my original assertion about serializability.

Sklivvz
Not all web-service implementations support generics (except perhaps for generic lists etc)
Marc Gravell
This is not true. You can return `object`. -1.
John Saunders
He's edited to say he's using WCF.
John Saunders
Does it make any difference? SOAP is SOAP!?
Sklivvz
Yes, but your example is ASMX.
John Saunders