Search code examples
c#serializationajaxcontroltoolkitjavascriptserializer

Serialize and Deserialize AjaxFileUploadEventArgs - No parameterless constructor defined'


I'm changing a webform website to use StateServer and now I'm trying to find a way to serialize and deserialize AjaxFileUploadEventArgs, my code so far:

In the html I have:

<ajaxToolkit:AjaxFileUpload
ID="AAA"
runat="server"
OnUploadComplete="OnUploadComplete"
ViewStateMode="Enabled" />

Server:

protected void OnUploadComplete(object sender, AjaxFileUploadEventArgs file)
        {
            UpdateListInSession(file);
        }

public static void UpdateListInSession(AjaxFileUploadEventArgs file)
{
  var serializer = new JavaScriptSerializer();
  var fileSerialized = serializer.Serialize(file);
}

public static AjaxFileUploadEventArgs GetLeadsListFromSession()
{
    var serializer = new JavaScriptSerializer();
    AjaxFileUploadEventArgs file = null;

    AjaxFileUploadEventArgs deserializeFile = 
         serializer.Deserialize<AjaxFileUploadEventArgs>(
            HttpContext.Current.Session[k_file] as string);

  return deserializeFile;
}

The error:

System.MissingMethodException: 'No parameterless constructor defined for type of 'AjaxControlToolkit.AjaxFileUploadEventArgs'.'


Solution

  • Assuming you are using AjaxFileUploadEventArgs.cs from , the exception message is self-explanatory. The serializer you are using, JavaScriptSerializer, can only construct and deserialize a type with a parameterless constructor, but as shown in its reference source, AjaxFileUploadEventArgs only has a single constructor, which is parameterized:

    public AjaxFileUploadEventArgs(string fileId, AjaxFileUploadState state, string statusMessage, string fileName, int fileSize, string contentType) {
            // Initialize fields
    }
    

    So, what are your options to deserialize this type? Firstly, you could switch to which supports parameterized constructors out of the box. Once Json.NET is installed, if you do:

    var deserializeFile = 
        Newtonsoft.Json.JsonConvert.DeserializeObject<AjaxFileUploadEventArgs>(jsonString);
    

    Then it simply works. Sample fiddle. Note that Microsoft's own documentation for JavaScriptSerializer states:

    Json.NET should be used serialization and deserialization.

    So this is likely the best solution.

    If you cannot use Json.NET for whatever reason, you will need to write a custom JavaScriptConverter for AjaxFileUploadEventArgs such as the following:

    public class AjaxFileUploadEventArgsConverter : JavaScriptConverter
    {
        public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
        {
            var args = new AjaxFileUploadEventArgs
            (
                serializer.ConvertItemToTypeOrDefault<string>(dictionary, "FileId"),
                serializer.ConvertItemToTypeOrDefault<AjaxFileUploadState>(dictionary, "State"),
                serializer.ConvertItemToTypeOrDefault<string>(dictionary, "StatusMessage"),
                serializer.ConvertItemToTypeOrDefault<string>(dictionary, "FileName"),
                serializer.ConvertItemToTypeOrDefault<int>(dictionary, "FileSize"), 
                serializer.ConvertItemToTypeOrDefault<string>(dictionary, "ContentType")
            ) 
            { PostedUrl = serializer.ConvertItemToTypeOrDefault<string>(dictionary, "PostedUrl") };
            return args;
        }
    
        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            throw new NotImplementedException();
        }
    
        public override IEnumerable<Type> SupportedTypes
        {
            get { return new[] { typeof(AjaxFileUploadEventArgs) }; }
        }
    }
    
    public static class JavaScriptSerializerExtensions
    {
        public static T ConvertItemToTypeOrDefault<T>(this JavaScriptSerializer serializer, IDictionary<string, object> dictionary, string key)
        {
            object value;
    
            if (!dictionary.TryGetValue(key, out value))
                return default(T);
    
            return serializer.ConvertToType<T>(value);
        }
    }
    

    Then deserialize as follows:

    var serializer = new JavaScriptSerializer();
    serializer.RegisterConverters(new JavaScriptConverter[] { new AjaxFileUploadEventArgsConverter() });
    var deserializeFile = serializer.Deserialize<AjaxFileUploadEventArgs>(jsonString);