Вызов концентратора SignalR не работает при возврате объекта Castle DynamicProxy без конструктора по умолчанию

У меня возникают проблемы с вызовом концентратора сигналов, когда возвращаемый объект является Castle DynamicProxy.

Допустим, у меня есть следующий код сервера на концентраторе сигналов (это не настоящий код, а просто для демонстрации проблемы):

public Article Read()
{
    var article = new Article(0);
    return article;
}
public class Article
{
    public Article(int id)
    {
        Id = id;
    }

    public int Id { get; set; }
}

Вышеупомянутый метод правильно возвращает мой объект. Если я изменю этот код на:

public Article Read()
{
    var proxyGenerator = new Castle.DynamicProxy.ProxyGenerator();
    var entity = proxyGenerator.CreateClassProxy(typeof(Article), new object[]{0}, new TestInterceptor()) as Article; ;
    return entity;
}
class TestInterceptor : Castle.DynamicProxy.IInterceptor
{
    public void Intercept(Castle.DynamicProxy.IInvocation invocation)
    {
    }
}

Объект никогда не возвращается. Клиент (javascript) не получает никаких ошибок, и ни функции done, ни fail не выполняются.

Я подозреваю, что это проблема с сериализацией. Если я попытаюсь сериализовать объект с помощью Newtonsoft, я получу следующую ошибку:

System.ArgumentNullException was unhandled by user code
  HResult=-2147467261
  Message=Value cannot be null.
Parameter name: key
  Source=mscorlib
  ParamName=key
  StackTrace:
       at System.Collections.ObjectModel.KeyedCollection`2.Contains(TKey key)
       at Newtonsoft.Json.Serialization.JsonPropertyCollection.AddProperty(JsonProperty property)
       at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateConstructorParameters(ConstructorInfo constructor, JsonPropertyCollection memberProperties)
       at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateObjectContract(Type objectType)
       at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateContract(Type objectType)
       at Newtonsoft.Json.Serialization.DefaultContractResolver.ResolveContract(Type type)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.GetContractSafe(Object value)
       at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
       at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
       at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
       at Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Type type, Formatting formatting, JsonSerializerSettings settings)
       at Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Formatting formatting, JsonSerializerSettings settings)
       at Newtonsoft.Json.JsonConvert.SerializeObject(Object value)
  InnerException: 

Есть идеи? Это проблема сериализации signalr?

РЕДАКТИРОВАТЬ:

Благодаря Андерсу я обнаружил, что проблема возникает только тогда, когда класс, для которого вы создали динамический прокси, не имеет конструктора по умолчанию. Например public Article(int id). Это проблема с сериализацией Json.NET?


person Davide Icardi    schedule 22.09.2013    source источник
comment
SignalR использует JSON.NET, поэтому, если JSON.NET по какой-то причине не может десериализовать объект (исключение выше), он также не будет работать в SignalR.   -  person davidfowl    schedule 23.09.2013
comment
@dfowler Спасибо, Дэвид. Единственное, что странно, это то, что я не получаю никаких ошибок от SignalR. В конце концов можно использовать пользовательскую сериализацию? Или напрямую вернуть json?   -  person Davide Icardi    schedule 23.09.2013
comment
Здесь мы не даем хороших ошибок, потому что пишем ответ кусками. Мы собираемся рассмотреть возможность сообщения об этой ошибке в будущем. Вы, безусловно, можете сериализовать себя и отправлять строки (хотя вы будете выполнять двойную сериализацию). JSON.NET также имеет возможность подключения сериализатора.   -  person davidfowl    schedule 23.09.2013


Ответы (2)


У Json.Net нет проблем с сериализацией динамического прокси, это сработало для меня

class Program
{
    static void Main(string[] args)
    {
        var proxyGenerator = new Castle.DynamicProxy.ProxyGenerator();
        var entity = proxyGenerator.CreateClassProxy(typeof(Article), new object[0], new TestInterceptor()) as Article; ;
        var json = JsonConvert.SerializeObject(entity);
    }
}

public class Article
{
    public int Id { get; set; }
}

class TestInterceptor : Castle.DynamicProxy.IInterceptor
{
    public void Intercept(Castle.DynamicProxy.IInvocation invocation)
    {
    }
}   

Результат был

{"__interceptors":[{}],"Id":0}

Обновить:

Без конструктора без параметров я уже получаю ожидание в замке

Can not instantiate proxy of class: ConsoleApplication1.Article.

Could not find a parameterless constructor.
person Anders    schedule 23.09.2013
comment
Прости, Андерс, ты прав. На самом деле мой производственный код немного отличается. Кажется, это проблема при использовании Dynamic Proxy, когда у класса нет конструктора по умолчанию. По сути, если класс Article имеет только конструктор с параметрами, например public Article(int id), выдается исключение ArgumentNullException. Как вы думаете, это ошибка Json.NET? Учтите, что если я сериализую тот же класс без DynamicProxy, он отлично работает. - person Davide Icardi; 23.09.2013
comment
Вы должны передать аргументы конструктора генератору прокси: proxyGenerator.CreateClassProxy(typeof(Article), new object[]{param1}, new TestInterceptor()) as Article; Таким образом, Castle правильно сгенерирует прокси, но Json.NET выдаст исключение при сериализации. - person Davide Icardi; 23.09.2013
comment
После еще нескольких исследований я нашел проблему. Это небольшая ошибка в Json.NET. Я создал новую проблему на веб-сайте json.net, которая теперь решена. - person Davide Icardi; 03.10.2013

После еще нескольких исследований я нашел проблему. Это небольшая ошибка в Json.NET. Я создал новую проблему на веб-сайте json.net, которая теперь решена.

person Davide Icardi    schedule 03.10.2013