18

I am creating asp.net web service. I have one class, whose static constructor is not getting called when I try to initialize object of that class. I am not able to understand this behavior. Inside static constructor I am reading values from web.config file.

Here is part of code :

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
    AppController extractor;

    public Service()
    {
        try
        {
            extractor = new AppController();
        }
        catch(Exception ex)
        {
            // I am not getting exception at this point.
        }
    }
}

public class AppController
{
    static string converterBatchFilePath = null;
    static string personalProfileOutputFolderPath = null;

    static AppController()
    {
        // reading some settings from web.config file
        try
        {
            converterBatchFilePath = ConfigurationManager.AppSettings["WordToTextConverterBatFilePath"];
        }
        catch(Exception ex)
        { // }
    }
    public AppController()
    {
        // do some initialization
    }
}

While debugging web service I noticed that only instance constructor is getting called and control never goes to static constructor.

Anyone know why this is happening?

I am using VS 2008 Express edition and C#.

EDIT

Actually this AppController is console based project. I have added that project as a reference inside Web service project and then using it. If I use AppController from command line, it works fine, but its not working from inside web service project.

Shekhar
  • 11,438
  • 36
  • 130
  • 186
  • 3
    I suspect your diagnostics are wrong - can you produce a short but complete program which demonstrates this occurring? – Jon Skeet Sep 13 '11 at 10:37
  • Very strange. Are you sure it's not your test that's flawed? – CodesInChaos Sep 13 '11 at 10:39
  • Works fine for me, the static constructor is called in a simple example. If the observable behaviour of the constructor not being called is something to do with the config, I'd guess the error is with the config stuff instead. – Adam Houldsworth Sep 13 '11 at 10:39
  • There are private static string type variables in AppController class. Is it happening because I have initialized those variable to null at declaration time? – Shekhar Sep 13 '11 at 10:40
  • @sll but it should be called, bcoz according to MSDN static constructor is called when either first instance of class is initialized or any static method is called – Waqas Sep 13 '11 at 10:40
  • 2
    One thing I'd try is (temporarily) putting the content of `static AppController` into a try...catch and display/log the exception. – CodesInChaos Sep 13 '11 at 10:41
  • yep, most probably exception in `static AppController()` – driushkin Sep 13 '11 at 10:44
  • dup of http://stackoverflow.com/questions/2925611/static-constructor-can-run-after-the-non-static-constructor-is-this-a-compiler-b – V4Vendetta Sep 13 '11 at 10:47
  • Why do you say "control never goes to static ctor"? Is it because a breakpoint isn't hit or because values (that should be set there) are wrong (empty)? – Hans Kesting Sep 13 '11 at 10:53
  • @Hans Kesting, for both reasons. static constructor of AppController class reads values from web.config file. These Static member variables were not getting Values. So I put debug point at the first sentence inside static constructor and inside instance constructor. Program control directly went to debug point inside instance constructor. – Shekhar Sep 13 '11 at 10:55
  • @V4V I disagree. That other question is special because you construct an instance inside a static field initializer of the same class. So in essence the static construction is already in progress when the constructor gets called. And field initializers run before the static constructor. This does not seem to be the case here. – CodesInChaos Sep 13 '11 at 10:56
  • @Shekhar do you have any non-trivial static field initializers? – CodesInChaos Sep 13 '11 at 10:57
  • It called at first call of static class. for example when you call a method from static class (for first time) it first calls static constructor. – Mahdi Ataollahi Jun 22 '17 at 13:02

6 Answers6

22

Today my static initializer was not being called. It turns out static initializers are not called prior to accessing const members of a class.

Since const values are known at compile time this makes sense, but it means that the documentation which states "It is called automatically before ... any static members are referenced" is technically incorrect, at least when combined with @JonSkeet's assertion that "All constants declarations are implicitly static".

This program demonstrates the problem:

using System;

static class Program
{
    public static void Main()
    {
        Console.WriteLine("Constant={0}", Problem.Constant);
        Console.WriteLine("ReadOnly={0}", Problem.ReadOnly);
        Console.WriteLine("Field={0}", Problem.Field);
        Console.WriteLine("Property={0}", Problem.Property);
    }

    private static class Problem
    {
        public const int Constant = 1;
        public static readonly int ReadOnly = 2;
        public static int Field = 3;
        private static int mProperty = 4;
        public static int Property { get { return mProperty; } }

        static Problem()
        {
            Console.WriteLine("Problem: static initializer");
        }
    }
}

The output is:

Constant=1
Problem: static initializer
ReadOnly=2
Field=3
Property=4

(Tested against .NET 4.5.)

yoyo
  • 8,310
  • 4
  • 56
  • 50
  • 5
    I observed the same behavior as described here. It is very confusing and contradicts documentation. – Boris Zinchenko Apr 23 '16 at 13:34
  • Const is a keyword to declare a compile time constant. It doesn't ever exist as a variable in memory. Also why you need to call a special method in reflection to get the value since it actually has to instanciate a new instance to hold the value. You can also see this by looking at the IL code created for you function. The .Constant is replaced by a verbatim 1. – Cine Aug 16 '21 at 08:42
21

My guess is that it's called before you expected it to be called. If you have already debugged your site but not recycled the AppPool, it's very likely that the static constructor has already been run. Similarly anything that accesses any static members will also call the static constructor if it hasn't already been called.

J0e3gan
  • 8,740
  • 10
  • 53
  • 80
Rune FS
  • 21,497
  • 7
  • 62
  • 96
  • 2
    you were right. Application development Server was already running. I stopped it and started web service again. Now its working fine. Thanks a million !!!! – Shekhar Sep 13 '11 at 10:58
  • 1
    @Shekhar the behaviour of static variables in relation to AppDomain/process is more pronouced in IIS, as IIS can recycle processes whenever, meaning static variables get recycled too. – Adam Houldsworth Sep 13 '11 at 10:59
  • @Adam, how do recycling of processes will affect static variables? Do you know any reading material/book/blog where I can get more information about it? – Shekhar Sep 13 '11 at 11:06
  • 1
    @Shekhar it appears to be related to just AppDomains: http://bytes.com/topic/c-sharp/answers/757645-static-variable-lifetime-webservice – Adam Houldsworth Sep 13 '11 at 11:17
  • Four years later, *still* helping people with this answer. – T.J. Crowder Jul 01 '15 at 17:44
3

A static constructor is used to initialize any static data, or to perform a particular action that needs performed once only. It is called automatically before the first instance is created or any static members are referenced.

Please note that a static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced. and the user has no control on when the static constructor is executed in the program.

Taken from MSDN's Static Constructors (C# Programming Guide) .

Sandeep Pathak
  • 10,567
  • 8
  • 45
  • 57
  • 14
    That doesn't explain how the instance constructor could be called without the static constructor ever getting called... – Jon Skeet Sep 13 '11 at 10:42
  • This just shows that it should be called(Since an instance was created the static constructor is guaranteed to have run), but doesn't explain the behavior the OP observes. – CodesInChaos Sep 13 '11 at 10:43
  • To be honest I think the underlying implication is that the OP has not diagnosed the problem correctly. – Adam Houldsworth Sep 13 '11 at 10:44
  • @CodeBuzz, I agree that user has no control on when the static constructor is gets executed, but normally when I debug any program using Visual Studio and put debug point inside static constructor, execution stops on that line and I am able to debug the code inside that static constructor. This is not happening now. – Shekhar Sep 13 '11 at 10:44
  • 1
    @Shekhar a number of things can stop breakpoints from being hit, such as some of the debugging attributes available, or VS settings. I created a blank project with nothing in the constructors and my static constructor is called OK, C# 4, .Net 4, VS 2010. – Adam Houldsworth Sep 13 '11 at 10:47
  • @Shekhar : Ok I agree with the fact , but it might happen that you were initializating the class on one service and not in the other. – Sandeep Pathak Sep 13 '11 at 10:49
  • Indeed, that was the answer for me - I was wondering why a static constructor wasn't being called in my web service. Answer is, it was being called somehow before VS had a chance to attach. Added Debugger.Break(), then my breakpoint in the constructor started working. – neminem Mar 12 '13 at 21:32
3

I suspect that your problem is caused by an exception being raised in your static constructor and being swallowed by the code that creates the instance.

Potentially even an exception in a static field initializer which are even harder to debug.

Perhaps enabling breaking on first-chance exceptions helps debugging the problem.


I would not put code that reads from a config file into a static constructor at all. I'd instead encapsulate all config dependent stuff you have in a class and pass an instance of that class into your constructor, probably using an IoC container.

This has a number of advantages:

  • You can use different configurations in the same AppDomain at the same time
  • You can use alternate ways of loading the configuration
  • You don't need to do complex stuff that might fail in a static constructor. As you have seen static constructors tend to be problematic to debug, so I'd do only simple initializations that don't depend on external state there

(I know this is not an answer, but it's too long for a comment)

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
1

When I was trying to debug by placing a breakpoint on the line where the static field had referenced, I was not getting debug control on the static constructor.

I kept breakpoint on the static constructor entrance, removed the breakpoint from the line where the static field had referenced. Now Debug control started coming into the static constructor code.

This image shows how your editor with breakpoints would look like

DSR
  • 592
  • 5
  • 14
1

Here's a quick sample I put together to get values from a config file in your extractor class, both in the static and instance constructors. This works for me -- compare it against what you're doing and see what's different:

public class Service : System.Web.Services.WebService
{
    AppController extractor;

    [WebMethod]
    public string HelloWorld()
    {
        extractor = new AppController();
        return AppController.staticString + " :: " + extractor.instanceString;
    }
}

class AppController
{
    public static string staticString;
    public string instanceString;

    static AppController()
    {
        staticString = System.Configuration.ConfigurationManager.AppSettings["static"];
    }
    public AppController()
    {
        instanceString = System.Configuration.ConfigurationManager.AppSettings["instance"];
    }
}

My web.config:

  <appSettings>
    <add key="static" value="blah blah"/>
    <add key="instance" value="ha ha"/>
  </appSettings>

My response:

<?xml version="1.0" encoding="UTF-8"?>
<string xmlns="http://tempuri.org/">blah blah :: ha ha</string>
David Hoerster
  • 28,421
  • 8
  • 67
  • 102