70-562:Deploying Web applications

Artykuł pochodzi w serii przygotowań do egzaminu 70-562 ASP.NET.

W dzisiejszej lekcji powiemy sobie o wdrażaniu aplikacji internetowych w ASP.NET.

Tworzenie projektu Web Setup

Web setup jest narzędziem, które wspomaga wdrażanie naszej aplikacji internetowej. Projekt Web Setup jest bardzo podobny do standardowego projektu Setup, który mamy w aplikacjach Windows Forms, lecz dostarcza specjalnych właściwości wymaganych przez aplikację Web. Aby stworzyć nowy projekt typu Web Setup musimy podczas tworzenia projektu wybrać zakładkę Other Project Types –> Setup  and Deployment –> Web Setup Project.
image
Po stworzeniu nowego projektu, Visual dołączy projekt do solution oraz wyświetli edytor “File System”. Następnie musimy dodać do nowo utworzonego projektu nowy element. Ustawiamy się na projekcie i wybieramy Add-> Project Output. W oknie tworzenia Project Output wybieramy Content i configuration ustawiamy na Active. W tym momencie zapewniliśmy sobie dostęp do naszego projektu, który chcemy wdrażać.

Tworzenie warunków uruchomienia

Dzięki warunkom uruchomienia możemy sobie sprawdzać np. czy na serwerze znajdują się Service Packi albo inne komponenty, które są wymagane do wdrożenia naszej aplikacji. Do tworzenia i zarządzania warunkami uruchomienia używa się edytora Launch Condition. Aby z niego skorzystać klikamy prawym przyciskiem na projekcie, następnie wybieramy View-> Launch Condition. Teraz aby dodać nowy warunek klikamy prawym przyciskiem na folderze Launch Condition i wybieramy Add Launch Condition:
image

 

Istnieją dwie główne gałęzie w edytorze: Search Target Machine oraz Launch Condition:
Search Target Machine – pozwala na zdefiniowanie kryteriów wyszukiwania przed instalacją. Domyślnie zawiera wyszukiwanie dla IIS ale możemy dodać do niego pliki rejestru, Windows Installer Search Condition itp.
Launch Condition – pozwala na tworzenie nowych warunków, które muszą być spełnione przed instalacją. Mogą być one oparte o warunki wyszukiwania lub inne kryteria (np. wersja systemu operacyjnego).

Po stworzeniu nowego warunku, możemy we właściwości Condition ustawić nasz warunek. Np. sprawdzanie wersji IIS może odbyć się w taki sposób:

   1: IISVERSION = "#6" 

Sprawdzamy tu, czy wersja IIS jest równa 6. Oczywiście możemy używać operatorów > < >= <=. Aby sprawdzić czy dyskiem domowym jest C:

   1: %HOMEDRIVE = "C:"

Dodawanie własnej strony setup’u

Możemy dodać własne strony do naszego instalatora. Można w nich pobierać jakieś informacje a następnie przekazywać je jako parametry do własnych akcji. Działania jakie możemy wykonywać podczas instalacji:
Wyświetlanie licencji – projekt Web Setup dostarcza szablon do potwierdzania licencji
Modyfikowanie ustawień w Web.Config – zmienianie ustawień Web.Config na podstawie danych przekazanych przez użytkownika
Wykonywanie niestandardowej konfiguracji – możemy za pomocą własnej konfiguracji zapytać użytkownika o jakieś informację i przechowywać je np. w rejestrze.
Aktywacja bądź rejestracja aplikacji – możemy wymagać od użytkownika podanie klucza bądź rejestracji

Aby dodać własną stronę, wchodzimy w User Interface(prawym przyskiem myszy na projekcie –> View –> User Interface). Edytor ten wyświetla różne etapy konfiguracji itp:
image

Teraz wystarczy PPM na etapie, w którym chcemy dodać stronę i wybieramy Add Dialog. Widzimy opcję, które możemy dodać do projektu. Proponuję pobawić się nimi i zobaczyć jak działają bądź doczytać o nich na msdnie.
image

Wdrażanie aplikacji

Po skonfigurowaniu naszego projektu i zbudowaniu jesteśmy gotowi wdrożyć go na serwerze :) Aby to zrobić, należy użyć plików wygenerowanych podczas buildu:
Setup.exe – plik, który instaluje pliki i wprowadza ustawienia, które dodaliśmy w naszym projekcie. Podczas instalacji zostaniemy zapytani o wszystkie dodatkowe ustawienia.
<NazwaProjektu>.msi – plik instalatora Windows zawierający wszystkie pliki dodane do projektu. Uruchomienie tego pliku jest równoważne uruchomieniu Setup.exe. Ten typ pliku jest mniejszy i bardziej uniwersalny.
Bardziej polecany jest plik msi, chociaż ma jedną wadę: serwer, na którym chcemy instalować aplikację musi mieć Windows Installer.

To wszystko z mojej strony :) Dziękuję za wytrwanie w tej serii wpisów :)

 

Tagi: , , , , ,

70-503: Transaction Basics

Ten artykuł pochodzi z serii przygotowań do egzaminu 70-503: Windows Communication Foundation.

Podstawową funkcją transakcji jest zagwarantowanie zasad ACID:

  • atomowości (ang. atomicity),
  • spójności (ang. consistency),
  • izolacji (ang. isolation),
  • trwałości (ang. durability).

Kiedy operacje związane z bazą odbywają się na wielu maszynach i wielu zbiorach danych, nie jest to takie proste. WCF wspomaga programistę w tym zadaniu.

W celu spełnienia zasad ACID najczęstszym podejściem jest wykorzystanie dwuetapowego zgłoszenia (ang. two-phase commit):

  1. Etap przygotowania (ang. prepare phase) – koordynator transakcji zarządza tym etapem, wysyła żądanie przygotowania do wszystkich zarządców transakcji (ang. transaction manager), na maszynach biorących udział w procesie. Zarządcy odsyłają informację o tym, czy operacje zakończyły się sukcesem, czy porażką. Kiedy wszyscy odpowiedzą etap przygotowania uznajemy za zakończony.
  2. Etap zgłoszenia (ang. commit phase) – zależny od wyników etapu poprzedniego; jeżeli tamten zakończy się sukcesem – wysyłane zostaje żądanie Commit, w przeciwnym wypadku, jeżeli chociaż jedna maszyna zwróci komunikat błędu – koordynator transakcji wysyła żądanie Abort, aby poinformować zarządców o potrzebie cofnięcia zmian.

W zależności od sytuacji wykorzystany może zostać jeden z trzech zarządców transakcji:

  • The Lightweight Transaction Manager (LTM) – wprowadzony w .NET 2.0 przez przestrzeń nazw System.Transaction (do projektu trzeba dodać assembly); poniższy przykład aktualizuje bazę danych w ramach lekkiej transakcji. W celu zgłoszenia transakcji wywołana jest metoda Complete:
  •    1: using (TransactionScope ts = new TransactionScope())
       2: {
       3:   using (SqlConnection cn1 = new SqlConnection(connectionString))
       4:   {
       5:     insertRecord(cn1, "User1");
       6:     using(SqlConnection cn2 = new SqlConnection(connectionString))
       7:     {
       8:       insertRecord(cn2, "User2");
       9:     }
      10:   }
      11:   ts.Complete();
      12: }
      13: private void insertRecord(SqlConnection cn, string userName)
      14: {
      15:   SqlCommand cmd = new SqlCommand(String.Format("Insert INTO [Users]" +" VALUES('{0}')", userName), cn);
      16:   cn.Open();
      17:   cmd.ExecuteNonQuery();
      18: }
  • OLE Transactions (OleTx),
  • WS-Atomic Transactions (WS-AT).

Transakcji możemy pozwolić na działanie poza granicami serwisu, lub nie. Decyzję o tym podejmują klient i serwis, jednak jeżeli serwis wymaga transakcji, blokowanie po stronie klienta spowoduje błąd aplikacji. Ustawione może to zostać w bindingu za pomocą atrybutu TransactionFlow, zarówno imperatywnie jak i deklaratywnie:

   1: // C#
   2: WSHttpBinding binding = new WSHttpBinding();
   3: binding.TransactionFlow = true;
   4:  
   5: <!--XML-->
   6: <bindings>
   7: <wsHttpBinding>
   8: <binding name="Transactional" transactionFlow="true" />
   9: </wsHttpBinding>
  10: </bindings>

 

 

Dodatkowo wymagane jest, aby operacje serwisu były oznaczone atrybutem TransactionFlow, który wskazuje na to, że mogą one brać udział w transakcji:

   1: [ServiceContract]
   2: public interface IDemoContract
   3: {
   4:   [OperationContract]
   5:   [TransactionFlow(TransactionFlowOption.Allowed)]
   6:   void TransactedMethod(...);
   7: }

Po stronie klienta w ten sam sposób zostanie udekorowana klasa proxy:

   1: public class DemoService : IDemoContract
   2: {
   3:   [TransactionFlow(TransactionFlowOption.Allowed)]
   4:   public void TransactedMethod(...)
   5:   {...}
   6: }

W powyższym przykładzie TransactionFlow ustawiony jest na wartość TransactionFlowOption.Allowed, która pozwala transakcji klienta przechodzić do serwisu. Domyślna opcja TransactionFlowOption.NotAllowed sprawia, że żadna transakcja nie jest przesyłana.

Uwaga: Transakcje nie działają w przypadku metod typu one-way – bez komunikatu zwrotnego nie ma możliwości stworzenia rozproszonej transakcji.

Tagi: , , , ,

70-562: Building Mobile Application

Artykuł pochodzi w serii przygotowań do egzaminu 70-562 ASP.NET.

W dzisiejszej lekcji będzie na temat budowania, uruchamiania oraz testowania mobilnych wersji aplikacji webowych stworzonych w technologii ASP.NET.

Tworzenie aplikacji mobilnych mocno nie różni się od tworzenia zwykłych aplikacji webowych. Trzeba tylko pamiętać, że w większości urządzenia mobilne mają większe ograniczenia w stosunku do normalnych komputerów. Dlatego wersje mobilne aplikacji powinny być jak najmniej skomplikowane oraz zawierać jak najmniej elementów, aby urządzenie poradziło sobie z jej wyświetleniem.

Dodanie mobilnej strony do aplikacji

Aplikacja ASP.NET może zawierać jednocześnie strony w wersji normalnej oraz wersje mobilne. Nie ma oddzielnego projektu w Visual Studio dla mobilnych aplikacji ASP.NET. Nie ma również szablonu dla strony mobilnej, który można by wykorzystać dodając taką stronę do projektu. W celu dodania mobilnej strony, programista musi dodać normalną stronę, a następnie zmienić trzy elementy na niej:

  • w kodzie behind danej strony zmieniamy klasę, z której dziedziczy klasa strony z System.Web.UI.Page na System.Web.UI.MobileControls.MobilePage
  • w kodzie aspx po dyrektywie page dodajemy dyrektywę, która załaduje przestrzeń nazw System.Web.UI.MobileControls, z której będą pochodzi kontrolki na stronie
       1: <%@ Register TagPrefix="mobile" Namespace="System.Web.UI.MobileControls" %>
  • zamieniamy wygenerowany przez Visual Studio formularz, który korzysta z wcześniej dodanej przestrzeni nazw:
   1: <mobile:Form id="form1" runat="server">
   2: </mobile:Form>

Mobilne kontrolki

Przestrzeń nazw System.Web.UI.MobileControls udostępnia programiście szereg kontrolek, które może wykorzystać tworząc mobilne wersje aplikacji ASP.NET, które są przystosowane do pracy z urządzeniami mobilnymi. Tymi kontrolkami są między innymi (większość kontrolek jest bardzo podobna do normalnych kontrolek ASP.NET):

  • Label – za jej pomocą programista może z poziomu kodu behind wyświetlić tekst na stronie. Gdy ma zostać wyświetlona większa ilość tekstu, lepiej skorzystać z kontrolki TextView
  • TextBox – służy do pobierania danych tekstowych od użytkownika
  • TextView – służy do wyświetlenia większej ilości tekstu. Umożliwia użycia prostego formatowania HTML (np. a (link), b (pogrubienie), br (znak nowej lini), i (kursywa), p (akapit))
  • Command – przycisk, który może kliknąć użytkownik. Wywoływane jest zdarzenie OnClick, gdy użytkownik kliknie w przycisk
  • Image – kontrolka służy do wyświetlenie obrazka, w przypadku, gdy format obrazka nie jest obsługiwany, wyświetlany jest tekst z właściwości AlternateText
  • List – kontrolka służy do wyświetlenie elementów w formie listy
  • SelectionList – jest podobna do kontrolki List, dodatkowo umożliwia wielokrotny elementów z listy
  • ObjectList – jest to odpowiednik GridView z normalnego ASP.NET, czyli umożliwia wyświetlenie danych w postaci tabelki
  • Calendar – kontrolka kalendarza umożliwiająca wybranie daty przez użytkownika. Kontrolka może wyglądać różnie w zależności od urządzenia (patrz opis niżej)
  • Kontrolki walidujące – dostępne są wszystkie kontrolki walidujące dostępne w normalnym ASP.NET

Brak obsługi cookie

Większość urządzeń mobilnych niestety nie obsługuje plików cookie przez co mogą wystąpić problemy między innymi z sesją oraz uwierzytelnianiem, gdzie domyślnie te mechanizmy korzystają z plików cookie (np. do przechowywania ID sesji). Dlatego w przypadku sesji należy ustawić właściwość cookieless na true, dzięki czemu ID sesji będzie przekazywany w adresie url. Aby to zrobić trzeba w web.configu (dla system.web) dodać:

   1: <sessionState cookieless="true" />

Adaptacyjny rendering

Na rynku istnieją różnego rodzaju urządzenia mobilne, które czasami mają bardzo ograniczone możliwości wyświetlania strony. Dlatego kontrolki mobilne ASP.NET umożliwiają renderowanie strony w zależności od przeglądarki, z której jest wysłane żądanie do serwera. I tak na SmartPhonie kontrolka kalendarza może być wyświetlona w sposób identyczny, jak w normalnej wersji strony w przeglądarce na komputerze, co widać na rysunku niżej:

imageNatomiast w prostym telefonie wybór daty z kalendarza może przebiegać w kilku etapach, co widać na poniższym rysunku:

image 

Gdzie wybór daty może przebiegać w trzech krokach:

  • wybór miesiąca np. wrzesień 2006
  • wybór tygodniach np. 10 – 16 września
  • wybór dnia tygodnia środa 12 września

W każdym żądaniu HTTP jest przekazywany nagłówek User-Agent, w którym znajduje się ciąg znaków identyfikujący przeglądarkę z jakiej korzysta użytkownik. ASP.NET przechowuje w plikach o rozszerzeniu browser konfigurację sposobu wyświetlania strony w zależności od przeglądarki. Globalnie pliki te przechowywane są w katalogu c:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\Browsers\. Właśnie na podstawie tych plików ASP.NET decyduje w jaki sposób ma zostać wyświetlona strona, czy to kontrolki (np. Calendar pokazany wyżej).

Dodatkowo programista z poziomu kodu behind może sprawdzić, czy żądanie przyszło z urządzenia mobilnego, czy nie. Na podstawie tej informacji może wykonać odpowiedni kod. Aby to sprawdzić, wystarczy sprawdzić wartość właściwości Request.Browser.IsMobileDevice.

   1: if(Request.Browser.IsMobileDevice)
   2: {
   3:     //kod dla mobilnej wersji   
   4: }else
   5: {
   6:     //kod dla wersji normalnej
   7: }

Tagi: , , , ,

70-562: Securing Your Site

Artykuł pochodzi w serii przygotowań do egzaminu 70-562 ASP.NET.

Do tej pory powiedzieliśmy sobie o profilach użytkowników, narzędziu WSAT, kontrolce Login czy też o podstawach membershipa. ASP.NET wspiera co najmniej 4 rodzaje uwierzytelniania są to:

  • Windows authentication
  • Forms authentication (which ASP.NET membership uses)
  • Passport authentication
  • Anonymous access

Dzisiaj porozmawiamy w sposób ogólny jak można wykorzystać każdy z tych sposobów.

Konfiguracja aplikacji webowej która wymaga uwierzytelnienia poprzez Windows authentication

Jeśli aplikacja będzie wykorzystywana typowo wewnątrz firmy w której użytkownicy mają swoją konta które są w bazie lub jest cały Active Direcotry to wskazane jest korzystanie właśnie z Windows authentication. Możesz skonfigurować uwierzytelnianie Windows na dwa sposoby: w IIS oraz w aplikacji ASP.NET. Jeśli chcemy się ekstra zabezpieczyć to korzystamy z dwóch na raz. Kiedy aplikacja internetowa wymaga uwierzytelniania systemu Windows, aplikacja odrzuca wniosek, który nie zawiera prawidłowej nazwy użytkownika i hasła w nagłówku żądania. Niektóre przeglądarki np. IE ;) automatycznie dostarczają aktualną nazwę oraz hasło użytkownika który jest obecnie w intranecie. Nie trzeba chyba mówić, że to usprawnia prace i pozwala się płynnie uwierzytelniać użytkownikowi podczas każdych odwiedzin.

Dodatkowo, ponieważ użytkownicy są uwierzytelniani przez serwer w lokalnej bazie danych użytkownika lub
Domeny Active Directory, przy użyciu uwierzytelniania systemu Windows pozwala to uniknąć tworzenia bazy danych do przechowywania poświadczenia użytkownika. Także można stwierdzić, że Windows authentication jest najprostszym ze sposobów uwierzytelniania.

Aby dodać w prosty sposób Windows authentication do naszej aplikacji webowe w pliku web.config musimy umieścić sekcje <authentication> :

   1: <configuration>
   2: <system.web>
   3:     <authentication mode="Windows" />
   4:         <authorization>
   5:                 <deny users="?" />
   6:        </authorization>
   7: </system.web>
   8: </configuration>

 

Jeśli mamy jakiś formularz w który mielibyśmy możliwość wpisania loginu i hasła. Powiedzmy, że zrobiliśmy taki formularz i jest on na stornie Login.aspx. Musimy tam odesłać każdego niezalogowanego użytkownika ze storn do których nie ma dostępu. Aby to zrobić umieszczamy sekcje w web.config:

   1: <configuration>
   2:     <system.web>
   3:             <authentication mode="Forms">
   4:                 <forms loginURL="Login.aspx" />
   5:             </authentication>
   6:            <authorization>
   7:                <deny users="?" />
   8:            </authentication>
   9:     </system.web>
  10: </configuration>

Na stornie Login.aspx oczywiście musimy sprawdzić poprawność wprowadzonych danych. Aby to zrobić wystarczy prosty kod:

   1: if (FormsAuthentication.Authenticate(username.Text,
   2: password.Text))
   3: {
   4: //user is authenticated. Redirect user to the page requested.
   5: FormsAuthentication.RedirectFromLoginPage(usernameTextBox.Text, false);
   6: }

False oznacza, że dane nie będą pamiętane w ciasteczku stąd po wyłączeniu przeglądarki na nowo będziemy musieli się zalogować.

Jest możliwość skonfigurowania konta użytkownika wewnątrz web.config jeśli nie chcemy trzymać tych danych np. w bazie. Są trzy możliwości przechowywania hasła takiego użytkownika: jawny tekst, MD5 lub SHA1. Pozwala to uniknąć kradzieży konta przez użytkownika który ma dostęp do naszego pliku web.config. Spójrzmy jak przykładowo wygląda to właśnie w pliku web.config :

   1: <authentication mode="Forms">
   2:     <forms loginUrl="login.aspx" protection="Encryption" timeout="30" >
   3:         <credentials passwordFormat="SHA1" >
   4:             <user name="Eric" password="07B7F3EE06F278DB966BE960E7CBBD103DF30CA6"/>
   5:             <user name="Sam" password="5753A498F025464D72E088A9D5D6E872592D5F91"/>
   6:         </credentials>
   7:     </forms>
   8: </authentication>

Jednak aby pozwolić nam na korzystanie z takich zakodowanych haseł musimy mieć możliwość ich stworzenia. Przydałaby się program który by kodował hasło które później moglibyśmy używać w web.configu . Do tego celu możemy wykorzystać przestrzeń nazw System.Security.Cryptography. Spójrzmy na przykładowy kod generowania hash’a.

   1: namespace HashExample
   2: {
   3: class Program
   4: {
   5: static void Main(string[] args)
   6: {
   7: SHA1CryptoServiceProvider myHash=new SHA1CryptoServiceProvider();
   8: byte[] password = Encoding.ASCII.GetBytes(args[0]);
   9: myHash.ComputeHash(password);
  10: foreach (byte thisByte in myHash.Hash)
  11: Console.Write(thisByte.ToString("X2"));
  12: Console.WriteLine();
  13: }
  14: }
  15: }

 

Uwierzytelnianie za pomocą Paszportów

Można korzystać z usługi paszportów oferowaną przez Microsoft. Paszport pozwala odpłatnie korzystać z zcentralizowanej bazy danych. Przechowywanie danych o użytkownikach w ramach tej usługi uwalnia ich od tworzenia nowych profili, pamiętania kolejnego hasła do kolejnej witryny itd. Jest to również zaoszczędzenie czasu i co tu ukrywać przyjemne dla naszego odbiorcy.

Konfigurowanie aplikacji dla anonimowych użytkowników

Możemy wyraźniej wyłączyć autoryzowanie użytkowników w naszej aplikacji. Jednak zaleca się aby wtedy korzystać z IIS. Aby to zrobić wystarczy następująca sekcja w web.config:

   1: <configuration>
   2:     <system.web>
   3:         <authentication mode="None" />
   4:     </system.web>
   5: </configuration>

Możemy ograniczyć dostęp do poszczególnych folderów, plików naszej aplikacji na podstawie np. grupy czy konkretnych użytkowników. Domyślnie machine.config zawiera:

   1: <authorization>
   2: <allow users="*"/>
   3: </authorization>

Sekcja ta pozwala na dostęp wszystkim użytkownikom. Jeśli chcielibyśmy ograniczyć dostęp do poszczególnych użytkowników należałoby zastosować tą przykładowa sekcje:

   1: <authorization>
   2:     <allow users="Eric, Sam"/>
   3:     <deny users="*"/>
   4: </authorization>

 

Sekcja ta jednak ogranicza nam dostęp dla całej aplikacji. Jeśli chcielibyśmy użyć ograniczeń do konkretnej strony wyglądałoby to następująco:

   1: <location path="ListUsers.aspx">
   2:     <system.web>
   3:         <authentication mode="forms">
   4:             <forms loginUrl="AdminLogin.aspx" protection="All"/>
   5:         </authentication>
   6: <authorization>
   7:     <allow users="admin"/>
   8:         <deny users="*"/>
   9: </authorization>
  10: </system.web>
  11: </location>

 

To tyle na dzisiaj. Miłej zabawy na Kortowiadzie ;)

Tagi: , , ,

70-503: Working with Instances

· Ten artykuł pochodzi z serii przygotowań do egzaminu 70-503: Windows Communication Foundation.

Wiemy już, że WCF może tworzyć oddzielne instancje klasy serwisu dla poszczególnych wywołań, dla poszczególnych sesji lub używać tylko jednej instancji do obsłużenia wszystkich klientów i ich wywołań.

Dzisiaj dowiemy się jak zarządzać poszczególnymi instancjami klasy serwisu.

Zabezpieczanie serwisu

W rzeczywistym świecie głównym problemem są ataki typu “Odmowa usługi” (ang. Denial of service). Ataki te powodują wyczerpanie się zasobów serwisu tak by go zablokować. WCF udostępnia kilka parametrów, którymi możemy kontrolować dostępność naszego serwisu.

Dławienie

Dławienie (ang. Throttling) po pierwsze zabezpiecza serwis przed przeciążeniem pod wpływem zasypywania wiadomościami, po drugie umożliwia wyrównanie obciążenia serwisu (i całego serwera). W obu przypadkach głównym celem jest ograniczenie ilości przetwarzanych wiadomości w jednostce czasu. Domyślne ustawienia WCF’a nie przewidują dławienia w ogóle. Jeśli włączymy dławienie, WCF sprawdza odpowiednie liczniki przy każdej nadchodzącej wiadomości. Jeśli liczniki zostały przekroczone wiadomości są zbierane do kolejki. Gdy wartości liczników spadną do akceptowalnej wartości, wiadomości z kolejki zostaną przekazane do serwisu.

Do ustawienia dławienia mamy dostępne trzy ustawienia w klasie ServiceThrottlingBehavior:

  • MaxConcurrentCalls – liczba jednoczesnych wywołań które serwis zaakceptuje, domyślnie 16,
  • MaxConcurrentSessions – maksymalna liczba kanałów wymagających obsługi sesji, które serwis obsłuży, domyślnie 10, każda kolejna próba utworzenia kanału zostanie zakończona wyjątkiem TimeoutException, to ustawienie nie dotyczy bindingów nie obsługujących sesji np. basicHttpBinding,
  • MaxConcurrentInstances – maksymalna liczba instancji obiektów implementujących serwis, domyślnie 32, w trybie “per call” wartość jest tym samym co MaxConcurrentCalls ponieważ każde wywołanie ma własną instancję, w trybie “per session”, wartość jest tym samym co MaxConcurrentSessions, dla singletona, ponieważ zawsze jest tylko jedna instancja obiektu obsługującego serwis, wartość ma znaczenie tylko gdy jest użyty IInstanceContextProvider.

Poniżej przykłady konfiguracji dławienia:

   1: <behaviors>
   2:     <serviceBehaviors>
   3:         <behavior name="throttlingBehavior">
   4:             <serviceThrottling maxConcurrentCalls="10"
   5:                 maxConcurrentInstances="10"
   6:                 maxConcurrentSessions="5"/>
   7:         </behavior>
   8:     </serviceBehaviors>
   9: </behaviors>
   1: ServiceHost host = new ServiceHost( typeof(UpdateService),
   2: new Uri("http://localhost:8080/UpdateService"));
   3: host.AddServiceEndpoint( "IUpdateService",
   4:     new WSHttpBinding(), String.Empty);
   5: ServiceThrottlingBehavior throttlingBehavior = new ServiceThrottlingBehavior();
   6: throttlingBehavior.MaxConcurrentCalls = 10;
   7: throttlingBehavior.MaxConcurrentInstances = 10;
   8: throttlingBehavior.MaxConcurrentSessions = 5;
   9: host.Description.Behaviors.Add(throttlingBehavior);
  10: host.Open();

Tak jak zostało wspomniane, przekroczenie limitów spowoduje wyrzucenie wyjątku TimeoutException u klienta. Ponieważ w każdym przypadku jest to ten sam wyjątek, trzeba przyjrzeć się dokładnie miejscu jego wystąpienia. Jeśli problem dotyczy liczby jednoczesnych sesji (MaxConcurrentSessions) wyjątek będzie wyrzucany przy wywołaniu metody SendPreamble. Jeśli wyjątek jest wyrzucany przy metodzie Send, bardziej prawdopodobnym jest problem z maksymalną liczbą wywołań (MaxConcurrentCalls).

Jeszcze mała uwaga. Dobrze jest konfigurować dławienie z poziomu kodu. Konfigurowanie dławienia w pliku konfiguracyjnym umożliwia administratorowi serwera ustawienie tych opcji np. dopiero gdy będzie tego potrzebował.

Odczytywanie ustawień dławienia

Istnieje możliwość odczytania (ale nie aktualizacji) aktualnych ustawień dławienia po uruchomieniu serwisu.

Klasa ServiceHost udostępnia kolekcję dyspozytorów (ang. dispatchers) w właściwości ChannelDispatchers. Jest to kolekcja obiektów typu ChannelDispatcher. Każdy z nich ma właściwość ServiceThrottle. Przez tą właściwość mamy dostęp do ustawień dławienia, w tym MaxConcurrentCalls, MaxConcurrentInstances i MaxConcurrentSessions. Poniżej przykład kodu:

   1: ChannelDispatcher dispatcher =
   2:     OperationContext.Current.Host.ChannelDispatchers[0] as ChannelDispatcher;
   3: ServiceThrottle throttle = dispatcher.ServiceThrottle;
   4: Trace.WriteLine(String.Format("MaxConcurrentCalls = {0}",
   5:     throttle.MaxConcurrentCalls));
   6: Trace.WriteLine(String.Format("MaxConcurrentSessions = {0}",
   7:     throttle.MaxConcurrentSessions));
   8: Trace.WriteLine(String.Format("MaxConcurrentInstances = {0}",
   9:     throttle.MaxConcurrentInstances));

Limity

WCF umożliwia ustawienie limitu (ang. quota) na ilość pamięci wykorzystywanej przez host serwisu i implementujące go obiekty. Zabezpiecza to przed nadmiernym alokowaniem pamięci. Każde kolejne wywołania które spowodują brak możliwości zaalokowania pamięci do obsługi tych wywołań zakończą sie wyjątkiem OutOfMemoryException lub StackOverflowException.

Jeśli ustawimy limity to po przekroczeniu limitu będzie wyrzucany wyjątek QuotaExceededException a wiadomość jest po prostu pomijana i serwis przechodzi do obsługi kolejnej.

Mamy kilka dostępnych limitów:

MaxReceivedMessageSize

– maksymalna wielkość wiadomości, domyślnie 65536 bajtów

<bindings>
    <netTcpBinding>
        <binding name="netTcp"
            maxReceivedMessageSize="128000" />
    </netTcpBinding>
</bindings>
NetTcpBinding binding = new NetTcpBinding();
binding.MaxReceivedMessageSize = 128000;
ServiceHost host = new ServiceHost( typeof(UpdateService),
    new Uri("net.tcp://localhost:1234/UpdateService"));
host.AddServiceEndpoint( "IUpdateService",
    binding, String.Empty);
host.Open();
ReaderQuotas

– limity złożoności wiadomości,

Obiekt ReadeQuotas ma kilka właściwości, które umożliwiają określenie maksymalnej złożoności wiadomości:

  • MaxDepth – maksymalna złożoność (głębokość zagnieżdżenia XML’a reprezentującego wiadomość), domyślnie 32
  • MaxStringContentLength – maksymalna długość wartości typu string w wiadomości (wartości lub atrybutu, lub tekstu wewnątrz znacznika), domyślnie 8192 bajty,
  • MaxArrayLength – maksymalna liczba elementów w pojedynczej tablicy, domyślnie 16384,
  • MaxBytesPerRead – maksymalna liczba bajtów zwracanych przy metodzie Read podczas przetwarzania wiadomości, domyślnie 4096 bajtów,
  • MaxNameTableCharCount – maksymalna liczba znaków w nazwie tablicy, domyślnie 16384 znaków.

Może ograniczenie liczby zwracanych bajtów w metodzie Read wydaje się dziwne, ale służy to zabezpieczeniu przeciw atakom DoS, których wiadomość zawiera bardzo długie rozpoczynające tagi w wiadomości. Ponieważ do przetworzenia konieczne jest wczytanie całego taga do pamięci, ograniczenie tego zapobiega przepełnieniom.

Rozgraniczenia operacji

Teoretycznie obsługa sesji gwarantuje nam, że wiadomo które wiadomości przychodzą od którego klienta. Sesja umożliwia też zapamiętywanie stanu pomiędzy poszczególnymi wywołaniami. A czy mamy gwarancję że wywołania przyjdą w odpowiedniej kolejności? Nie! Wystarczy że dwie metody będą wywoływane w różnych wątkach i już mamy zachwianie kolejności. Protokół HTTP w ogóle nie gwarantuje kolejności przesyłanych wiadomości.

WCF udostępnia mechanizm oznaczania, które metody nie mogą być wywoływane jako pierwsze lub jako ostatnie przez ustawienie właściwości IsInitiating i IsTerminating w atrybucie OperationContract.

Jeśli IsInitiating jest ustawiony na true w momencie gdy sesja nie została utworzona,sesja jest tworzona. Jeśli sesja już istnieje, metoda jest wywoływana w ramach tej sesji.

Jeśli IsTerminating jest ustawiony na true, gdy metoda jest wywoływana, sesja jest kończona. Nie oznacza to tego samego co zakończenie połączenia, klient nadal musi wywołać metodę Close na obiekcie proxy aby zamknąć połączenie. Każde kolejne próby wywoływania metod serwisu po zakończeniu sesji będą generować wyjątki InvalidOperationException.

Domyślne wartości dla tych właściwości to true dla IsInitiating i false dla IsTerminating.

Poniżej przykład kontraktu z odpowiednimi wartościami tych atrybutów:

[ServiceContract(SessionMode = SessionMode.Required)]
public interface IProcessOrders
{
    [OperationContract]
    void InitializeOrder(int customerId);
 
    [OperationContract(IsInitiating=false)]
    void AddOrderLine(string productId, int quantity);
 
    [OperationContract(IsInitiating=false)]
    double GetOrderTotal();
    
    [OperationContract(IsInitiating=false, IsTerminating=true)]
    bool SubmitOrder();
}

Z powyższych czterech metod tylko InitializeOrder może rozpocząć sesję, więc każda inna metoda wywołana przed nią spowoduje wyrzucenie wyjątku OperationException. Wywołanie metody SubmitOrder spowoduje zakończenie sesji, żadna inna metoda nie może już być wywołana w tym połączeniu.

Aby użyć tych właściwości serwis musi obsługiwać sesję (przez tryb “per session”, albo “singleton”).

Deaktywowanie instancji

Gdy rozpoczynana jest nowa sesja WCF tworzy nowy kontekst (Context) i w ramach tego kontekstu tworzone są instancje obiektów obsługujące wywołania. WCF pozwala nawet utworzyć kontekst bez instancji. Przy pomocy właściwości ReleaseInstanceMode atrybutu OperationBehavior możemy decydować kiedy instancje mają być zwalniane. Dostępne są następujące opcje:

  • BeforeCall – nowa instancja jest tworzona z początkiem wywołania, jeśli instancja już istnieje, jest deaktywowana i wywoływała jest jej metoda Dispose, klient jest w tym czasie zablokowany,
  • AfterCall – aktualna instancja jest deaktywowana i zwalniana gdy metoda jest zakończona,
  • BeforeAndAfterCall – aktualna instancja jest zwalniana przed wywołaniem, tworzona jest nowa, która zaraz po zakończeniu metody jest zwalniana,
  • None – instancja nie jest zwalniana między wywołaniami metod, wartość domyślna.
public class UpdateService : IUpdateService
{
    [OperationBehavior(ReleaseInstanceMode=ReleaseInstanceMode.BeforeAndAfterCall)]
    public void Update()
    {
        // Implementation code goes here
    }
}

Możemy także zwolnić instancję zaraz po zakończeniu aktualnej metody przez :

OperationContext.Current.InstanceContext.ReleaseServiceInstance();

W kolejnych artykułach opowiemy o obsłudze transakcji.

Tagi: , , , , ,

70-562:Using ASP.NET Membership

Artykuł pochodzi w serii przygotowań do egzaminu 70-562 ASP.NET.

W dzisiejszym artykule powiemy sobie o używaniu kontrolki logowania, zarządzaniu użytkownikami, informacjami na ich temat oraz o rolach. To wszystko zrealizujemy używając mechanizmu Membership.

Użycie WSAT do konfigurowania zabezpieczeń

Do zarządzania użytkownikami, rolami oraz zabezpieczeniami na naszej stronie możemy użyć wbudowanego narzędzia Web Site Administration Tool (WSAT).

Tworzenie użytkowników

Aby uruchomić WSAT należy wybrać z menu ASP.NET Configuration. Konfiguracje użytkowników znajdziecie w zakładce Security. Najpierw musimy skonfigurować uwierzytelnianie. Mamy do wyboru uwierzytelnianie Windows, Lokalne Active Directory oraz uwierzytelnianie za pomocą formularza. Po wybraniu interesującego nas uwierzytelniania możemy stworzyć użytkownika, zarządzać nim, nadać mu role itp. Poniżej przykład tworzenia nowego usera:

image 

Jeśli wybraliśmy uwierzytelnianie oparte o formularze (Web-based), WSAT automatycznie stworzy lokalną baze i umieści ją w katalogu App_Data (no chyba że chcemy podczepić inną baze np. wygenerowaną tak jak w poprzednim wpisie). Doda również wpis do pliku Web.config, który włącza nasze uwierzytelnianie:

   1: <configuration>
   2:  <system.web>
   3:   <authentication mode="Forms" />
   4:  </system.web>
   5: </configuration>
Tworzenie ról

Aby włączyć role wystarczy odpalić WSAT i kliknąć w link, który je włącza :) Po włączeniu ról, WSAT doda do Web.Config taki kod:

   1: <configuration>
   2:  <system.web>
   3:   <roleManager enabled="true" />
   4:  </system.web>
   5: </configuration>

Teraz możemy już tworzyć własne role i przypisywać do nich użytkowników. Robi się to podczas tworzenia nowego użytkownika ew. podczas jego edycji :)

Podobnie działa mechanizm “Acces Rules”, dzięki któremu możemy określić kto ma dostęp do folderu czy pliku. Również wszystko robimy z poziomu WSAT.

Kontrolka Login

Istnieje kilka kontrolek, wbudowanych w ASP .NET, dzięki którym możemy zarządzać logowaniem i informacjami na temat logowania. Dostarczają one interfejs użytkownika i szereg metod pomagających w zarządzaniu informacjami. Poniżej hierarchia:

image

 

CreateUserWizard – jest to “kreator”, dzięki któremu stworzymy nowego użytkownika.
Login – kontrolka, dzięki której dajemy użytkownikowi możliwość zalogowania się .
LoginView – kontrolki tej możemy użyć np. do udostępnienia linka, dostępnego dla zalogowanych użytkowików
LoginName – wyświetla bieżącego użytkownika (jeśli jest zalogowany)
PasswordRecovery – pozwala na zresetowanie hasła użytkownika poprzez wysłanie maila bądź odpowiedź na pytanie
ChangePassword – pozwala zmienić bieżące hasło.

Wszystkie kontrolki są bardzo proste w użyciu, więc nie będę opisywał po kolei (tak jak jest to opisane w TK), jak przeciągnąć na formatkę itp :) Myślę że każdy sobie z tym poradzi.

Klasa Membership

Poniżej najważniejsze statyczne metody klasy Membership, dzięki którym możemy ręcznie stworzyć użytkownika, usunąć itp:
CreateUser – dodaje nowego użytkownika do bazy danych.
DeleteUser – usuwa użytkownika z bazy
FindUsersByEmail – metoda wyszukuje użytkownika (z kolekcji użytkowników), do którego pasuje podany mail
FindUsersByName – tak jak wyżej tylko szukanie odbywa się po nazwie.
GeneratePassword – metoda ta tworzy losowe hasło o podanej długości
GetAllUsers – zwraca kolekcję wszystkich użytkowników znajdujących się w bazie
GetNumberOfUsersOnline – metoda zwraca ilość zalogowanych osób
GetUser – zwraca aktualnie zalogowanego użytkownika
GetUserNameByEmail – pobiera nazwę użytkownika na podstawie maila
UpdateUser – aktualizuje informacje o użytkowniku

Klasa Roles

Klasa Roles dostarcza wielu statycznych metod, dzięki którym możemy operować, zarządzać rolami.

AddUserToRole, AddUsersToRole i AddUsersToRoles – dodają użytkownika (użytkowników) do roli (ról)
CreateRole – tworzy nową role
DeleteRole – kasuje role
FindUsersInRole – znajduje użytkowników w podanej roli
GetAllRoles – zwraca wszystkie istniejące role
GetRolesForUser – zwraca role przypisane do podanego użytkownika
IsUserInRole – zwraca true, jeśli użytkownik należy do podanej roli
RemoveUserFromRole, RemoveUsersFromRole, RemoveUserFromRoles, i RemoveUsersFromRoles – usuwa użytkownika z roli

Jeśli np. chcemy przypisać użytkownika do roli, możemy napisać tak: (w tym przykładzie nazwa użytkownika brana jest z kontrolki CreateUserWizard):

   1: Roles.AddUserToRole(CreateUserWizard1.UserName, "Users");

To tyle na dziś. W następnym artykule będziecie mogli przeczytać o zabezpieczaniu strony. Zapraszam w imieniu Dawida :)

Tagi: , , , , , ,

70-503: Instancing Modes

Ten artykuł pochodzi z serii przygotowań do egzaminu 70-503: Windows Communication Foundation.

WCF jest odpowiedzialny za wiązanie przychodzącego komunikatu do określonej instancji serwisu. Tryb wystąpienia (ang. instance mode) określa związek pomiędzy klientem a instancją serwisu (np. czy istniejąca instancja serwisu jest w stanie przetworzyć żądanie). Ta lekcja przedstawia, różne rodzaje możliwych wystąpień, sposób w jaki są tworzone i konsekwencje wyborów.

Dla InstanceContextMode dostępne są trzy wybory: per call mode, per session mode oraz singleton mode.

Co wywołanie

Domyślnym trybem jest PerCall, który utrzymuje asocjację jeden-do-jednego pomiędzy wywołaniami metod a instancjami serwera. Każde pojedyncze żądanie dostaje swoją własną kopię serwisu (obiektu serwisu). Klient wywołuje żądanie do serwisu poprzez obiekt proxy. Kiedy żądanie dochodzi do serwisu, host tworzy instancję serwisu. Obiekt ten jest następnie wywoływany w celu przetworzenia tego żądania. Kiedy zostanie ono już przetworzone a odpowiedź zwrócona do klienta, obiekt jest usuwany.

image

Jakkolwiek jest to metoda prosta w użyciu, nie oznacza to, że zawsze jest najlepsza. Ograniczony zasób (ang. scarce resource) to taki, który jest kosztowny u utworzeniu, lub ilość jego wystąpień jest ograniczona. Przykłady takich zasobów to pliki na dysku twardym komputera, połączenia do bazy danych, połączenia sieciowe, komunikacja przez porty. W takim wypadku tylko jedna instancja serwisu jest w stanie korzystać z zasobu, pozostałe muszą czekać na swoją kolej.

Tryb wystąpienia ustawiany jest po stronie serwisu. Poniższy przykład demonstruje sposób, w jaki można ustawić tryb na PerCall:

   1: [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
   2: class UpdateService : IUpdateService {...}

W tym trybie nie przekazywany jest stan aplikacji między wywołaniami metod. Ogólnie tryb ten najlepiej sprawdzi się kiedy indywidualne operacje są szybkie i nie składają się z żadnych zadań w tle, które kontynuują działanie nawet po obsłużeniu żądania.

Tryb sesji

image Tryb PerSession tworzy instancję dla każdego proxy klienta. W tym trybie WCF utrzymuje prywatną sesję pomiędzy klientem a określoną instancją serwisu. Klient, podczas pierwszego żądania do serwisu, otrzymuje instancję serwisu, która jest przeznaczona do obsłużenia żądań tego klienta. Wszystkie następujące potem żądania danego klienta są uznawane za część tej samej sesji, a wywołania są przetwarzane przez tę samą instancję serwisu.

Aby korzystać z tego trybu właściwość SessionMode musi zostać ustawiona na SessionMode.Required, co spowoduje poinformowanie klienta, że sesja ma być prowadzona:

   1: [ServiceContract(SessionMode = SessionMode.Required)]
   2: public interface IUpdateService
   3: {
   4: // ...
   5: }

Druga część konfiguracji to odpowiednie ustawienie InstanceContextMode:

   1: [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
   2: public class UpdateService : IUpdateService
   3: {
   4: // ...
   5: }

Instancja serwisu istnieje dopóki klient jej potrzebuje. Kiedy zakończy korzystanie ma możliwość zamknięcia proxy. Jeżeli tego nie zrobi sesja zakończy się automatycznie po dziesięciu minutach nieaktywności. Po tym czasie żądanie do serwisu spowoduje wyrzucenie wyjątku CommunicationObjectFaultedException. Przykład zmiany tej wartości dla netTcpBinding:

   1: NetTcpBinding binding = new NetTcpBinding();
   2: binding.ReliableSession.Enabled = true;
   3: binding.ReliableSession.InactivityTimeout = TimeSpan.FromMinutes(60);

Przykład deklaratywny:

   1: <netTcpBinding>
   2:  <binding name="timeoutSession">
   3:   <reliableSession enabled="true" inactivityTimeout="01:00:00"/>
   4:  </binding>
   5: </netTcpBinding>

Uwaga: basicHttpBinding nie jest w stanie przekazać informacji związanej z sesją!

Tryb pojedynczego wystąpienia (Singleton)

W tym trybie tworzona jest tylko jedna instancja serwisu. Obsługuje ona każde żądanie, które dociera do serwisu. Instancja nie jest usuwana, trwa do wyłączenia procesu hostującego go. Tryb ten nie wymaga danych sesyjnych podczas przesyłania komunikatów. Przykład ustawienia trybu:

   1: [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
   2: public class UpdateService : IUpdateService
   3: {
   4: // ...
   5: }

Najlepsze zastosowania tego trybu to takie, które modelują pojedynczy zasób – plik dziennika zdarzeń (log), komunikacja z pojedynczym robotem.

Podsumownie

Kiedy należy odpowiedzieć na pytanie, który tryb wystąpienia jest najlepszy, należy stwierdzić, że nie ma jednej poprawnej odpowiedzi. Wiele czynników musi zostać rozważonych, aby określić, “ten odpowiedni”. Wybór uzależniony jest od konkretnego zastosowania.

Tagi: , , , ,