Protobuf-net - 检测到可能的递归(偏移量:2 级)

Protobuf-net - Possible recursion detected (offset: 2 level(s))

我遇到以下异常:

An exception of type 'ProtoBuf.ProtoException' occurred in protobuf-net.dll but was not handled in user code

Additional information: Possible recursion detected (offset: 2 level(s)): DataAccess.Data.Models.Opta.OptaEvent

尝试序列化这些时 类:

[Serializable][ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
    public class RRML
    {
        public int Id { get; set; }

        public int CompId { get; set; }

        public OptaTeam Home { get; set; }
        public OptaTeam Away { get; set; }

        public int PeriodMinute { get; set; }

        public string Status { get; set; }

        public string Venue { get; set; }
        public string Referee { get; set; }

        public Dictionary<string, MatchStatCategory> MatchStats { get; set; }        //we are not currently including stats that are only included when livescoring = 11 ; ie possession + territory

        public List<OptaEvent> Events { get; set; }

        public ChartData ChartData { get; set; }

    }

    [Serializable][ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
    public class OptaTeam
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Score { get; set; }

        [ProtoMember(999)]
        public TeamData Data { get; set; }        
    }

    [Serializable][ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
    public class OptaEvent
    {
        public string Minute { get; set; }      //not always an int, eg 40+3
        public string Second { get; set; }
        public OptaEventType Type { get; set; }        
        public string Period { get; set; }
        public PlayerData Player { get; set; }
        public int TeamId { get; set; }
        public Commentary Commentary { get; set; }

        public double MinuteForOrder {        
            get {
                if(string.IsNullOrWhiteSpace(Minute))
                {
                    return 0;
                }

                string[] components = Minute.Split('+');
                if (components.Count() > 1)
                {
                    return Convert.ToInt32(components[0]) + Convert.ToInt32(components[1]) * 0.01;
                }
                else
                {
                    return Convert.ToInt32(components[0]);
                }
            }
        }
    }

    [Serializable][ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
    public enum OptaEventType
    {
        FirstHalfStart,
        FirstHalfEnd, 
        SecondHalfStart, 
        SecondHalfEnd, 
        End,
        SubOn, 
        SubOff, 
        YellowCard,
        RedCard,
        Try, 
        Penalty,
        Conversion,
        UNKNOWN
    }

    [Serializable][ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
    public class Commentary         //for RU8, ignore Message Type = "leader table"
    {
        public int Id { get; set; }
        public int PlayerId { get; set; } 
        public int TeamId { get; set; }
        public string Time { get; set; }
        public string Type { get; set; }
        public string Comment { get; set; }
    }

    [Serializable][ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
    public class ChartData
    {
        public string Home { get; set; }
        public string HomeColour { get; set; }
        public string Away { get; set; }
        public string AwayColour { get; set; }
    }

    [Serializable][ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
    public class TeamData
    {
        public Dictionary<int, PlayerData> Players { get; set; }        //(position_id / playerdata)
        public string Coach { get; set; }
    }

    [Serializable][ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
    public class PlayerData
    {
        //public int TotalSubs { get { return SubOn + SubOff; } }
        //public int SubOn {get;set;}
        //public int SubOff {get;set;}
        //public int Conversions { get; set; }
        //public int Tries { get; set; }
        //public int Penalties { get; set; }
        public int Id {get;set;}
        public string Name { get; set; }
        public string Position {get;set;}   //eg Back 8
        public int PositionId { get; set; }                     //players should be ordered by this

        public List<OptaEvent> Events { get; set; }
    }

    [Serializable][ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
    public class MatchStatCategory
    {
        public string Name {get;set;}  //eg Attack, Defence
        public List<MatchStat> Stats { get; set; }
    }

    [Serializable][ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
    public class MatchStat
    {
        public string Name { get; set; }   //eg Tries, Metres
        public string HomeDisplay { get; set; }
        public string AwayDisplay { get; set; }

        public int Ratio { get; set; }      //Ratio, for home v away             
        //when calculating this, don't forget 0-0 cases should be 50%
        //eg: 1/8 penalty goals  vs 2/2 is 12.5% against 100% so ratio is 12.5/112.5 = 11%
    }

    [Serializable][ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
    public enum MatchStatType
    {
        Numeric,
        Percentage,
        Ratio
    }

我阅读了有关将 IsReference 设置为 true 的信息,但我不确定我是否正确理解了 IsReference 的概念。我应该把属性放在哪里?

请注意,[Serializable] 属性仅用于遗留原因。

添加完整的异常正文:

[ProtoException: Possible recursion detected (offset: 2 level(s)): DataAccess.Data.Models.Opta.OptaEvent]
   ProtoBuf.ProtoWriter.CheckRecursionStackAndPush(Object instance) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:302
   ProtoBuf.ProtoWriter.StartSubItem(Object instance, ProtoWriter writer, Boolean allowFixed) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:326
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:44
   proto_43(Object , ProtoWriter ) +674
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_45(Object , ProtoWriter ) +1035
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_43(Object , ProtoWriter ) +674
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_45(Object , ProtoWriter ) +1035
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_43(Object , ProtoWriter ) +674
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_45(Object , ProtoWriter ) +1035
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_43(Object , ProtoWriter ) +674
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_45(Object , ProtoWriter ) +1035
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_43(Object , ProtoWriter ) +674
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_45(Object , ProtoWriter ) +1035
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_43(Object , ProtoWriter ) +674
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_45(Object , ProtoWriter ) +1035
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_43(Object , ProtoWriter ) +674
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_45(Object , ProtoWriter ) +1035
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_43(Object , ProtoWriter ) +674
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_45(Object , ProtoWriter ) +1035
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_43(Object , ProtoWriter ) +674
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_45(Object , ProtoWriter ) +1035
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_43(Object , ProtoWriter ) +674
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_45(Object , ProtoWriter ) +1035
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_43(Object , ProtoWriter ) +674
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_45(Object , ProtoWriter ) +1035
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_43(Object , ProtoWriter ) +674
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_41(Object , ProtoWriter ) +159
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_39(Object , ProtoWriter ) +454
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_37(Object , ProtoWriter ) +480
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_35(Object , ProtoWriter ) +532
   ProtoBuf.ProtoWriter.WriteObject(Object value, Int32 key, ProtoWriter writer) in c:\Dev\protobuf-net\protobuf-net\ProtoWriter.cs:46
   proto_33(Object , ProtoWriter ) +294
   ProtoBuf.Meta.TypeModel.SerializeCore(ProtoWriter writer, Object value) in c:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:186
   ProtoBuf.Meta.TypeModel.Serialize(Stream dest, Object value, SerializationContext context) in c:\Dev\protobuf-net\protobuf-net\Meta\TypeModel.cs:218
   AB.SiteCaching.Serializers.ProtobufNetSerializer.Serialize(Object o) in e:\Dev\NZRU\NZRU.Sites\Main\AB.SiteCaching\Serializers\ProtobufNetSerializer.cs:12
   AB.SiteCaching.Providers.<>c__DisplayClass12`1.<StoreCacheObject>b__10() in e:\Dev\NZRU\NZRU.Sites\Main\AB.SiteCaching\Providers\RedisDataSource.cs:159
   Microsoft.Practices.TransientFaultHandling.<>c__DisplayClass1.<ExecuteAction>b__0() +15
   Microsoft.Practices.TransientFaultHandling.RetryPolicy.ExecuteAction(Func`1 func) +612
   AB.SiteCaching.Providers.RedisDataSource.StoreCacheObject(String fullCacheKey, CacheDataContainer`1 cached, TimeSpan timeOut) in e:\Dev\NZRU\NZRU.Sites\Main\AB.SiteCaching\Providers\RedisDataSource.cs:153
   AB.SiteCaching.Providers.<>c__DisplayClass1`1.<RetrieveCached>b__0() in e:\Dev\NZRU\NZRU.Sites\Main\AB.SiteCaching\Providers\RedisDataSource.cs:53
   System.Threading.Tasks.Task.Execute() +110

[AggregateException: One or more errors occurred.]
   System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) +14086697
   System.Threading.Tasks.Task.Wait() +17
   AB.SiteCaching.Providers.RedisDataSource.RetrieveCached(String key, Func`1 onNotCached, TimeSpan timeOut) in e:\Dev\NZRU\NZRU.Sites\Main\AB.SiteCaching\Providers\RedisDataSource.cs:73
   DataAccess.Data.Caching.CachedMatches.GetMatchOptaData(Int32 optaMatchId) in e:\Dev\NZRU\NZRU.Sites\Main\DataAccess\Data\Caching\CachedMatches.cs:61
   Shared.Services.MatchService.ParseForScroller(List`1& fixtures, Int32 delay) in e:\Dev\NZRU\NZRU.Sites\Main\Shared\Services\MatchService.cs:109
   AllBlacksdotcom.Controllers.HomeController.Index() in e:\Dev\NZRU\NZRU.Sites\Main\AllBlacks.com\Controllers\HomeController.cs:47
   lambda_method(Closure , ControllerBase , Object[] ) +79
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +242
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +39
   System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +12
   System.Web.Mvc.Async.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult) +139
   System.Web.Mvc.Async.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d() +112
   System.Web.Mvc.Async.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f() +452
   System.Web.Mvc.Async.<>c__DisplayClass33.<BeginInvokeActionMethodWithFilters>b__32(IAsyncResult asyncResult) +15
   System.Web.Mvc.Async.<>c__DisplayClass2b.<BeginInvokeAction>b__1c() +37
   System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult) +241
   System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +29
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +111
   System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +53
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +19
   System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +51
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +111
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +606
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288

编辑:

序列化程序代码:

 public class ProtobufNetSerializer : ICacheDataSerializer
    {
        public byte[] Serialize(object o)
        {
            using (var memoryStream = new MemoryStream())
            {
                Serializer.Serialize(memoryStream, o);

                return memoryStream.ToArray();
            }
        }

        public T Deserialize<T>(byte[] stream)
        {
            var memoryStream = new MemoryStream(stream);

            return Serializer.Deserialize<T>(memoryStream);
        }
    }

我通过简化模型解决了这个问题:

 public List<OptaEvent> Events { get; set; }

代码中的这一行没有意义。我们只需要事件类型列表,而不是所有事件详细信息的列表。删除它并用适当的 属性 替换它就可以了。