2017-11-08 18 views
0

내가 .NET과 SignalR 2.2.2 (최신 버전)를 사용하고 4.5.2SignalR은 사용자 정의 직렬화 반대하지 않습니다

이 오류했습니다 :

Could not create an instance of type DF.ApplicationBlocks.IPropertyValueData. Type is an interface or abstract class and cannot be instantiated. Path 'Properties[0].Id', line 1, position 881.

문제는 다음과 같습니다

사용자 정의 객체를 보내는 SignalR 클라이언트 (Signal.Client 패키지를 사용하여 .NET으로 작성)가 있습니다.이 객체에는 인터페이스 (IPropertyValueData)로 형식화 된 객체 배열이 있습니다. 배열의 값은이 인터페이스의 구현입니다. signalR 클라이언트에서

는, 나는 TypeNameHandling.Auto 사용하도록 구성했습니다

 this._connection.JsonSerializer.TypeNameHandling = TypeNameHandling.Auto; 
     this._connection.JsonSerializer.PreserveReferencesHandling = PreserveReferencesHandling.Objects; 
     this._connection.JsonSerializer.ReferenceLoopHandling = ReferenceLoopHandling.Serialize; 

을하고 그것을 올바르게, 등 여기에 클라이언트가 보낸 무슨의 추출물 않습니다

"Properties":[ 
    { 
     "$id":"20", 
     "$type":"DF.MailFlow.Services.Contract.Data.MailDataProperty, DF.MailFlow.Services.Contract", 
     "Id":"5588ce9e-30fb-45b1-afbe-1e6ad0c3e8d4", 

$ type 속성이 정의되어 있고 값이 정확합니다. 그러나 어쨌든, 메시지가 수신되면 서버는 여전히 오류를 트리거합니다.

나는 여기, TypeNameHandling.Auto를 사용하도록 서버를 구성 허브 (I은 IOC의 같은 성 윈저를 사용)를 구성하는 방법입니다했습니다

 var resolver = new WindsorDependencyResolver(WebAPILoader.Container); 

     var hubConfig = new HubConfiguration() 
     { 
      EnableJSONP = true, 
      EnableDetailedErrors = true, 
      EnableJavaScriptProxies = true, 
      Resolver = resolver 
     }; 


     GlobalHost.DependencyResolver = resolver; 

     // Configure signalR and run it 
     app.UseCors(CorsOptions.AllowAll); 
     app.Map("/live", map => 
     { 
      map.UseCors(CorsOptions.AllowAll); 
      map.RunSignalR(hubConfig); 
     }); 

     var serializerSettings = new JsonSerializerSettings 
     { 
      TypeNameHandling = TypeNameHandling.Auto, 
      PreserveReferencesHandling = PreserveReferencesHandling.Objects, 
      ReferenceLoopHandling = ReferenceLoopHandling.Serialize 
     }; 
     GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = serializerSettings; 
     GlobalConfiguration.Configuration.Formatters.JsonFormatter.UseDataContractJsonSerializer = false; 

     // Register in Castle.Windsor container 
     WebAPILoader.Container.Register(Castle.MicroKernel.Registration.Component 
           .For<JsonSerializer>() 
           .UsingFactoryMethod(() => JsonSerializer.Create(serializerSettings))); 

내가 확인 한 첫번째 메시지는 때 받은 팩토리 메서드가 호출되고 설정에 여전히 올바른 TypeNameHandling.Auto가 있습니다. 메시지가 수신 될 때

GlobalHost.DependencyResolver.Register(typeof(JsonSerializer),() => JsonSerializer.Create(serializerSettings)); 

하지만 방법은, 서버가 항상 동일한 오류를 트리거 :

나는 또한 시리얼이 방법을 등록하는 테스트.

복잡도가 추가됨에 따라 애플리케이션은 signalr과 webapi 구성 요소를 서로 다른 URL에서 실행합니다. webapi가 JsonSerializer를 등록하지 않았으며 Windsor 컨테이너가 두 구성 요소 모두에 대해 동일한 지 확인했습니다.

아이디어가 있으십니까?

편집 # 1 : 난 그냥이 티켓에서 실행

https://github.com/SignalR/SignalR/issues/3304
은 누군가가 PR을했다하더라도, (https://github.com/SignalR/SignalR/pull/3343)를 버그가 3 년 이상에 대한 수정없이이 나열되어 있는지 단지 놀라운 보인다
그래서 지금은 해결 방법을 찾기 위해 노력하고있어 ...

답변

0

이 문제는 해결 방법이 012,398에 게시 SignalR

의 버그로 명확 때문이다개 작품, 즉 사용자 지정 해결을 등록 :

private class Resolver : DefaultParameterResolver 
{ 
    private readonly JsonSerializer _serializer; 

    public Resolver(JsonSerializer serializer) 
    { 
     _serializer = serializer; 
    } 

    private FieldInfo _valueField; 
    public override object ResolveParameter(ParameterDescriptor descriptor, Microsoft.AspNet.SignalR.Json.IJsonValue value) 
    { 
     if (value.GetType() == descriptor.ParameterType) 
     { 
      return value; 
     } 

     if (_valueField == null) 
      _valueField = value.GetType().GetField("_value", BindingFlags.Instance | BindingFlags.NonPublic); 

     var json = (string)_valueField.GetValue(value); 
     using (var reader = new StringReader(json)) 
      return _serializer.Deserialize(reader, descriptor.ParameterType); 
    } 
} 

이 버그를 해결하는 방법에 대한 논의는 당신이 찾을 수 있도록이 (희망)

를 해결할 수 있습니다 때, this ticket에 지금