views:

1153

answers:

5

Every object I return from a WebMethod of a ScriptService, is wrapped into a d JSON object. That's ok. But I don't want the additional __type property to be served to the client, since I do manual processing with jQuery.

Is it possible?

+5  A: 

Well its been a long time since yoy asked. I found that if i make the default constructor of my class that my webmethod returns anything other than public it will not serialize the __type:ClassName portion.

You may want to declare your default constructor protected internal ClassName(){}

I'm not getting this result, though I'm returning an array of objects. Not sure if this is the issue.
Laramie
+1  A: 

Do not use the [Serializable] attribute.

The following should just do it

JavaScriptSerializer ser = new JavaScriptSerializer(); string json = ser.Serialize(objectClass);

seanlinmt
A: 

dear Greg

I not sure this a good solution , but if you use the Json.net library, you can ignore some properties by adding [JsonIgnore] attribute.

-mironline

Mironline
A: 

This should solve it.

In the private SerializeValue method of JavaScriptSerializer in System.WebExtensions.dll, the __type is added to an internal dictionary if it can be resolved.

From Reflector:

private void SerializeValue(object o, StringBuilder sb, int depth, Hashtable objectsInUse)
{
    if (++depth > this._recursionLimit)
    {
        throw new ArgumentException(AtlasWeb.JSON_DepthLimitExceeded);
    }
    JavaScriptConverter converter = null;
    if ((o != null) && this.ConverterExistsForType(o.GetType(), out converter))
    {
        IDictionary<string, object> dictionary = converter.Serialize(o, this);
        if (this.TypeResolver != null)
        {
            string str = this.TypeResolver.ResolveTypeId(o.GetType());
            if (str != null)
            {
                dictionary["__type"] = str;
            }
        }
        sb.Append(this.Serialize(dictionary));
    }
    else
    {
        this.SerializeValueInternal(o, sb, depth, objectsInUse);
    }
}

If the type can't be determined, serialization will still proceed, but the type will be ignored. The good news is that since anonymous types inherit getType() and the names returned are dynamically generated by the compiler, the TypeResolver returns null for ResolveTypeId and the "__type" attribute is subsequently ignored.

I also took John Morrison's advice with the internal constructor just in case, though using just this method, I was still getting __type properties in my JSON response.

//Given the following class
[XmlType("T")]
public class Foo
{
    internal Foo()
    {

    }

    [XmlAttribute("p")]
    public uint Bar
    {
        get;
        set;
    }
}

[WebService(Namespace = "http://me.com/10/8")]
[System.ComponentModel.ToolboxItem(false)]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class MyService : System.Web.Services.WebService
{

    //Return Anonymous Type to omit the __type property from JSON serialization
    [WebMethod(EnableSession = true)]
    [System.Web.Script.Services.ScriptMethod(UseHttpGet = false, ResponseFormat = ResponseFormat.Json, XmlSerializeString = false)]
    public object GetFoo(int pageId)
    {
        //Kludge, returning an anonymois type using link, prevents returning the _type attribute.
        List<Foo> foos = new List<Foo>();
        rtnFoos.Add( new Foo(){
            Bar=99
        }};

        var rtn = from g in foos.AsEnumerable()
                   select g;

        return rtn;
    }
}

Note: I'm using an inherited JSON type converter that reads the XML Serialization attributes from serialized types to further compress the JSON. With thanks to CodeJournal. Works like a charm.

Laramie
A: 

I've been doing a lot of jQuery/ASP.NET web methods recently but have only seen this for the first time today.

I don't appear to be allowed to comment on John Morrison's post presumably because I'm a newbie; anyway, John's solution didn't work for me as the type I'm returning is in a seperate DLL. I have full control over that DLL but I can't construct my return type if the constructor is internal (of course).

I was wondering if the return type being a public type in a library might even be the cause; as I say I've been doing a lot of Ajax and not seen this one before. Quick tests:

  • Temporarily moved the return type declaration into App_Code. Still get __type serialised.

  • Ditto and applied the protected internal constructor per JM. This worked (so he gets a vote).

The solution for me, however, was to leave my return type in the DLL but set the WebMethod return type to object, i.e.

[WebMethod]
public static object ApplyCredits(int addonid, int[] vehicleIds) 

instead of

[WebMethod]
public static WebMethodReturn ApplyCredits(int addonid, int[] vehicleIds)

Strangely I don't get __type with a generic return type:

[WebMethod]
public static WebMethodReturn<IEnumerable<FleetObserverLiteAddOns.VehicleAddOnAccountStatus>> GetAccountCredits()

If anyone can shed any light on this it would be appreciated. Not even sure it's by design tbh.

Stephen Kennedy