473,387 Members | 1,583 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Static Constructor Called Twice

I'm having a problem with a static class constructor being called twice. I
have the static class MasterTaskList which uses a BackgroundWorker to execute
multiple methods on a separate thread. The static constructor calls a reset
function which creates a new instance of BackgroundWorker and attaches the
appropriate event handlers. There is also a static method ReportProgress for
the called methods to do just that.

What is happening is that the static class is initialized the first time,
functions are added to the list to be executed, the BackgroundWorker is
started, and one of the methods called by the BackgroundWorker's thread calls
MasterTaskList.ReportProgress(). This access of the MasterTaskList class
causes the static constructor to be called again. See below for the callstack
from the second call to the static constructor.

What I can't fathom is how it is possible for a static method from a static
class to appear in the callstack for a static constructor.

Here's a couple of other twists:

1) This only happens when the calls are made by a Windows service. Identical
calls in a regular Windows app work fine.

2) The call to ReportProgress() that does this isn't the first time it's
called within the scope of
Master.Common.Task.MasterTaskList.InternalCalculat ion(). It is the first time
it's called within Master.Bar.Calculation.Foo.FooCalculation.LoadData ()

3) The static constructor sets the BackgroundWorker instance of
MasterTaskList to a new BackgroundWorker. The original BackgroundWorker
continues to run, but doesn't fire it's RunWorkerCompleted event when
finished.

4) I can attach to this process running as a Windows service and step
through to right before it calls the static constuctor again. Using
Quickwatch, I can see that the MasterTaskList it's about to call is already
initialized. After it's called, the events in the class all get disconnected
and the only thing left running is the stranded BackgroundWorker thread.

This one has left me scratching my head.

Thanks for any help in advance,
Matt
Here is the call stack from the static constructor:

at Master.Common.Task.MasterTaskList..cctor()
at Master.Common.Task.MasterTaskList.ReportProgress()
at Master.Bar.Calculation.Foo.FooCalculation.LoadData (Object sender,
EventArgs e)
at Master.Bar.BarMaster.LoadData(Object sender, EventArgs e)
at Master.Common.Task.MasterTaskList.ExecuteTask(Mast erTask currentTask)
at Master.Common.Task.MasterTaskList.InternalCalculat ion(Object sender,
DoWorkEventArgs e)
at System.ComponentModel.BackgroundWorker.OnDoWork(Do WorkEventArgs e)
at System.ComponentModel.BackgroundWorker.WorkerThrea dStart(Object
argument)
at
System.Runtime.Remoting.Messaging.StackBuilderSink ._PrivateProcessMessage(IntPtr
md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext,
Object[]& outArgs)
at
System.Runtime.Remoting.Messaging.StackBuilderSink .PrivateProcessMessage(RuntimeMethodHandle
md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext,
Object[]& outArgs)
at
System.Runtime.Remoting.Messaging.StackBuilderSink .AsyncProcessMessage(IMessage msg, IMessageSink replySink)
at
System.Runtime.Remoting.Proxies.AgileAsyncWorkerIt em.ThreadPoolCallBack(Object o)
at System.Threading._ThreadPoolWaitCallback.WaitCallb ack_Context(Object
state)
at System.Threading.ExecutionContext.Run(ExecutionCon text
executionContext, ContextCallback callback, Object state)
at System.Threading._ThreadPoolWaitCallback.PerformWa itCallback(Object
state)

Aug 7 '07 #1
6 7213
Matt <in***************@nospam.nospamwrote:
I'm having a problem with a static class constructor being called twice. I
have the static class MasterTaskList which uses a BackgroundWorker to execute
multiple methods on a separate thread. The static constructor calls a reset
function which creates a new instance of BackgroundWorker and attaches the
appropriate event handlers. There is also a static method ReportProgress for
the called methods to do just that.
This does indeed look a bit odd. A few questions:

1) Is it definitely a static constructor as opposed to a type
initializer created by static variable initializers in your static
class?

2) Are multiple AppDomains involved at all? Don't forget that each
static constructor is called once per type *per AppDomain*. If somehow
MasterTaskList.ReportProgress from AppDomain A is using MasterTaskList
from AppDomain B, that would sort of explain things.

3) Can you reproduce it in a short but complete program?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that. I know that being a Windows Service will make this
harder, but it would really be useful for debugging...

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Aug 7 '07 #2
1) Nope, it's the following:

static MasterTaskList()
{
Trace.WriteLine("Static Constructor");
Trace.WriteLine(AppDomain.CurrentDomain.FriendlyNa me);
Trace.WriteLine(new StackTrace());
ResetWorker();
}

And I can tell by the field values before and after the call that the second
call does initialize the static fields as well. If it didn't, I could just
call ResetWorker manually and not care how many times it calls the static
constructor. It's the wiping of my events that's a problem.

2) As you can see from the code above, I thought of that too, and nope, it's
all still in the AppDomain of the service.

3) I'll start working on the sample, but it looks like it's not going to be
very short. I have a windows service which references an assembly that loads
other assemblies using reflection and then adds methods in those assemblies
to the list that the BackgroundWorker executes. At the least that's 4 dlls
and a service. I'll see if I can get it to do the same without all of that
structure, but it might be something about that structure that causes this.

Thanks for the quick reply,
Matt
Aug 7 '07 #3
Matt <in***************@nospam.nospamwrote:
1) Nope, it's the following:

static MasterTaskList()
{
Trace.WriteLine("Static Constructor");
Trace.WriteLine(AppDomain.CurrentDomain.FriendlyNa me);
Trace.WriteLine(new StackTrace());
ResetWorker();
}

And I can tell by the field values before and after the call that the second
call does initialize the static fields as well. If it didn't, I could just
call ResetWorker manually and not care how many times it calls the static
constructor. It's the wiping of my events that's a problem.
Right. As a short-term hacky fix, you could always keep a boolean value
to keep track of whether or not it's already been called, and just
return quickly if this isn't the first call.
2) As you can see from the code above, I thought of that too, and nope, it's
all still in the AppDomain of the service.
Hmm. Very puzzling.
3) I'll start working on the sample, but it looks like it's not going to be
very short. I have a windows service which references an assembly that loads
other assemblies using reflection and then adds methods in those assemblies
to the list that the BackgroundWorker executes. At the least that's 4 dlls
and a service. I'll see if I can get it to do the same without all of that
structure, but it might be something about that structure that causes
this.
It's probably worth taking a backup of the "real" one and gradually
hacking stuff out. That way you'll either end up finding out which bit
causes the problem, or getting down to a much smaller sample app.

If it ends up being too big to post, you could always mail it to me or
put it on a download site.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Aug 7 '07 #4
I got the test program to call the static constructor twice. What made it do
it was changing Environment.CurrentDirectory so that it's running in a
different directory than the WindowsService.exe. It's still in the same
AppDomain and the directory doesn't change after the first call to the
constructor, but it still calls it twice.

I'll trim back the sample code and post it soon.
Aug 8 '07 #5
Hi Matt,

If you will send the code via email, please also send a copy to me. Thanks.
Regards,
Walter Wang (wa****@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

Aug 8 '07 #6
On Aug 8, 12:58 am, Matt <inventorydynam...@nospam.nospamwrote:
I got the test program to call the static constructor twice. What made it do
it was changing Environment.CurrentDirectory so that it's running in a
different directory than the WindowsService.exe. It's still in the same
AppDomain and the directory doesn't change after the first call to the
constructor, but it still calls it twice.

I'll trim back the sample code and post it soon.
I've managed to reproduce it in a console application. The code is at
the bottom of this post. In short, it consists of two assemblies:
Plugin.dll and Test.exe.
Plugin.dll reference Test.exe, but not the other way round.
Test.exe contains a Helper class with a static constructor.
Test.exe creates a fresh directory, and takes a list of assembly files
from the command line.
One at a time, it performs the following steps:
1) Copy the file into the directory
2) Load the assembly using Assembly.LoadFrom
3) Try to find a type called "Plugin"
4) If the type exists, create an instance and call its Plug method
with reflection

The Plugin type in Plugin.dll calls a static method in Helper.

The results are that if you run:
test test.exe plugin.dll
you see the Helper static constructor twice. If you run
test plugin.dll test.exe
then you only see the Helper static constructor once.

In the first case, when the JIT tries to resolve Helper for Plugin, it
finds that there are two copies loaded. It uses the second copy, I
*believe* that's because it notices that the second copy was loaded
from the same directory as Plugin itself.

In the second case, when the JIT tries to resolve Helper for Plugin,
only one copy of Helper has been loaded at that point, so the existing
type is reused, and the static constructor isn't called again.

Basically, anything using Assembly.LoadFrom needs to be pretty
careful :)

Here's the code:

----------------- Test.cs ---------------------
using System;
using System.IO;
using System.Collections.Generic;
using System.Reflection;

public class Helper
{
static Helper()
{
Console.WriteLine ("Helper static constructor");
}

public static void Print(string x)
{
Console.WriteLine (x);
}
}

public class Program
{
const string PluginDirectory = "Plugins";

static void Main(string[] args)
{
Helper.Print("Starting");
if (Directory.Exists(PluginDirectory))
{
Directory.Delete(PluginDirectory, true);
}
Directory.CreateDirectory(PluginDirectory);

foreach (string x in args)
{
string target = Path.Combine(PluginDirectory, x);
File.Copy(x, target);
Assembly ass = Assembly.LoadFrom(target);
Type pluginType = ass.GetType("Plugin");
if (pluginType != null)
{
object plugin = Activator.CreateInstance(pluginType);
pluginType.GetMethod("Plug").Invoke(plugin, null);
}
}
}
}

----------------------- Plugin.cs ---------------------
public class Plugin
{
public void Plug()
{
Helper.Print("Hello");
}
}
Hope that helps,
Jon

Aug 8 '07 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
by: Bob Rock | last post by:
Hello, I was wondering when should static constructors be defined or are they even required??? Also, when are they implicitly called??? Bob Rock
6
by: Robert | last post by:
Hello all... In my code below, the Notify Constructor and Destructor is getting called twice and it appears that a new Notify object is created on the 2nd call. The 2nd call is caused by this...
7
by: ank | last post by:
Hi, I was curious about how to define static data member of template class. Should I put the definition in a separate source file or in the same header file as its template class? And when this...
3
by: Alexander Stippler | last post by:
Given the following code snippet we get some unexpected behaviour: //-------------------------------------------------------------------- #include <iostream> using namespace std; struct A {...
3
by: Kirk Marple | last post by:
Just want to see if this is 'by design' or a bug... I have a common List<T> defined in a base class, and the base class has a static property to expose this list. I wanted the derived class to...
1
by: Arnaud Debaene | last post by:
Hello, I think I found a bug in VC 7.1 concerning destruction of stack objects when linking a static, non managed, C++ library within a managed C++ application. Here is a repro case : 1)...
12
by: Hemanth | last post by:
Hi, I have a base class with a static constructor and some abstract methods. Derived classes implement these methods. From articles on the web, it appears that there is no guarentee that this...
8
by: Jeff Brown | last post by:
I understand that a static constructor is not called until and unless the class is instantiated, or any of its static members are referenced. But suppose (for the sake of argument) a class is...
11
by: Rimpinths | last post by:
I'm new at developing user controls in C#, and one thing I've noticed right off the bat is that the constructor gets called twice -- once at design time, once at run time. In short, I'm trying...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.