Need help, get error "Object does not match target type" in one instanceof an app, when others work

  • Thread starter Lasse Vågsæther Karlsen
  • Start date
L

Lasse Vågsæther Karlsen

I get the above error in some of the ASP.NET web applications on a
server, and I need some help figuring out how to deal with it.

This is a rather long post, and I hope I have enough details that
someone who bothers to read all of it have some pointers.

Note, I have posted the stack trace and the code exhibiting the problem
further down so if you want to start by reading that, search for +++

Also note that I am unable to reproduce this problem in a smaller app,
otherwise I would try to post a working example that could be tested by
others.

Here's the deal.

I got a IIS6 web server hosted on W2K3 running a website containing
internal test instances of our web application. The web server does
nothing else and was explicitly set up for the purposes of these instances.

We have multiple databases hooked up and 3 different versions of the app
installed, so the basic setup is as follows:

- 3x versions
- 6x databases

Let's call the 3 versions version 1 through 3, and the databases
database A-F.

Since the instance name contain the version number (2, 3 and 3 digits
respectively) as well as the database name (which bears the name of the
customer we've gotten it from), the actual names of the instances
differs in lengths, varying from 17 to 20 characters. Since it doesn't
seem to be a pattern in that long instance names doesn't work and short
does, I assume that doesn't matter either.

The names all follow the following patterns:

ms_customer_date_ver

ms is for "Microsoft SQL Server", and we got "ora" for Oracle.
customer is customer name, either abbreviated or in full, only english
letters.
date is YYMMDD of the date the database was sent to us.
ver is 49, 499 or 410, depending on the version of the app.

The full (masked for security) url to one such database would be as follows:

http://our.internal.domain/ms_customer_070205_49/

18 instances in total. 3 and 3 share the same files, except for one line
in the web.config file with the connection string. Everything else has,
on the file level, been confirmed identical with a file comparing tool.

Files in the instances does not change after the app is loaded.

I set up the 18 web apps by first configuring the web site with the
default values, and then just adding 18 virtual directories below it,
pointing to each of the directories. The only thing I changed afterwards
was to point 6 and 6 versions to a separate app-pool, one for each
version. I added these app-pools after getting the error message, hoping
it would fix the problem, but it changed nothing so it apparently has no
bearing on it.

The strange thing now is that of the 18 instances, about 9 of them work.
I say "about" because it seems to be ill-tempered.

Version 1, all databases, work. Version 2, only one database works, and
version 3, 1 work all the time and the other only seems to work for a
short period of time after I restart the web server service.

There seems to be no apparent pattern to why these would work as I have
dropped and recreated the virtual directories inside IIS to try to fix
it. I also dropped and recreated one that worked and this one keeps on
working fine.

I tried separating out the 3 versions on their own 3 virtual web servers
with their own header hostnames on the same server, but if I can't get
this working I'm probably forced to split it up physically on different
servers.

Ok, that's the setup I've done, now I'll describe where the problem
appears. +++

The stack trace identifies the problem as the following line (at least
this is the last method in my own code that executes):

String previousValue = (String)pi.GetValue(this, args);

pi is of type PropertyInfo.
args is new Object[0]

The problem occurs in a base class used for descendant ORM objects, all
autogenerated. Some of these classes have one special property, of type
String, that needs to be auto-maintained on each update according to a
specific pattern. This is done by first finding the property, reading
the current value, passing that value through the update logic to get
the new value, and then writing it back.

For some objects (seemingly without a pattern), this fails on
pi.GetValue(...) with the mentioned exception message.

The code above is executed as part of the OnSaving() method for the
objects, before the object is persisted to the database.

Since the property name could be different on different objects, and not
all the objects have such a property, instead of looping through all the
properties on each save to see if any of them is such a special
property, I build a dictionary the first time, by finding all the types
in all the assemblies in the current appdomain, that have a property
tagged with a specific attribute. I keep track of the PropertyInfo
object for these properties.

The whole OnSaving method looks like this:

protected override void OnSaving()
{
base.OnSaving();

if (_ObjectsWithModificationHistories == null)
{
_ObjectsWithModificationHistories = new Dictionary<Type,
PropertyInfo>();

foreach (Assembly assembly in
AppDomain.CurrentDomain.GetAssemblies())
{
foreach (Type type in assembly.GetTypes())
{
if (type.IsDefined(typeof(PersistentAttribute), true))
{
foreach (PropertyInfo pi in GetType().GetProperties())
{
if
(pi.IsDefined(typeof(ModificationHistoryAttribute), true) &&
pi.IsDefined(typeof(PersistentAttribute), true))
{
if (pi.PropertyType == typeof(String))
{
_ObjectsWithModificationHistories[type]
= pi;
break;
}
}
}
}
}
}
}

if (ModificationHistoryGeneration.Default != null &&
_ObjectsWithModificationHistories.ContainsKey(GetType()))
{
PropertyInfo pi = _ObjectsWithModificationHistories[GetType()];
Object[] args = new Object[0];

String previousValue = (String)pi.GetValue(this, args); // ***
String newValue =
ModificationHistoryGeneration.Default.GenerateNewValue(previousValue);
pi.SetValue(this, newValue, args);
}
}

The first time the method is called, it finds that the dictionary is
null and thus creates it, by populating it with all the PropertyInfo
objects for all the properties for all the types, binding them to the
Type object for that type.

What I think is happening is some kind of pollution of the assemblies,
in that one class is found when the app is first executing this code,
and when the code is executed later, a different (but yet identical
enough to be found in the dictionary) Type object is used and thus the
GetValue(...) method fails.

The stack trace is as follows:

[TargetException: Object does not match target type.]
System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target) +2329749
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags
invokeAttr, Binder binder, Object[] parameters, CultureInfo culture,
Boolean skipVisibilityChecks) +114
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags
invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) +29
System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags
invokeAttr, Binder binder, Object[] index, CultureInfo culture) +55
System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[]
index) +18
***LVK.Data.Persistence.XPBaseObjectEx.OnSaving() in
d:\Dev\VS.NET\Gatsoft\LVK.Data.Persistence\XPBaseObjectEx.cs:270***
DevExpress.Xpo.XPBaseObject.DevExpress.Xpo.IXPObject.OnSaving() +7
DevExpress.Xpo.Session.TriggerObjectSaving(Object theObject) +65
DevExpress.Xpo.Session.PreProcessSavedList() +231
DevExpress.Xpo.Session.CommitTransaction() +63
DevExpress.Xpo.Session.ProcessingProcess(IDictionary
markedObjectsHolder, Object theObject) +113
DevExpress.Xpo.Session.Save(Object theObject) +15
DevExpress.Xpo.XPBaseObject.Save() +67
Gatsoft.Gat.BusinessLogic.Logging.Log.LogUserLoginTraffic(SystemSource
source) in d:\Dev\VS.NET\Gatsoft\Gatsoft.Gat.BusinessLogic\Logging\Log.cs:89
MyGat.Persistence.Session.WebContext.set_User(UserContext value) in
d:\Dev\VS.NET\Gatsoft\Applications\Web\MinGat\MinGat_deploy\Source\App_Code\Persistence\Session\WebContext.cs:900
Gatsoft.Gat.BusinessLogic.Security.Login.Controllers.UserLoginController.ConfigureUserContext(UserAccount
account) in
d:\Dev\VS.NET\Gatsoft\Gatsoft.Gat.BusinessLogic\Security\Login\Controllers\UserLoginController.cs:601
Gatsoft.Gat.BusinessLogic.Security.Login.Controllers.WebUserLoginController.Login()
in
d:\Dev\VS.NET\Gatsoft\Gatsoft.Gat.BusinessLogic\Security\Login\Controllers\WebUserLoginController.cs:353
gtw.frmLogin.btLogin_Click(Object sender, EventArgs e) in
d:\Dev\VS.NET\Gatsoft\Applications\Web\MinGat\MinGat_deploy\Source\frmLogin.aspx.cs:389
System.Web.UI.WebControls.Button.OnClick(EventArgs e) +105
System.Web.UI.WebControls.Button.RaisePostBackEvent(String
eventArgument) +107
System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String
eventArgument) +7
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler
sourceControl, String eventArgument) +11
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33
System.Web.UI.Page.ProcessRequestMain(Boolean
includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5102

I apologize for the low readability of this but the usenet posting
program wordwraps.

I've added *** to the above stacktrace to last (topmost) call that is
our code. I've added *** to the code posted above the stacktrace for
what corresponds to line 270.

The application relies on a bunch of assemblies, all working together,
and I've verified that the correct versions of them all has been copied
to the web directory. Also, since another copy of the same version, just
with a different connection string, works fine, I don't think this is
the problem.

I tried adding some code to dump the version numbers of the files in
question, as well as paths, etc. and it all matches up to what I expect
for each instance.

Can anyone see a flaw, or know something that could point me in the
right direction? *Anything* would help.
 
L

Lasse Vågsæther Karlsen

Solved!

Bug in the loop at the bottom.

The code essentially did this:

- foreach assembly in appdomain
--- foreach type in assembly
------ if type is to be included
--------- find all properties in *current type*

that was the bug, did not use the type I was currently iterating for,
and minor differences in the databases meant that for some databases one
object was the first to be saved, in other it was another object, which
meant that it used one object as a template for wether *all other*
objects had this special string property or not.

Removed the rest of the code, see the parent post if you really want to
look at it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top