Application fails in 3-tier 'Release' mode but works fine in 3-tier 'Debug' mode

Application fails in 3-tier 'Release' mode but works fine in 3-tier 'Debug' mode

Old forum URL: forums.lhotka.net/forums/t/10182.aspx


MANOJ posted on Monday, March 21, 2011

We are using CSLA 3.8.3 and VS 2010 (.Net Framework 4.0).

 

Our application works fine in 3 - tier ‘Debug’ mode and 2-tier ‘Release’ mode.

 

But the same application fails in 3 – tier ‘Release’ mode.  Can anyone give some pointers to the issue and the fix?   

 

The error we are getting is below:

 

Server was unable to process the request -à Exception has been thrown by the target of an invocation -à The type initializer for <<our class name>> threw an exception. -à  Object reference not to set to an instance of an object

 

This error happens while we are retrieving value from the DB.  Before executing the below lines of code which throws this error, we are fetching data from DB and that works fine.  So connection to the DB and fetching data works.

 

Source code which throws error is below:

 

From the Business Layer:

 

private void DataPortal_Fetch(Criteria criteria)

        {

            XmlNode customFields = HelperMethods.GetCustomFieldXML(HelperMethods.TableName.TAB_CONTAINER);

            DataFactory df = new DataFactory();

            var dal = df.GetContainerDataObject();

            _containers = dal.GetContainers(criteria.LocationId, criteria.Barcode, customFields, criteria.UserId);

        }

 

And the DAL Layer code is

 

  public override DataSet GetContainers(int locationId, string barcode, XmlNode customFieldsXML, int userId)

        {

            string methodSignature = MethodBase.GetCurrentMethod().DeclaringType.Name + "->" + MethodBase.GetCurrentMethod().Name.ToUpper() + " ";

            try

            {

                _coeLog.LogStart(methodSignature);

                DbCommand dbCommand = db.GetStoredProcCommand(BuildStoredProcName(PKG_CONTAINER, SP_GET_CONTAINERS));

                db.AddInParameter(dbCommand, BuildParameterName(PROP_LOCATION_ID), DbType.Int32, locationId);

                db.AddParameter(dbCommand, BuildParameterName(PROP_CUSTOM_FIELDS), DbType.AnsiString, Int32.MaxValue, ParameterDirection.Input, true, 0, 0, string.Empty, DataRowVersion.Current, customFieldsXML.OuterXml.ToString());

                db.AddInParameter(dbCommand, BuildParameterName(PROP_BARCODE), DbType.String, barcode);

                db.AddInParameter(dbCommand, BuildParameterName(PROP_USER_ID), DbType.Int32, userId);

                return db.ExecuteDataSet(dbCommand);

            }

            catch (Exception ex)

            {

                _coeLog.Log(methodSignature + " - " + ex.Message);

                throw new InventoryException(ex);

            }

            finally

            {

                _coeLog.LogEnd(methodSignature);

            }

        }

 

Since there is no entry for exception message in our log file

, we are assuming the procedure has been executed without exception, but before reaching the result back to Business Layer it fails.

 

Stack trace shows, last lines executed are from

 

Csla\Web References\WebServiceHost\Reference.cs:line 124

 

Csla\DataPortalClient\WebServicesProxy.cs:line 75

RockfordLhotka replied on Monday, March 21, 2011

A couple things to consider.

First, 3.8.x was never tested on .NET 4 - that's what CSLA 4 is all about. There were a few changes that had to be made to 3.8.4 to get it working at the beginning of the CSLA 4 project. I don't remember the specific changes, and I don't think any of them were related to the data portal.

Second, the web service data portal channel (that you appear to be using) really was never tested, and in fact was removed from CSLA 4 entirely. That data portal channel was created in 2003 (or so) to combat some specific politically-driven decisions by a couple customers. Those were (imo) poor decisions technically, but some battles you just can't win based on what is technically correct. So the asmx channel was created to accomodate an application requirement driven by someone in power misunderstanding the technologies being used.

In any case, I've viewed the asmx channel as obsolete since 2006 when WCF was integrated into CSLA 2.1.x, because WCF really is a good solution, and it even meets the misguided reasoning that caused the creation of the asmx channel in the first place :)

To make this rambling reply more clear - I'm suggesting that you might want to try the WCF channel instead of the asmx channel. However, I am pretty sure the WCF channel did require some change to make it work with .NET 4 - Microsoft changed something with WCF and we had to recreate the WCF service reference (if I recall correctly) to get it working in .NET 4.

sg11 replied on Monday, March 21, 2011

More on the stack trace:

System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.TypeInitializationException: The type initializer for 'CambridgeSoft.COE.Inventory.Library.ContainerList' threw an exception. ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at CambridgeSoft.COE.Inventory.Library.ContainerList..cctor() in C:\Projects\sunildesk2\People\sgupta\InvMgr\Inventory.NET\Inventory.Library\Container\ContainerList.cs:line 44
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
   at System.RuntimeFieldHandle.GetValue(RtFieldInfo field, Object instance, RuntimeType fieldType, RuntimeType declaringType, Boolean& domainInitialized)
   at System.Reflection.RtFieldInfo.InternalGetValue(Object obj, Boolean doVisibilityCheck, Boolean doCheckConsistency)
   at System.Runtime.Serialization.FormatterServices.GetObjectData(Object obj, MemberInfo[] members)
   at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo()
   at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder)
   at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
   at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
   at Csla.Server.Hosts.WebServicePortal.Serialize(Object obj) in C:\Projects\sunildesk2\People\sgupta\InvMgr\Inventory.NET\Csla\Server\Hosts\WebServicePortal.cs:line 269
   at Csla.Server.Hosts.WebServicePortal.Fetch(Byte[] requestData) in C:\Projects\sunildesk2\People\sgupta\InvMgr\Inventory.NET\Csla\Server\Hosts\WebServicePortal.cs:line 211
   --- End of inner exception stack trace ---

sg11 replied on Monday, March 21, 2011

Rocky

How would you explain not seeing this error with Debug goods. Also, are you suggeting trying the WCF channel with CSLA 3.8 (that we are using). Unfortunately we cannot change to CSLA 4 yet, as a library we are internally dependent on still uses CSLA 3.8, and the team responsible for that library is in no position to upgrade yet.

Thanks

SG

RockfordLhotka replied on Monday, March 21, 2011

The full stack trace helps a lot. This is an issue with the BinaryFormatter, or at least with serialization.

You may be able to reproduce this by using the Clone method on a business object of that type. Although that won't solve the issue, it might make it easier to chase down the problem because it will eliminate the data portal and web services infrastructure from the picture.

Also, "cctor" refers to the static constructor.

Hmm. It is quite possible you are hitting an issue with static field initialization - potentially on the client.

So some questions:

  1. Are you manually implementing ISerializable? That complicates the heck out of things.
  2. Do you have custom base classes with properties?
    1. Are you using the _forceInit trick? Is your _forceInit code complex enough that the compiler won't opimize it away?
    2. Are your PropertyInfo<T> fields public? That's a more reliable way to ensure proper initialization.

My previous post was pre-coffee, and so was a bit rambling.

It is true that 3.8.3 was never tested on .NET 4 - so there could absolutely be issues due to changes in .NET from 3.5 to 4. I literally didn't try doing that, so I don't know.

And I really do recommend avoiding the asmx channel. From day 1 I've said it was a sub-optimal channel I created to meet some misguided decisions on the part of some organizations who had irrational issues with Remoting. But since 2006 WCF has been available and makes those misguided people feel good, while also providing a good technical solution.

But given the stack trace you posted later, I doubt WCF will help. I don't think this is a data portal issue, I think it is a serialization issue. And I don't think it is "serialization" as much as static field initialization (though I can't say for sure).

sg11 replied on Monday, March 21, 2011

Rocky

Someone will respond to your questions, but I was curious about the effort to switch to WCF. Chapter 21 indicates that for obvious reasons the creation of the service layer is quite involved, and I am not sure we've the luxury to do that at this point. The asmx layer has been magically there for us.

Thanks

SG

RockfordLhotka replied on Monday, March 21, 2011

Chapter 21 is about creating a service interface using WCF, not about using the WCF data portal channel.

The data portal abstracts the network and uses a channel adapter design pattern. The result is that you can switch between various data portal channels without impacting your code, or having to do all the work described in Chapter 21.

The only catch with using WCF is that you might need to configure WCF somewhat, and that's harder than configuring asmx (because WCF is so much more powerful/flexible).

In short: none of Chapter 21 applies to the use of the WCF data portal channel.

MANOJ replied on Tuesday, March 22, 2011

Thanks, will checkout Chapter 21.

The issue has been identified; we have a member in the class to store user_id as below

private static readonly int _userId = int.Parse(Csla.ApplicationContext.GlobalContext["USER_PERSONID"].ToString());

this line of code has caused the issue.  Application is working in 'Release' mode after we had changed our code to get rid of the above line.  It seems to be the static member's value is not getting assigned while coming back from DAL layer. 

Csla.ApplicationContext.GlobalContext isn't the appropriate context for storing user_id? 

 

 

RockfordLhotka replied on Tuesday, March 22, 2011

There are three context dictionaries: LocalContext, ClientContext, and GlobalContext.

I discuss these in detail in the Using CSLA 4 ebook series.

ClientContext and GlobalContext (and their contents) are obviously serialized and deserialized as they flow through the data portal. All standard serialization rules apply - including that static members of types are never serialized.

It is also the case that the async data portal treats GlobalContext differently. The sync data portal replaces the GlobalContext on the client with the one from the server at the end of the data portal call. Because numerous async calls could occur at once, that obviously can't be done with the async data portal. So the async data portal provides you with access to a GlobalContext property you can use to get at the values as the call completes.

So in your async callback handler code, you can pull out any appropriate GlobalContext values and update the "real" GlobalContext - keeping in mind that there could be multiple outstanding async operations - so it is up to you to figure out how to reconcile any differences.

Generally, no. GlobalContext is not the right place for the user id information. That should go into a principal object - the official .NET location for user identity information.

Copyright (c) Marimer LLC