27/06/2010

Słów kilka o ASP.NET, IIS, corflags i opcjach kompilacji

Home

Jakiś czas temu przenosiłem aplikację ASP.NET z środowiska developerskiego do testowego i jak często bywa w takich sytuacjach migracja nie obyła się bez pewnych kłopotów. Przy próbie uruchomienia aplikacji użytkownik otrzymywał informację o tym, że nie udało się załadować jednej z bibliotek. Po chwili zauważyłem, że bezpośrednim winowajcą był wyjątek BadImageFormatException. Z podobnym problem już się spotkałem dlatego szybko skojarzyłem, że przyczyną problemu może być próba załadowania 32 bitowej biblioteki do procesu 64 bitowego (środowisko testowe było 64 bitowe). Dla przypomnienia nie jest możliwe aby proces 64 bitowy korzystał z bibliotek 32 bitowych i na odwrót.

Przyjrzałem się więc bliżej kłopotliwej bibliotece przy pomocy programu corflags (pisałem już o nim w tym poście) i okazało się, że ma ona ustawiona flagę 32BIT wskazującą, że biblioteka może być uruchamiana tylko w trybie 32 bitowym. Sprawdziłem również inne biblioteki ale nie miały ustawione tej flagi. W tym momencie wszystko było już jasne, aplikacja ASP.NET hostowana była przez 64 bitowy serwer i w związku z tym nie mogła skorzystać z biblioteki 32 bitowej. Wyczyściłem flagę, również przy pomocy programu corflags i zgodnie z oczekiwaniami problem ustąpił.

Następnie postanowiłem wyjaśnić przyczynę czemu jedna biblioteka miała ustawioną flagę 32BIT. W tym celu przyjrzałem się ustawieniom projektu w Visual Studio i okazało się, że opcja Platform target ustawiona jest na x86 zamiast na Any CPU jak w innych projektach. W tym momencie przypomniałem sobie, że sam to zrobiłem żeby móc używać funkcji Edit and Continue, a po skończeniu pracy zapomniałem przywrócić odpowiednią konfigurację.

Na koniec pozostaje wyjaśnić czemu aplikacja działała w 64 bitowym środowisku developerskim, a w testowym już nie. Otóż, w środowisku testowym pula aplikacyjna w jakiej została umieszczona aplikacja miała wyłączoną flagę Włącz aplikacje 32 bitowe, która umożliwia hostowanie takich aplikacji na 64 bitowym serwerze IIS. Flaga ta dostępna jest w zaawansowanych ustawieniach puli aplikacji w grupie Ogólne. W środowisku developerskim używałem natomiast serwera zintegrowanego z Visual Studio. Nie jestem tego pewien ale prawdopodobnie ma on domyślnie włączoną tą flagę albo środowisko samo określa czy ta flaga ma być włączona w zależności od ustawień uruchamianych projektów.

Reasumując warto znać narzędzie corflags, opcję konfiguracji projektów Platform target oraz przełącznik Włącz aplikacje 32 bitowe .

16/06/2010

Własne zdarzenia IntelliTrace 2

Home

Dzisiaj, zgodnie z wcześniejszą obietnicą, chciałem pokazać w jaki sposób zdefiniować nowe zdarzenie diagnostyczne dla naszej własnej metody. W tym celu użyję bardzo prostej klasy pokazanej poniżej:

namespace SmallTest
{
    public class Fun
    {
        public void Hello(int count, string msg)
        {
            for (int i = 0; i < count; ++i)
                Console.WriteLine(msg);
        }
    }
}

Przyjmijmy, że klasa ta znajduje się w projekcie o nazwie SmallTest po skompilowaniu, którego powstanie plik SmallTest.dll. Skoro mamy już z czym pracować przystąpmy do modyfikacji pliku ColllectionPlan.xml. Cały proces będzie bardzo podobny do tego co pokazałem w poprzednim poście. Zaczynamy od znalezienia węzła o nazwie ModuleList i umieszczamy pod nim węzeł wskazujący na naszą bibliotekę:

  <ModuleSpecification Id="SmallTest">SmallTest.dll</ModuleSpecification>

Co istotne biblioteka nie musi być podpisana, ani znajdować się w jakimś konkretnym katalogu. Następnie tworzymy nową kategorię dla zdarzeń. W tym celu pod węzłem Categories powinniśmy umieścić pokazany poniżej węzeł XML. Jeśli nie chcemy tworzyć nowej kategorii możemy pominąć ten krok.

  <Category Id="my" _locID="category.My">My</Category>

Na koniec najważniejsza rzecz, zdefiniowanie nowego zdarzenia. Postępujemy dokładnie tak samo jak przy definiowaniu zdarzenia dla metody platformy .NET. Potrzebny kod XML został pokazany poniżej. Umieszczamy go pod węzłem DiagnosticEventSpecifications. Jeśli w poprzednim kroku nie tworzyliśmy nowej kategorii wartość węzła CategoryId powinna odpowiadać nazwie innej, już istniejącej kategorii.

    <DiagnosticEventSpecifications>
      <DiagnosticEventSpecification>
        <CategoryId>my</CategoryId>
        <SettingsName _locID="settingsName.Fun.Hello">Fun.Hello</SettingsName>
        <SettingsDescription _locID="settingsDescription.Fun.Hello">Fun.Hello</SettingsDescription>
        <Bindings>
          <Binding>
            <ModuleSpecificationId>SmallTest</ModuleSpecificationId>
            <TypeName>SmallTest.Fun</TypeName>
            <MethodName>Hello</MethodName>
            <MethodId>SmallTest.Fun.Hello(System.Int32, System.String):System.Void</MethodId>
            <ShortDescription _locID="shortDescription.Fun.Hello">Fun.Hello({0},{1})</ShortDescription>
            <LongDescription _locID="longDescription.Fun.Hello">Fun.Hello(count={0},msg={1})</LongDescription>
            <DataQueries>
              <DataQuery index="1" maxSize="0" type="Int32" _locID="dataquery.Fun.Hello.count" _locAttrData="name" name="count" query="" />
              <DataQuery index="2" maxSize="256" type="String" _locID="dataquery.Fun.Hello.msg" _locAttrData="name" name="msg"  query=""></DataQuery>
            </DataQueries>
          </Binding>
        </Bindings>
      </DiagnosticEventSpecification>

Szczegółowy opis znaczenia poszczególnych węzłów XML użytych w tej definicji podałem w poprzednim poście, a więc nie będę go tutaj powielał. Uruchamiany Visual Studio i jeśli nie popełniliśmy żadnego błędu możemy już korzystać z nowego zdarzenia. W celu sprawdzenia czy wszystko jest w porządku najpierw zaglądamy do Tools->Options->IntteliTrace->IntteliTrace Events. Powinniśmy zobaczyć nową kategorię, a po jej rozwinięciu nowe zdarzenie:



Teraz możemy stworzyć nowy projekt konsolowy i dodać referencję to biblioteki SmallTest. Kiedy to zrobimy, nie pozostaje nic innego jak utworzyć obiekt klasy Fun i wywołać metodę Hello:

            Fun f = new Fun();
            f.Hello(2, "Hello world!");

Po skompilowaniu i uruchomieniu programu pod kontrolą debugger'a i z włączonym mechanizmem IntteliTrace w oknie z zarejestrowanymi zdarzeniami zobaczymy nasze zdarzenie:



W następnym poście pokażę w jaki sposób analizować wystąpienia zdarzeń w sposób programowy.