poniedziałek, 22 października 2012

Multicore JIT

Aplikacje oparte o platformę .NET podczas uruchomienia muszą zostać skompilowane przez wirtualną maszynę. Kompilacja w przypadku dużej aplikacji może zająć więcej, niż życzyłby sobie tego użytkownik. Jednym z rozwiązań tego problemu jest Ngen.exe - generowany kod jest przerzucony z fazy uruchomienia do instalacji. Rozwiązanie ma to jednak jedną wadę - nadaje się tam, gdzie aplikacja posiada instalator. Innym problemem może być niedostępność tego narzędzia.
W nowym .NET 4.5 wprowadzono Multicore JIT - kompilacja odbywa się na dwóch procesorach. Przyrost w przypadku średnich aplikacji waha się w granicach 20 - 50%. Im większa aplikacja tym większy procent przyśpieszenia.
Jak wygląda w praktyce nowość? Dla przeglądarki Bing osiągnięto rezultat na poziomie 50% (więcej na stronie http://blogs.technet.com/b/windowsserver/archive/2012/06/07/bing-com-runs-on-windows-server-2012.aspx).
Wyniki z innych aplikacji:


W przypadku aplikacji Paint.Net na poniższym wykresie możemy zobaczyć jak zmieniło się zużycie zasobów procesora z i bez Multicore JIT:


W jaki sposób działa Multicore JIT?
Multicore JIT działa w dwóch fazach: nagrywania i odtwarzania. Podczas nagrywania kompilator JIT nagrywa każdą metodę, która jest wywoływana. Kiedy środowisko CLR stwierdzi, że uruchomienie programu zostało zakończone zapisywany jest na dysku profil, zawierający wszystkie uruchomione metody. 


Podczas pierwszego uruchamiania aplikacji wykorzystywane jest nagrywanie. Podczas kolejnych uruchomień aplikacji wczytywany jest z dysku zapisany profil, a uzyskane z niego informacje służą do kompilacji kodu w tle, jeszcze przed jego zażądaniem przez główny wątek.






Rezultatem tych operacji jest poprawienie szybkości uruchamiania aplikacji na maszynach wielordzeniowych - w przypadku stacji wyposażonych w jeden procesor technologia ta jest wyłączona.


Co należy zrobić aby mechanizm działał w mojej aplikacji?
W przypadku aplikacji desktopowych należy dodać w konstruktorze aplikacji następujące instrukcje:


Code:
public App() 
{
    ProfileOptimization.SetProfileRoot(@"C:\MyAppFolder");
    ProfileOptimization.StartProfile("Startup.Profile");
}  

  • SetProfileRoot - determinuje gdzie będą zapisywane nagrane profile
  • StartProfile  - uaktywania Multicore JIT poprzez podanie nazwy profilu
W przypadku ASP.NET sprawa jest jeszcze prostsza i sprowadza się do ustawienia flagi profileGuidedOptimizations:
Code:
<?xml version="1.0" encoding="utf-8" ?> 
<configuration>
 <!-- ... -->
 <system.web> 
 <compilation profileGuidedOptimizations="None" /> 
 <!-- ... --> 
 </system.web> 
</configuration>

poniedziałek, 15 października 2012

O interfejsach raz jeszcze

O interfejsach napisano już wiele artykułów. Postaram się dlatego podejść do tego zagadnienia od innej strony.
Na początek pytanie: czym różni się metoda wirtualna od implementacji metody z interfejsu?
Mogło by się zdawać, że są to bardzo podobne operacje. Dostarczamy definicję metody zadeklarowanej w innym typie. W interfejsie metoda nie jest wirtualna - przynajmniej nie domyślnie. Klasy dziedziczące po klasie, która implementuje interfejs nie mogą nadpisywać metod zaimplementowanych w klasie bazowej.
Tutaj jest jeden haczyk - można tak zaimplementować metody interfejsu aby istniała możliwość ich nadpisania w klasach potomnych.

Zobaczmy na prosty przykład:

Code:
    public interface IAnimal
    {
        void Voice();
    }


Code:
    public class Animal : IAnimal
    {
        public void Voice()
        {
            Console.WriteLine("Animal");
        }
    }


Code:
    public class Cat : Animal
    {
        public void Voice()
        {
            Console.WriteLine("Cat");
        }
    }

Wywołanie funkcji w mainie:

Code:
        static void Main(string[] args)
        {
            var cat = new Cat();
            cat.Voice();
            var animal = cat as IAnimal;
            animal.Voice();
        }

Efekt który można przewidzieć:

Code:
Cat
Animal

Zdarza się jednak, że chcemy w potomnych klasach przedefiniować funkcję implementowaną z interfejsu w klasie bazowej. Mamy dwie możliwości. Jeżeli nie mamy dostępu do klasy bazowej możemy zaimplementować interfejs w klasie dziedziczącej:

Code:
    public class Cat : Animal, IAnimal
    {
        public new void Voice()
        {
            Console.WriteLine("Cat");
        }
    }


Wynik:

Code:
Cat
Cat

Jednak wersja bazowa jest nadal dostępna:


Code:
            var cat = new Cat();
            cat.Voice();
            var animal = cat as IAnimal;
            animal.Voice();
            var animalBaseClass = cat as Animal;
            animalBaseClass.Voice();


Wynik:

Code:
Cat
Cat
Animal

Jedną z metod naprawienia tego problemu jest zadeklarowanie metody Voice w klasie bazowej jako wirtualnej, a następnie w klasie dziedziczącej nadpisanie tej metody:

Code:
    public class Animal : IAnimal
    {
        public virtual void Voice()
        {
            Console.WriteLine("Animal");
        }
    }

    public class Cat : Animal, IAnimal
    {
        public override void Voice()
        {
            Console.WriteLine("Cat");
        }
    }

Wynik:
Cat
Cat
Cat

Możemy iść dalej i klasę bazową zadeklarować jako abstrakcyjną (tak można zaimplementować interfejs bez implementacji jego metody):

Code:
    public abstract class Animal : IAnimal
    {
        public abstract void Voice();
    }

Klasa dziedzicząca może następnie zapobiec przeładowywaniu metody Voice w kolejnych potomnych klasach:

Code:
    public class Cat : Animal, IAnimal
    {
        public sealed override void Voice()
        {
            Console.WriteLine("Cat");
        }
    }


Ostatni aspekt. Jeżeli dziedziczymy po klasie bazowej, która implementuje interfejs, dziedzicząca także ma zadeklarowaną implementację w sygnaturze to w dziedziczącej nie musimy implementować metody:

Code:
    public class Cat : Animal, IAnimal
    {
        //empty
    }


Interfejsy pozwalają na abstrakcyjną, wirtualną i zamkniętą implementację. Daje to dużą elastyczność w przypadku tworzenia hierarchii klas.

niedziela, 14 października 2012

Zarządzanie pamięcią w .NET

Artykułów na temat Garbage Collector zostało napisanych już wiele. Dlatego nie będę przedstawiać dokładnie zasady jego działania, a raczej praktyczne wskazówki implementacji finalizerów i wzorca IDisposable.
Garbage Collector podczas swojego cyklu wykonuje następujące czynności
  • sprawdza czy dany obiekt jest przypisany do referencji
  • defragmentuje zarządzaną stertę
  • wolne miejsce scala do jednego bloku pamięci
Finalizery to defensywna metoda dopilnowania, aby pamięć została zwolniona nawet wtedy, kiedy użytkownik zapomni wywołać metody Dispose. Finalizery są wywoływane przez Garbage Collector po usunięciu obiektu z pamięci. Moment wywołania finalizera nie jest deterministyczny.
Finalizery obniżają wydajność aplikacji. Gdy GC otrzyma zadanie usunięcia obiektu, który posiada finalizer nie zrobi tego od razu. Najpierw musi zostać wywołany finalizer. Wywołanie go nie odbywa się w tym samym wątku co działania GC. Obiekt taki trafia do kolejki obiektów, którym należy wywołać finalizera. GC nie przerywa w tym momencie swojej pracy. Przy następnym wywołaniu GC obiekty z wywołanym finalizerem zostają usunięte z pamięci. Wydawałoby się iż obiekty posiadające finalizer trwają w pamięci o jeden cykl więcej niż ich odpowiednicy bez niego. Tak nie jest. GC pracuje z tzw. generacjami. Jest ich 3: zerowa, pierwsza i druga. Każdy obiekt który przetrwał 1 cykl oczyszczania trafia do pierwszej generacji, obiekt który przetrwał 2 cykle lub więcej trafia do drugiej generacji.Tak więc:
  • generacja 0 - przeważnie zmienne lokalne
  • generacja 1 lub 2 - zmienne globalne
 GC optymalizuje swoją pracę poprzez ograniczenie czyszczenia 1 i 2 generacji. W każdym cyklu czyszczona jest generacja 0, jednak tylko raz na 10 cykli jest czyszczona generacja 1, a raz na 100 wszystkie generacje. Obiekt zwierający finalizer może więc przebywać o 9 cykli więcej niż taki, który go nie zawiera.
Rozwiązaniem jest poprawna implementacja wzorca IDisposable. Nic jednak nie pomoże tak GC, jak unikanie niepotrzebnego tworzenia obiektów. Przykładem złego tworzenia obiektów jest napisana poniżej funkcja OnPaint:

Code:
        protected override void OnPaint(PaintEventArgs e)
        {
            using (var font = new Font("Verdana", 10.0f))
            {
                e.Graphics.DrawString("Ala ma kota",
                font, Brushes.Black, new PointF(0, 0));
            }
            base.OnPaint(e);
        }

Metoda OnPaint wywoływana jest wielokrotnie podczas działania programu. Za każdym razem tworzony będzie obiekt czcionki (Font). W takim przypadku warto wyciągnąć tworzenie czcionki na zewnątrz funkcji:

Code:
        Font font = new Font("Verdana", 10.0f);
        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.DrawString("Ala ma kota", font, Brushes.Black, new PointF(0, 0));
            base.OnPaint(e);
        }

Warto zauważyć tutaj także użycie klasy Brushes. Klasa ta może być wykorzystywana w dowolnym miejscu programu. Każdy kolor w tej klasie jest tworzony jako singleton. Nie jest więc tworzony odrębny obiekt pędzla a korzystamy z jednego dostępnego dla całego programu.
Kolejnym przykładem złego tworzenia obiektów jest łączenie długich stringów. Jeżeli łączymy wiele stringów należy stworzyć obiekt typu StringBuilder i za pomocą niego dokonać operacji na łańcuchu.

W przypadku hierarchii klas, klasa bazowa powinna implementować interfejs IDisposable. Dodatkowo implementujemy finalizer na przypadek gdy użytkownik zapomni zwolnić zasoby. Jeżeli klasa potomna także alokuje zasoby, które muszą zostać zwolnione, musi także implementować interfejs IDisposable oraz dodatkowo wywołać implementację z klasy bazowej.
Implementacja IDisposable musi spełnić 4 założenia:
  1. uwolnienie zasobów nie zarządzanych
  2. uwolnienie zasobów zarządzanych (np. uchwyty zdarzeń)
  3. ustawienie flagi mówiącej, że obiekt został zwolniony. W publicznych metodach powinno nastąpić sprawdzenie flagi i w przypadku jej ustawienia rzucenie wyjątku ObjectDisposedException
  4. Zapobiegnięcie finalizacji obiektu - wywołanie funkcji GC.SuppressFinalize(this) 
Dwa pierwsze punkty eliminuje implementuje IDisposable. Mechanizm będzie nadal posiadał luki:
W jaki sposób klasy potomne wyczyszczą swoje zasoby, a zarazem pozwolą klasie bazowej posprzątać po sobie? Jeżeli klasy dziedziczące nie wywołają czyszczenia z klasy bazowej zasoby nigdy nie zostaną zwolnione. Aby zwolnić te zasoby tworzymy wirtualną metodę Dispose, o następującej sygnaturze:

Code:
protected virtual void Dispose(bool isDisposing)

klasy potomne nadpisują tę metodę a na końcu wywołują wersję z klasy bazowej. W zależności od wartości parametru idDisposing:
  • TRUE - czyścimy zarówno zasoby zarządzane jak i nie zarządzane
  • FALSE - tylko zasoby nie zarządzane
Przykład:

Code:
    public class A : IDisposable
    {
        private bool isDisposed = false;

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool isDisposing)
        {
            if (isDisposed)
            {
                return;
            }
            if (isDisposing)
            {
                //usuwamy zasoby zarządzane
            }

            //czyszczenie zasobów nie zarządzanych

            isDisposed = true;
        }

        public void Method()
        {
            if (isDisposed)
            {
                throw new ObjectDisposedException("A");
            }
        }

        ~A()
        {
            Dispose(false);
        }
    }


Code:
    public class B : A
    {
        private bool isDisposed = false;
        protected override void Dispose(bool isDisposing)
        {
            if (isDisposed)
            {
                return;
            }
            if (isDisposing)
            {
                //czyszczenie zasobów zarządzanych
            }
            //czyszczenie zasobów niezarządzanych

            base.Dispose(isDisposing);
            isDisposed = true;
        }
    }

Warto zauważyć, że flaga jest powielona - zarówno klasa bazowa jak i dziedzicząca ją posiada. Zapobiega to niepoprawnemu zwalnianiu zasobów tylko dla jednego typu.
Finalizer do klasy dodajemy tylko wtedy kiedy kod zawiera zasoby niezarządzane. W powyższym przypadku nie musiał zostać zdefiniowany, wręcz brak jego definicji wpłynie bardzo pozytywnie na wydajność.
Ważne jest także, aby operacja zwalniania nie wykonywała żadnych innych operacji niż tych do które jest przewidziana. Implementacja innych operacji niż tych które czyszczą pamięć, może dojść do niechcianego odtworzenia obiektu.

sobota, 13 października 2012

Pułapki podczas implementacji GetHashCode

Funkcja GetHashCode używana jest tylko i wyłącznie w przypadku korzystania z kolekcji typu klucz wartość jak HashSet<T> lub Dictionary<T1, T2>.
Funkcja ta nie jest tak oczywista jak się to zdaje i napisanie poprawnej jej wersji sprawia wiele problemów. Tworząc własny typ powinniśmy unikać jej implementacji, jednak jeżeli nasz typ zamierzamy użyć jako klucz słownika, jesteśmy zmuszeni do jej zdefiniowania. Kolekcje klucz - wartość wykorzystują rezultat funkcji GetHashCode w celu efektywnego wyszukiwania elementów w kolekcji.
Implementacja metody GetHashCode musi spełniać 3 warunki:
  1. jeżeli dwa obiekty są równe (operator==) - muszą generować ten sam hash
  2. niezależnie od zmienianych wartości w obiekcie, funkcja ta musi zwracać zawsze ten sam rezultat
  3. funkcja powinna generować losową wartość Integer dla danych wejściowych z całego zakresu tego typu danych.
Spełnienie 3 warunku jest szczególnie trudne. Domyślnie Object.GetHashCode() używa pola w którym przechowuje wartość hash. Każdy tworzony obiekt, w konstruktorze ma przypisany unikalną wartość typu Integer. Wartości te zaczynają się od 1 a następnie inkrementowane przy tworzeniu kolejnych wartości. Wartość ta jest przypisana w konstruktorze i nie może być później zmieniona. Funkcja GetHashCode() zwraca tę wartość.

W przypadku struktur funkcja ta zwraca hash dla pierwszego zadeklarowanego pola w niej. Przykładowo:

Code:
    public struct MyStruct
    {
        public string Name { get; set; }
        public int Id  { get; set; }
    }

dla tej struktury hash zostanie wygenerowany na podstawie pola Name.

Implementacja w przypadku klasy:

Code:
    public class Person
    {
        public string Name { get; private set; }
        public string Address { get; set; }

        public Person()
        {
        }

        public Person(string name)
        {
            Name = name;
        }

        public Person SetName(string name)
        {
            return new Person() { Name = name, Address = Address };
        }

        public override int GetHashCode()
        {
            return Name.GetHashCode();
        }
    }


Oraz użycie:

Code:
            var dictionary = new Dictionary<Person, string>();
            var p1 = new Person("Jan");
            dictionary.Add(p1, "20");
            Person p2 = p1.SetName("Marek");
            string s = dictionary[p1];
            dictionary.Remove(p1);
            dictionary.Add(p2, s);


Warto zauważyć tutaj dwie rzeczy:
  1. Właściwość Name jest tylko do odczytu - co zapewni nam że nie zostanie przez to zmieniony hash
  2. Mamy dodatkową metodę SetName, która zwraca nowy obiekt typu Person. W użyciu widać że w przypadku gdy zmienimy Name, należy stary obiekt wyrzucić ze słownika i zastąpić nowym. Rozwiązanie to umożliwia uniknięcie trudnych do wykrycia błędów związanych z tworzeniem hash-a.

Zrozumieć Equality

Tworząc własny typ w większości przypadków definiujemy także dla niego funkcje równości.

Mało kto wie jednak że C# oferuje aż 4 takie funkcje:

Code:
public virtual bool Equals(object obj)
public static bool Equals(object objA, object objB)
public static bool ReferenceEquals(object objA, object objB)
public static bool operator ==(MyClass left, MyClass right)


Przeważnie nie definiujemy wszystkich 4 funkcji a tylko dwie z nich: Equals oraz operator ==
Należy pamiętać, że zmieniając jedną z nich możemy wpłynąć nieświadomie na pozostałe.
Oprócz tych 4 metod istnieje także interfes IEquatable<T>. Implementacja tego interfejsu jest wskazana tam, gdzie definiujemy funkcję Equals (interfejs ten zawiera jedną metodę Equals).
Mnogość metod sprawdzania równości wynika z prostego faktu:
  • Jeżeli porównujemy dwa obiekty, to są one równe gdy ich referencje wskazują na ten sam obiekt
  • Jeżeli porównujemy dwa typy wartościowe, to są one równe wtedy kiedy ich wartości są równe

Pierwsza z metoda, której nigdy nie zmieniamy - ReferenceEquals() zwraca prawdę, gdy dwie zmienne odnoszą się do tego samego obiektu - do tej samej komórki pamięci. Metoda ta nie sprawdza zawartości obiektu. Wynika z tego iż dla typów wartościowych zawsze zwraca fałsz (false). Nawet jeżeli porównany za pomocą tej metody zmienną wartościową z samą sobą dostaniemy false - związane jest to z boxing-iem.

Druga funkcja, której nigdy nie zmieniamy to statyczna funkcja Equals zdefiniowana w klasie Object:

Code:
public static bool Equals(object objA, object objB)
{
 return objA == objB || (objA != null && objB != null && objA.Equals(objB));
}


Funkcji tej używamy gdy nie znamy typu zmiennych, które porównujemy. Z kodu powyższego możemy odczytać, że rozważane są trzy przypadki:
  1. sprawdzenie za pomocą metody ReferenceEquals czy obiekty wskazują na tę samą komórkę pamięci
  2. sprawdzenie czy któryś z argumentów nie jest nullem
  3. wykorzystanie metody Equals


Kolejną metodą jest wirtualna metoda Equals. Kiedy ją nadpisujemy?
  • w przypadku typów wartościowych - zawsze
  • w przypadku typów referencyjnych - wtedy kiedy zależy nam na równości zawartości obiektu
Nadpisując metodę Equals warto zrobić to implementując interfejs IEquatable<T>
Zasady podczas nadpisywania metody Equals:
  • metoda ta nie powinna rzucać wyjątku - nie ma to większego sensu
  • w pierwszej kolejności sprawdzamy czy wchodzący do metody parametr nie jest nullem
  • drugie sprawdzenie dotyczy tego czy porównujemy dwa obiekty tego samego typu
  • implementując IEquatable<T>  - zapewniamy, że tworzymy silnie typowane sprawdzenie.
  • nadpisując metodę Equals należy także nadpisać GetHashCode
Przykładowa implementacja:

Code:
    public class Point : IEquatable<Point>
    {
        public int X { get; set; }
        public int Y { get; set; }

        public override bool Equals(object obj)
        {
            //1. sprawdzenie czy obiekt nie jest nullem
            if (obj == null)
            {
                return false;
            }

            //2. sprawdzenie czy porównujemy obiekty tego samego typu
            var point = obj as Point;
            if (point == null)
            {
                return false;
            }

            //3. porównanie zawartości obiektu
            return point.X == X && point.Y == Y;
        }

        public bool Equals(Point other)
        {
            if (other == null)
            {
                return false;
            }

            return other.X == X && other.Y == Y;
        }
    }



Nadpisanie operatora == jest rzeczą banalną. W przypadku typu wartościowego jego nadpisanie jest bardzo ważne w aspekcie wydajności - jeżeli tego nie zrobimy podczas porównywania będzie stosowana refleksja.
Jeżeli chodzi o typy referencyjne operator== sprawdza równość referencji. Jeżeli jest to tylko możliwe nie powinniśmy zmieniać tej funkcjonalności.

Random - losowy element kolekcji za pomocą LINQ

Często potrzebujemy losowy element danej kolekcji. Aby nie pisać ciągle tego samego kodu wybierającego element losowy, możemy napisać metodę LINQ, którą użyjemy w dowolnym projekcie.
Metoda będzie się nazywać RandomElement.

Wymagania dla metody:
- przyjmuje źródło implementujące IEnumerable<T> i zwraca jeden element typu T
- przyjmuje opcjonalnie seed (kontrola nad generowanymi liczbami losowymi)
- jeżeli źródło jest nullem rzucany jest wyjątek ArgumentNullException
- jeżeli źródło nie zawiera elementów (kolekcja jest pusta) rzucany jest wyjątek InvalidOperationException

Implementacja:

Code:
using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication1
{
    public static class LinqExtensions
    {
        public static T RandomElement<T>(this IEnumerable<T> source, int? seed = null)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source is null");
            }

            int count = 0;
            if (source is ICollection<T>)
            {
                count = ((ICollection<T>)source).Count;
            }
            else
            {
                count = source.Count();
            }
            if (count == 0)
            {
                throw new InvalidOperationException("Source contains no elements");
            }

            Random random;
            if (!seed.HasValue)
            {
                random = new Random();
            }
            else
            {
                random = new Random(seed.Value);
            }

            var list = source as IList<T>;
            var index = random.Next(0, count);
            if (list != null)
            {
                return list[index];
            }
            else
            {
                using(IEnumerator<T> e = source.GetEnumerator())
                {
              e.MoveNext();
                    while (index > 0)
                    {
                     e.MoveNext();
                        --index;
                    }

                    return e.Current;
                }
            }
        }
    }
}


Przedstawiona metoda została zoptymalizowana aby korzystać z możliwości które dają kolekcje. Jak wiadomo listy, tablice itd. można przeglądać odnosząc się do ich elementów poprzez indeks. Pobranie poprzez indeks wartości jest dużo szybsze niż iteracja po całej kolekcji i wybranie żądanej wartości.

Przykładowe użycie metody:

Code:
            var sequence = Enumerable.Range(0, 100);
            var selectec = sequence.RandomElement();

piątek, 12 października 2012

Exception Assistant Visual Studio 2012 Express For Desktop

Exception Assistant - czyli asystent wyjątków.
Jeżeli korzystamy z najnowszego Visual Studio 2012 Windows Desktop możemy się rozczarować gdy zamiast dobrze znanego okienka:



dostaniemy irytujące modalne okienko:


Tutaj smutna wiadomość: Microsoft postanowił usunąć z wersji 2012 Express dla aplikacji desktopowych asystenta wyjątków pokazanego na poprzednim screenie.
Problem został opisany w wątku: http://connect.microsoft.com/VisualStudio/feedback/details/762652/enable-exception-assistant-option-missing-from-vs2012-express-for-desktop

Czy to krok w dobrą stronę? Czy zachęci nowych programistów do korzystania z darmowej wersji?

środa, 10 października 2012

MS SQL baza dancyh bez pliku loga

Chcąc dołączyć do MS SQL bazę która nie posiada pliku loga poprzez Management Studio zostanie wyrzucony błąd braku tego pliku.

Aby dołączyć bazę bez pliku logu można skorzystać z polecenia:

sp_attach_single_file_db @dbname= 'databasename', @physname= 'sciezka_do_pliku_mdf'

niedziela, 7 października 2012

Tworzenie i zwalnianie DbContext w aplikacji ASP.NET MVC

Korzystając z aplikacji ASP.NET MVC i EntityFrameworka warto stworzyć uniwersalny kod pobierania i zwalniania DbContex.

Przejdę od razu do implementacji:
Code:
    public static class MvcContext
    {
        public const string ContextName = "DatabaseContext";

        public static DatabaseContext Current
        {
            get
            {
                if (HttpContext.Current.Items[ContextName] == null)
                {
                    HttpContext.Current.Items[ContextName] = new DatabaseContext();
                }

                return (DatabaseContext)HttpContext.Current.Items[ContextName];
            }
        }
    }

Plik Global.asax:

Code:
public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
        }

        protected void Application_EndRequest()
        {
            var entityContext = HttpContext.Current.Items[MvcContext.ContextName] as DatabaseContext;
            if (entityContext != null)
            {
                entityContext.Dispose();
            }
        }

        protected void Application_BeginRequest()
        {

        }
    }


Pytanie odnośnie kodu powyżej może być jedno: dlaczego DbContext nie jest tworzony w Application_BeginRequest() ?

Metody Application_BeginRequest oraz Application_EndRequest wywoływane są przy każdym żądaniu. Jeżeli weźmiemy stronę która ma 30 obrazków - zostałoby stworzonych 30 DbContext-tów.

W przypadku powyższego kodu DbContext zostanie stworzony tylko wtedy kiedy będzie potrzebny a zwolniony po zakończeniu żądania.

MemoryCache - prosty mechanizm cache w .NET 4.0

Tworząc w ASP.NET z pewnością mieliście styczność z klasą Cache, która umożliwia buforowanie danych do późniejszego użycia. Do tej pory byliśmy ograniczeni do aplikacji webowych. Wraz z wersją .NET 4.0 dodano obsługę buforowania dla wszystkich rodzajów aplikacji (Windows Forms, WPF itd.).

Obsługa bufora jest bardzo prosta:

Code:
            var key = "klucz";
            var value = "value";
            var memoryCache = MemoryCache.Default;
            var cachePolicy = new CacheItemPolicy();
            cachePolicy.SlidingExpiration = TimeSpan.FromMinutes(1);
            memoryCache.Add(key, value, cachePolicy);

            var valueFromCache = memoryCache[key];
            if (valueFromCache == null)
            {
                memoryCache[key] = value;
            }

Powyższy kod oznacza, iż jeżeli wartość nie zostanie pobrana w ciągu minuty od jej umieszczenia tam, zostanie skasowana.

Oprócz SlidingExpiration mamy do dyspozycji AbsoluteExpiration:

Code:
cachePolicy.AbsoluteExpiration = DateTime.Now.AddMinutes(1);

oznacza on dokładną datę kiedy obiekt zostanie usunięty z bufora.

Do dyspozycji zostały nam oddane także dwa monitory:
  • SqlChangeMonitor - sprawdzający zmiany w bazie danych
  • HostFileChangeMonitor - sprawdza czy pod podanymi ścieżkami plików/folderów dokonano zmian

Innymi przydatnymi cechami bufora są:
  • możliwość ustalenia rozmiaru bufora
  • możliwość opróżnienia bufora - według procentów
  • dwa zdarzenia: UpdateCallback oraz RemovedCallback

piątek, 5 października 2012

Łatwiejsze ścieżki w MVC 4

Do tej porty w ASP.NET MVC korzystaliśmy z następującej składni:

Code:
<script src="@Url.Content("~/Scripts/Site.js")"></script>


W nowej wersji jest możliwe użycie skróconej wersji:

Code:
<script src="~/Scripts/Site.js"></script>


Bundling and Minification

Tytuł ściśle związany z minimalizacją - zarówno pod względem wielkości przesyłanych danych jak i szybkością ładowania strony.

W nowej wersji MVC zostały dodane mechanizmy zwiększające wydajność ładowania JavaScript oraz stylów CSS. Jest to kontynuacja motta "Konwencja nad konfiguracją" - brak wymagania konfiguracji. Mimo braku potrzeby konfiguracji mechanizmu - jest on w pełni konfigurowalny jaki i rozszerzalny.

W jaki sposób działa mechanizm?

Jeżeli spojrzymy do eksploratora projektu nowego projektu, znajdziemy folder zawierający pliki JavaScript jak również folder gdzie znajdują się style CSS:



Uruchamiając program i badając ruch sieciowy - np w Firebug znajdziemy tam tylko dwa wpisy:


Ciekawy jest zwłaszcza pierwszy - jest to właśnie wynik miniaturyzacji i scalania wszystkich użytych skryptów w projekcie.
Kod scalający znajduje się w pliku BundleConfig:

Code:
using System.Web.Optimization;

namespace MvcApplication3
{
    public class BundleConfig
    {
        // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                        "~/Scripts/jquery-{version}.js"));

            bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
                        "~/Scripts/jquery-ui-{version}.js"));

            bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                        "~/Scripts/jquery.unobtrusive*",
                        "~/Scripts/jquery.validate*"));

            // Use the development version of Modernizr to develop with and learn from. Then, when you're
            // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
            bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
                        "~/Scripts/modernizr-*"));

            bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));

            bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
                        "~/Content/themes/base/jquery.ui.core.css",
                        "~/Content/themes/base/jquery.ui.resizable.css",
                        "~/Content/themes/base/jquery.ui.selectable.css",
                        "~/Content/themes/base/jquery.ui.accordion.css",
                        "~/Content/themes/base/jquery.ui.autocomplete.css",
                        "~/Content/themes/base/jquery.ui.button.css",
                        "~/Content/themes/base/jquery.ui.dialog.css",
                        "~/Content/themes/base/jquery.ui.slider.css",
                        "~/Content/themes/base/jquery.ui.tabs.css",
                        "~/Content/themes/base/jquery.ui.datepicker.css",
                        "~/Content/themes/base/jquery.ui.progressbar.css",
                        "~/Content/themes/base/jquery.ui.theme.css"));
        }
    }
}


czwartek, 4 października 2012

Dependency Injection ASP MVC 4

W ASP.NET MVC 1/2 wstrzykiwanie polegało na nadpisaniu Fabryki tworzącej kontrolery. W wersji 3 i 4 wprowadzono serwis DependencyResolver. Interfejs ten zawiera dwie podstawowe metody:

Code:
  public interface IDependencyResolver
  {
    /// <summary>
    /// Resolves singly registered services that support arbitrary object creation.
    /// </summary>
    /// 
    /// <returns>
    /// The requested service or object.
    /// </returns>
    /// <param name="serviceType">The type of the requested service or object.</param>
    object GetService(Type serviceType);

    /// <summary>
    /// Resolves multiply registered services.
    /// </summary>
    /// 
    /// <returns>
    /// The requested services.
    /// </returns>
    /// <param name="serviceType">The type of the requested services.</param>
    IEnumerable<object> GetServices(Type serviceType);
  }

Warto użyć własnego kontenera rozwiązującego zależności, który oferuje znacznie więcej możliwości konfigurowania.

Użycie kontenera Unity jest bardzo proste w tym przypadku. Skorzystać można tutaj z Nuget-a.

1. Tworzymy nowy projekt ASP.NET MVC 3/4
2. Korzystając z Package Manager Console instalujemy Unity wraz z dodatkiem MVC3:

Code:
PM> Install-Package unity.Mvc3


3. Do projektu zostanie dodana klasa Bootstrapper która służy do konfiguracji naszego kontenera:

Code:
    public static class Bootstrapper
    {
        public static void Initialise()
        {
            var container = BuildUnityContainer();

            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        }

        private static IUnityContainer BuildUnityContainer()
        {
            var container = new UnityContainer();

            // register all your components with the container here
            // it is NOT necessary to register your controllers
            
            // e.g. container.RegisterType<ITestService, TestService>();            

            return container;
        }
    }


4. Kontener inicjujemy w Global.asax

Code:
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
            Bootstrapper.Initialise();
        }
    }


To wszystko co należy zrobić aby możliwe było korzystanie z wzorca IoC w ASP.NET MVC 3/4

wtorek, 2 października 2012

Szyfrowanie Web.config

Szyfrowanie Web.config-a jest rzeczą oczywistą. Znajdują się w nim dane dostępowe do bazy danych, klucze do webserwisów oraz inne poufne dane.

Instrukcja szyfrowania Web.config-a:
1. Eksportujemy klucz maszyny (Machine key):

Code:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -px "iisConf
igurationKey" C:\folder\iisConfKey.xml -pri

Code:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -px "iisWasKey" C:\folder\iisWasKey.xml -pri


Wyeksportowany klucze znajdziemy pod ścieżką:

Code:
 C:\folder\



2. Import klucza na serwerach

Code:
c:\windows\Microsoft.NET\Framework64\v2.0.50727\aspnet_regiis.exe -pi "iisConfigurationKey" c:\folder\iisconfkey.xml -exp

Code:
c:\windows\Microsoft.NET\Framework64\v2.0.50727\aspnet_regiis.exe -pi "iisWasKey" c:\folder\iisWasKey.xml -exp


3. Autoryzacja zaimportowanego klucza

Code:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis -pa 
"iisConfKey"


4. Do Web.config-a dodajemy sekcję zawierającą informacje nt używanego prowidera szyfrowania:
 Jest to krok konieczny jeżeli zamierzamy używać zaimportowanego klucza na wielu serwerach:

Code:
<configprotecteddata>
<providers>
<add keyContainerName=”MyWebServerRSA”
description=”Uses RsaCryptoServiceProvider to encrypt and decrypt”
name=”MyWebServerRSAProvider”
type=”System.Configuration.RsaProtectedConfigurationProvider,System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a” />
</providers>
</configProtectedData>


5. Przykładowe szyfrowanie sekcji connectionstringów:

Code:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis -pef "connection
Strings" "C:\inetpub\WebApplication1" -prov "MyWebServerRSAProvider"

Po zakodowaniu sekcja connectionStrings będzie wyglądała w następujący sposób:

Code:
    <connectionStrings configProtectionProvider="MyWebServerRSAProvider">
        <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
            xmlns="http://www.w3.org/2001/04/xmlenc#">
            <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
            <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
                    <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
                    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                        <KeyName>Rsa Key</KeyName>
                    </KeyInfo>
                    <CipherData>
                        <CipherValue>f19a64s6YB208ibupTTE6+8zWI3y+trQTAajwtpaoArJ8kLic2k0ifmmSmok3NU2Aw7vBUcR2oayzUsoJSuYIDePVr/zvI9/oMVuRMBE+nvzi598BlpZ3lxsggKiwrCO1U/h/zcgNQFuosu7PnX4Rz+4cXZB60LngaZe+Gk+jy8=</CipherValue>
                    </CipherData>
                </EncryptedKey>
            </KeyInfo>
            <CipherData>
                <CipherValue>6xZXUTJzr/ovYhI4qvw06hBA9qj59AKiOpEuwdx175R8HCiY/toW4G31GZwI237cmNTMPdlJac/VGki9C/UhU6Ehwb7VQoM8LjiqiJnWNkjyOUJYJOa+uZhpoVtEY06trjMqcFtLP/hdNiDtOwvOxusSFxGioP4Jwvfl22qTSBuc4j1QS1t8PSr/5tlZFJkSV6rxflMPJ+4Z4FYTHdfCyuk3vdnbO2RKjHyx3kNqjEz1eeKrKfz2jH9b6pbMKNss91+fE/ERjeGgdaP8wmewCw67zfjfx7B9fz/FZCw5MK+L2rUsnQMjqXCQEodVBbQtrDSGIlIAcQXGng8h2F9U09AzDSyZRrY+</CipherValue>
            </CipherData>
        </EncryptedData>
    </connectionStrings>