Remoting issue with IPrefetchPath2?

Posts   
 
    
thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 25-Oct-2008 22:28:32   

Runtime Library Version: 2.6.8.1013

.NET 3.5, Adapter, General2008, Oracle 9i

I am getting a NullReferenceException once I include IPrefetchPath2 into my remoting interface. The exception details including locals window, call stack etc. is attached. If I remove the signature with IPrefetchPath2, everything works fine. If it is present, the exception happens regardless of whether I call the overload with the prefetch, or the other FetchEntity method without it.

Any ideas? Please let me know if any other info is needed be it assembly references etc. Thanks

Remote data server interface:


namespace CRMA.Core.DataAccess
{
    public interface IDataServer
    {
        int CommitUnitOfWork(UnitOfWork2 uow);

        TEntity FetchEntity<TEntity>(TEntity entity)
            where TEntity : EntityBase2, new(); //IEntity2

[b]     //ISSUE: If IPrefetchPath2 is used here, null ref ex upon remoting:
        TEntity FetchEntity<TEntity>(TEntity entity, IPrefetchPath2 prefetchPath)
            where TEntity : EntityBase2, new(); //IEntity2[/b]

        EntityCollection<TEntity> FetchEntityCollection<TEntity>(
            IRelationPredicateBucket filterBucket, ExcludeIncludeFieldsList fields,
            ISortExpression sort)
            where TEntity : EntityBase2, new();

        EntityCollection<TEntity> FetchEntityCollection<TEntity>(
            IRelationPredicateBucket filterBucket)
            where TEntity : EntityBase2, new();

        EntityCollection<TEntity> FetchEntityCollection<TEntity>(
            IPredicateExpression filter)
            where TEntity : EntityBase2, new();

        EntityCollection<TEntity> FetchEntityCollection<TEntity>(
            IPredicateExpression filter, ExcludeIncludeFieldsList fields,
            ISortExpression sort)
            where TEntity : EntityBase2, new();

        TView FetchTypedView<TView>(IPredicateExpression filter)
            where TView : ITypedView2, new();

        T FetchLookups<T>() where T : DataAccessObjectBase, IServerLookups<T>, new();

        T Fetch<T>() where T : DataAccessObjectBase, IServerFetch<T>, new();

        TDataAccess Fetch<TDataAccess, UParam>(UParam param)
            where TDataAccess : DataAccessObjectBase, IParameterizedFetch<TDataAccess, UParam>, new();
    }
}

DataServer (entity partial) in service library used in console (debugging) and service (server side):


namespace CRMA.ServiceLibrary
{
    partial class DataServer
    {
        public TEntity FetchEntity<TEntity>(TEntity entity)
            where TEntity : EntityBase2, new() //IEntity2
        {
            try
            {
                using (IDatabaseAdapter adapter = DataAccessAdapterFactory.Create())
                {
                    adapter.FetchEntity(entity);
                    return entity;
                }
            }
            catch (ORMQueryExecutionException queryEx)
            {
                throw HandleQueryExecutionError(queryEx);
            }
        }

        
        public TEntity FetchEntity<TEntity>(TEntity entity, IPrefetchPath2 prefetchPath)
            where TEntity : EntityBase2, new() //IEntity2
        {
            try
            {
                using (IDatabaseAdapter adapter = DataAccessAdapterFactory.Create())
                {
                    adapter.FetchEntity(entity, prefetchPath);
                    return entity;
                }
            }
            catch (ORMQueryExecutionException queryEx)
            {
                throw HandleQueryExecutionError(queryEx);
            }
        }
        
    }
}

Data Access Class:


namespace CRMA.DataAccess.EntitySpecific.Server
{
    public class BatchDataAccess : DataAccessObjectBase
    {
        public static BatchesEntity GetBatch(long batchId)
        {
            BatchesEntity batch = new BatchesEntity(batchId);
            return Remote.DataServer.FetchEntity<BatchesEntity>(batch);
        }

        public static BatchesEntity GetBatchWithChartReviews(long batchId)
        {
            BatchesEntity batch = new BatchesEntity(batchId);
            IPrefetchPath2 prefetchPath = new PrefetchPath2(EntityType.BatchesEntity);
            prefetchPath.Add(BatchesEntity.PrefetchPathChartReviews);
            return Remote.DataServer.FetchEntity<BatchesEntity>(batch, prefetchPath);
        }

    }
}

Remote server access class:


namespace CRMA.DataAccess.Core
{
    public class Remote
    {
        public static IDataServer DataServer { get; set; }
        
        static Remote()
        {
            // will get set by client when remoting is initialized
            //Remote._dataServer = new DataServer();
        }
    }
}

Client app startup:


private static void AppStartup()
        {
            //RemotingConfiguration.Configure("CRMA.Client.exe.config", false);         
            TcpChannel channel = new TcpChannel();
            ChannelServices.RegisterChannel(channel, true);

            MarshalByRefObject mbro = (MarshalByRefObject)RemotingServices.Connect(
                typeof(IDataServer), GetEndPointUrl());
            Remote.DataServer = mbro as IDataServer;
            
            if (null == Remote.DataServer)
            {
                throw new Exception("Service couldn't be obtained. Aborting");
            }

            // null ref ex if IPrefetch2 is in IDataServer interface:
            CRMA.Model.EntityClasses.BatchesEntity entity
                = CRMA.DataAccess.EntitySpecific.Server.BatchDataAccess.GetBatch(1);

            LookupDataCache.Singleton.LoadSharedLookupData();
        }

Console:


namespace CRMA.Console
{
    class Program
    {
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
        private const int SW_MINIMIZE = 6;
        private const int SW_MAXIMIZE = 3;
        private const int SW_RESTORE = 9;

        static void Main(string[] args)
        {
            RemotingConfiguration.Configure("CRMA.Console.exe.config", false);

            MinimizeConsole();

            System.Console.WriteLine("Press <ENTER> key to shut down server.");
            System.Console.ReadLine();          
        }

        private static void MinimizeConsole()
        {
            IntPtr winHandle = Process.GetCurrentProcess().MainWindowHandle;
            ShowWindow(winHandle, SW_MINIMIZE);
        }
    }
}

Console app config remoting section:

<system.runtime.remoting> <customErrors mode="Off"/> <application name="CRMA.Console"> <service> <wellknown mode="SingleCall" objectUri="theEndPoint" type="CRMA.ServiceLibrary.DataServer, CRMA.ServiceLibrary" /> </service> <channels> <channel ref="tcp" port="65100" secure="true" impersonate="true"> <clientProviders> <formatter ref="binary" /> </clientProviders> <serverProviders> <!-- <provider type="Product.Common.Remoting.CompressionServerSinkProvider, Product.Common" /> --> <formatter ref="binary" typeFilterLevel="Full" /> </serverProviders> </channel> </channels> </application> </system.runtime.remoting>

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39903
Joined: 17-Aug-2003
# Posted on: 26-Oct-2008 10:59:19   

I dont see you're using fast serialization or not, so for clarity: you use fastserialization or not? The stacktrace is really odd... as if some block of data is missing...

Frans Bouma | Lead developer LLBLGen Pro
thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 26-Oct-2008 20:07:17   

No I am not currently using FastSerialization. I should have mentioned FastSerialization as when I tried it before I get the exception below and maybe it is related problem. With FastSerialization enabled the exception is below:

System.Runtime.Serialization.SerializationException occurred Message="Member 'AmountEntitiesInList' was not found." Source="mscorlib" StackTrace: at System.Runtime.Serialization.SerializationInfo.GetElement(String name, Type& foundType) InnerException:

... which happens on the below line:


                /// <summary>
        /// Protected CTor for deserialization
        /// </summary>
        /// <param name="info"></param>
        /// <param name="context"></param>
        protected EntityCollection( SerializationInfo info, StreamingContext context )
            : base( info, context )
        {
        }

I will try to attach the code and maybe that will help...

thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 26-Oct-2008 20:18:55   

I attached proof of concept app code and DB DDL in email to info AT llblgen.com referencing this thread (was too large to attach here). Not sure it will be runnable but perhaps it will help in troubleshooting...

thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 26-Oct-2008 20:43:17   

Forgot to mention that in the original attachment, the Locals window has more info than what is shown... the image got cut off but can be resized for more info.

Also, may be nothing but I noticed the below in the output when attempting to step into w/debugger:

Step into: Stepping over method without symbols 'CRMA.DataAccess.Core.Remote.DataServer.get'

Step into: Stepping over method without symbols 'System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke'

It seems strange to me that I can successfully fetch entity collections, typed views, and even entities (w/o prefetch paths)... no idea why having IPrefetchPath2 in the signature seems to throw things off.

Interesting... on a hunch I removed the overload that does not take in a prefetch path and it worked fine with only one variation of a FetchEntity method (w/prefetch, passing null). It is almost like something is getting confused and the wrong overload is being called or something. I am really scratching my head here. I have several overloads of FetchEntityCollection that give me no problem... ??

Trying a couple other variations of things here...

thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 26-Oct-2008 21:16:28   

Please CHOP off looooooooooong lines next time. Thanks. -- Otis

Yeah the original exception appears to be some sort of strange remoted method overload issue. If I leave FetchEntity(TEntity) in place and change the other one to a new name like FetchEntities(TEntity rootEntity, IPrefetchPath2 path) both versions work fine. Not sure if this is LGEN related, a .NET bug, and/or something with the architecture I have in place? Let me know if you find anything out...

With the "overloading issue" temporarily worked around, I then see something slightly different if I again switch on fast serialization...

Execution will then stop at:


/// <summary> Protected CTor for deserialization</summary>
        /// <param name="info"></param>
        /// <param name="context"></param>
        protected CommonEntityBase(SerializationInfo info, StreamingContext context) : base(info, context)
        {
            
            // __LLBLGENPRO_USER_CODE_REGION_START DeserializationConstructor
            // __LLBLGENPRO_USER_CODE_REGION_END
        }

With the below exception / call stack:

System.Runtime.Serialization.SerializationException occurred Message="Member '_' was not found." Source="mscorlib" StackTrace: at System.Runtime.Serialization.SerializationInfo.GetElement(String name, Type& foundType) InnerException:

mscorlib.dll!System.Runtime.Serialization.SerializationInfo.GetElement(string name, out System.Type foundType) + 0xb3 bytes 
mscorlib.dll!System.Runtime.Serialization.SerializationInfo.GetValue(string name, System.Type type = {Name = "Byte[]" FullName = "System.Byte[]"}) + 0x26 bytes 
SD.LLBLGen.Pro.ORMSupportClasses.NET20.dll!SD.LLBLGen.Pro.ORMSupportClasses. SerializationHelper.GetSerializedBytes(System.Runtime.Serialization.SerializationInfo info = {System.Runtime.Serialization.SerializationInfo}) + 0x48 bytes    
SD.LLBLGen.Pro.ORMSupportClasses.NET20.dll!SD.LLBLGen.Pro.ORMSupportClasses. SerializationHelper.Deserialize(SD.LLBLGen.Pro.ORMSupportClasses.EntityBase2 entity = {CRMA.Model.EntityClasses.BatchesEntity}, System.Runtime.Serialization.SerializationInfo info = {System.Runtime.Serialization.SerializationInfo}, System.Runtime.Serialization.StreamingContext context = {System.Runtime.Serialization.StreamingContext}) + 0x4a bytes  
SD.LLBLGen.Pro.ORMSupportClasses.NET20.dll!SD.LLBLGen.Pro.ORMSupportClasses. EntityBase2.EntityBase2(System.Runtime.Serialization.SerializationInfo info = {System.Runtime.Serialization.SerializationInfo}, System.Runtime.Serialization.StreamingContext context = {System.Runtime.Serialization.StreamingContext}) + 0x860 bytes 

CRMA.Model.dll!CRMA.Model.EntityClasses.CommonEntityBase.CommonEntityBase( System.Runtime.Serialization.SerializationInfo info = {System.Runtime.Serialization.SerializationInfo}, System.Runtime.Serialization.StreamingContext context = {System.Runtime.Serialization.StreamingContext}) Line 51 + 0x14 bytes C# CRMA.Model.dll!CRMA.Model.EntityClasses.BatchesEntity.BatchesEntity(System.Runtime.Serialization.SerializationInfo info = {System.Runtime.Serialization.SerializationInfo}, System.Runtime.Serialization.StreamingContext context = {System.Runtime.Serialization.StreamingContext}) Line 131 + 0x13 bytes C# [Native to Managed Transition] [Managed to Native Transition] mscorlib.dll!System.Reflection.RuntimeConstructorInfo.SerializationInvoke(object target, System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + 0x6d bytes mscorlib.dll!System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(object obj, System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + 0x112 bytes mscorlib.dll!System.Runtime.Serialization.ObjectManager.FixupSpecialObject(System.Runtime.Serialization.ObjectHolder holder = {System.Runtime.Serialization.ObjectHolder}) + 0x32 bytes mscorlib.dll!System.Runtime.Serialization.ObjectManager.DoFixups() + 0xe0 bytes mscorlib.dll!System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize (System.Runtime.Remoting.Messaging.HeaderHandler handler = {Method = {System.Object HeaderHandler(System.Runtime.Remoting.Messaging.Header[])}}, System.Runtime.Serialization.Formatters.Binary.__BinaryParser serParser, bool fCheck, bool isCrossAppDomain, System.Runtime.Remoting.Messaging.IMethodCallMessage methodCallMessage = null) + 0xbd bytes mscorlib.dll!System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler, bool fCheck, bool isCrossAppDomain, System.Runtime.Remoting.Messaging.IMethodCallMessage methodCallMessage) + 0xcc bytes System.Runtime.Remoting.dll!System.Runtime.Remoting.Channels.CoreChannel.DeserializeBinaryRequestMessage(string objectUri, System.IO.Stream inputStream, bool bStrictBinding, System.Runtime.Serialization.Formatters.TypeFilterLevel securityLevel) + 0x60 bytes System.Runtime.Remoting.dll!System.Runtime.Remoting.Channels.BinaryServerFormatterSink. ProcessMessage(System.Runtime.Remoting.Channels.IServerChannelSinkStack sinkStack = {System.Runtime.Remoting.Channels.ServerChannelSinkStack}, System.Runtime.Remoting.Messaging.IMessage requestMsg = null, System.Runtime.Remoting.Channels.ITransportHeaders requestHeaders = {System.Runtime.Remoting.Channels.BaseTransportHeaders}, System.IO.Stream requestStream = {System.Runtime.Remoting.Channels.Tcp.TcpFixedLengthReadingStream}, out System.Runtime.Remoting.Messaging.IMessage responseMsg = null, out System.Runtime.Remoting.Channels.ITransportHeaders responseHeaders = null, out System.IO.Stream responseStream = null) + 0x356 bytes System.Runtime.Remoting.dll!System.Runtime.Remoting.Channels.Tcp.TcpServerTransportSink.ServiceRequest(object state) + 0x151 bytes System.Runtime.Remoting.dll!System.Runtime.Remoting.Channels.SocketHandler.ProcessRequestNow() + 0x34 bytes System.Runtime.Remoting.dll!System.Runtime.Remoting.Channels.RequestQueue.ProcessNextRequest( System.Runtime.Remoting.Channels.SocketHandler sh) + 0x17 bytes System.Runtime.Remoting.dll!System.Runtime.Remoting.Channels.SocketHandler.BeginReadMessageCallback( System.IAsyncResult ar) + 0xb6 bytes System.dll!System.Net.LazyAsyncResult.Complete(System.IntPtr userToken) + 0x69 bytes System.dll!System.Net.LazyAsyncResult.ProtectedInvokeCallback(object result, System.IntPtr userToken) + 0xb0 bytes System.dll!System.Net.Security.NegotiateStream.ProcessFrameBody(int readBytes = 0x00000059, byte[] buffer, int offset, int count, System.Net.AsyncProtocolRequest asyncRequest) + 0xa4 bytes System.dll!System.Net.Security.NegotiateStream.ReadCallback(System.Net.AsyncProtocolRequest asyncRequest = {System.Net.AsyncProtocolRequest}) + 0xba bytes System.dll!System.Net.AsyncProtocolRequest.CompleteRequest(int result) + 0x38 bytes System.dll!System.Net.FixedSizeReader.CheckCompletionBeforeNextRead(int bytes) + 0x34 bytes System.dll!System.Net.FixedSizeReader.ReadCallback(System.IAsyncResult transportResult) + 0x6e bytes System.dll!System.Net.LazyAsyncResult.Complete(System.IntPtr userToken) + 0x69 bytes System.dll!System.Net.ContextAwareResult.CompleteCallback(object state) + 0x1a bytes mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x6f bytes System.dll!System.Net.ContextAwareResult.Complete(System.IntPtr userToken) + 0x91 bytes System.dll!System.Net.LazyAsyncResult.ProtectedInvokeCallback(object result, System.IntPtr userToken) + 0xb0 bytes System.dll!System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* nativeOverlapped) + 0x94 bytes mscorlib.dll!System.Threading._IOCompletionCallback.PerformIOCompletionCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* pOVERLAP) + 0x54 bytes

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39903
Joined: 17-Aug-2003
# Posted on: 26-Oct-2008 21:37:25   

You sent a truckload of code, but where to start, what to test?

I'm sorry, but in things like this, a SIMPLE test will do. We'll see if we can reproduce this with simple BinaryFormatter serialization/deserialization, which should already reveal the problem, but otherwise, please at least give a simple repro test and a short description what to test? I really am not going to wade through all that code to look for a possible issue.

Frans Bouma | Lead developer LLBLGen Pro
thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 26-Oct-2008 21:47:40   

Sure, I understand. I was planning on creating a new sample app against Northwind DB that would illustrate the issue. That will likely take me a while to setup though and not sure when I will get the chance. So in the mean time I just thought I'd send the code to see if anything jumped out. As to where to start, it would basically be in the CRMA.Client project in Program.cs in AppStartup where it attempts to get the batches entity... just back tracking from there to see sequence and looking at project references etc. and using above original source and problem details as a guide.

I will try to create a new sample app against a common DB if I can get the chance soon. Thanks

Sorry for not formatting the exception dump Otis simple_smile

thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 27-Oct-2008 03:17:05   

Okay attached is a quick and dirty small sample app running against northwind db. It is not an exact match of what I am doing in the real app but follows the same basic pattern and appears to demonstrate the same problem.

Start in the UI solution folder with the ClientShell project, in DoDataAccessTest() of Program.cs.

Thanks again

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39903
Joined: 17-Aug-2003
# Posted on: 27-Oct-2008 11:23:41   

The null-ref exception is indeed something inside the .NET remoting layer: apparently when generics are involved it gets confused and can't do proper method resolution for overloaded methods. I can't find a resource to back this up, but your code looks OK however it crashes inside the remoting layer: I can't step into the service from the client whatever I do (debuggers attached to both sides etc.) -> the stacktrace shows that the call never makes it: it crashes doing the call.

The second stacktrace you ran into when switching on fast serialization is caused by the fact that you have to switch it on on BOTH sides.

Frans Bouma | Lead developer LLBLGen Pro
thnk2wn
User
Posts: 31
Joined: 05-Jul-2008
# Posted on: 27-Oct-2008 14:03:04   

Yeah thanks for confirming I was not crazy with that hunch. I wonder if Microsoft is aware of the problem; maybe I should make sure. It seems odd that I cannot find anything online to indicate this limitation. It is also odd that in my original project, I had several different remoted, generic overloads of FetchEntityCollection that did not give me any problems. Not sure exactly what the pattern is that causes it but apparently it is something we have run into before here. I suppose I will have to consolidate some methods and/or get more creative with my method names.

I guess having fast serialization turned on on both sides would help. simple_smile Thanks