HOW TO

DBML to SQL

Gdy przygotowywałem stronę z projektami i byłem przy ShipBattleChallenge, gdy okazało się, że przed formatowaniem dysku nie zrobiłem backupu bazy danych dla turnieju SBC. Tak – zrobiłem mini programik, który zamiast mnie uruchamia odpowiednie walki botów i loguje przebiegi walk do bazy – Tournament Master :). W związku z tym, że nie jest to kluczowe dla projektu postanowiłem wyłączyć to z solucji. Jednakże po chwili namysłu stwierdziłem, że skoro w dbml’u sa informacje na temat tabel, to może coś da się z tym zrobić… Dziś udało mi się zasiąść do tematu i poszukać co i jak. Okazuje się, że obiekty typu DataContext posiadają metodę CreateDatabase(), która potrafi przywrócić zaimportowane do dbml’a struktury i relacje z bazy. Oczywiście obejmuje to tylko DDL (ang. Data Definition Language), a nie DML. W moim przypadku było to w zupełności wystarczające, gdyż korzystałem z bazy poprzez LINQ to SQL – bardziej dla testów niż z przekonania, ale okazało się to przydatne.

Jak to zrobić? Wystarczy skorzystać z poniższego kawałka kodu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private static void RestoreDB()
{
	try
	{
		DataClasses1DataContext bd = new DataClasses1DataContext(DbmlTest.Properties.Settings.Default.DbmlTestNewConnectionString);
		if (bd.DatabaseExists())
		{
			Console.WriteLine("Database exists");
			bd.DeleteDatabase();
			Console.WriteLine("Database deleted");
		}
		bd.CreateDatabase();
		Console.WriteLine("Database restored");
	}
	catch (Exception ex)
	{
		Console.WriteLine("Error");
		Console.WriteLine(ex.ToString());
	}
}

Dla porządku dodam, że nie trzeba korzystać z konstruktora wymagającego connection stringa, lecz śmiało można użyć domyślnego. W demie mam zdefiniowane połączenia do dwóch baz, starej i nowej (docelowa baza do odtworzenia), dlatego wybrałem takie rozwiązanie.

Pobierz przykład


WCF service error HTTP could not register URL

Na dobry początek pracy pod nową domeną postanowiłem napisać na temat błędu przy uruchamianiu serwisu WCF jakim jest “HTTP could not register URL …“. O rozwiązaniu tego problemu często się zapomina, a jest ono stosunkowo proste. Zacznijmy od początku, czyli od opisu przypadku.

Przypadek:
Tworzymy usługę WCF, która jest udostępniana poprzez aplikację konsolową i korzysta z wiązań z rodziny *HttpBinding. Podczas uruchamiania hosta otrzymujemy błąd:
“HTTP could not register URL http://+:8733/Design_Time_Addresses/SampleServiceLibrary/SampleService/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details).”
Dla jasności – jeżeli udostępniamy metadane dotyczące serwisu przy pomocy MEX, to również otrzymamy taki błąd.

Oczywiście podany przeze mnie adres może być inny, gdyż zakres http://+:8733/Design_Time_Addresses jest wykorzystywany przez WcfServiceHost.exe, który automatycznie uruchamia się dla bibliotek WCF.

Rozwiązanie:
W przypadku gdy korzystamy z *HttpBinding konieczne będzie umożliwienie naszemu procesowi nasłuchiwania żądań przychodzących po http. Podążając zatem za wskazanym w błędzie adresem dowiadujemy się, że należy dodać nam prawa do takiego nasłychu. W tym celu korzystamy z polecenia NETSH w konsoli cmd:
netsh http add urlacl url=http://+:8733/Design_Time_Addresses/SampleServiceLibrary/SampleService/ user=maciek

W pole URL należy oczywiście wpisać adres, na którym chcemy działać. Po wykonaniu tego polecenia nasz serwis uruchomi się poprawnie. Jeżeli okaże się, że nie jest nam już potrzebne przechwytywanie tego adresu, wówczas możemy go usunąć wpisując następujące polecenie:

netsh http delete urlacl url=http://+:8733/Design_Time_Addresses/SampleServiceLibrary/SampleService/


Problem z HttpCookie.Expires i jQuery

Dziś na temat korzystania z jQuery i ciasteczek. Jako scenariusz przyjmijmy proste zliczenie kliknięć, gdzie licznik przechowujemy jako wartość ciastka.

W tym celu tworzymy aplikację ASP.NET MVC wraz z testowym kontrolerem i dwoma widokami – Indeks, który jest widokiem bazowym i Modify, który zwraca kawałek html’a z zawartością ciastka.

Kotroler inicjujemy w następujący sposób:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Web;
  5 using System.Web.Mvc;
  6
  7 namespace CookieAndJQuery.Controllers
  8 {
  9     [HandleError]
10     public class TestsController : Controller
11     {
12         private static string CookieName = “TestCookie”;
13
14         public ActionResult Index()
15         {
16             return View();
17         }
18
19         public ActionResult Modify()
20         {
21             HttpCookie cookie = Request.Cookies[CookieName];
22             if (cookie == null)
23             {
24                 cookie = new HttpCookie(CookieName, “0”);
25                 cookie.Expires = DateTime.MaxValue;
26             }
27
28             int v = int.Parse(cookie.Value);
29             cookie.Value = (++v).ToString();
30             Response.Cookies.Add(cookie);
31             ViewData[“itemValue”]= cookie.Value;
32             return View();
33         }
34     }
35 }

Indeks ma za zadanie po kliknięciu przycisku wywołać akcję Modify w kontrolerze TestsController a następnie wstrzyknąć jej wynik do diva o id=”resultContainer”

  1 <%@ Page Language=“C#” Inherits=“System.Web.Mvc.ViewPage” %>
  2 <html>
  3 <head runat=“server”>
  4     <title>Index</title>
  5     <script src=“Scripts/jquery-1.4.1.min.js” type=“text/javascript”></script>
  6 </head>
  7 <body>
  8     <div>
  9         <input type=“button” id=“btnTestCookies” value=“ClickMe” />
10         <div id=“resultContainer”></div>
11     </div>
12     <script type=“text/javascript”>
13         $(“#btnTestCookies”).click(function () {
14             $.ajax(
15                 {
16                     url: “/Tests/Modify”,
17                     success: function (data) {
18                         $(“#resultContainer”).html(data);
19                     },
20                     cache: false,
21                     dataType: “html”
22                 }
23             );
24         });
25     </script>
26 </body>
27 </html>

 

Dla pełnego obrazu poniżej widnieje zawartość widoku Modify:

  1 <%@ Page Language=“C#” Inherits=“System.Web.Mvc.ViewPage” Buffer=“false” %>
  2 <div>
  3     <%= ViewData[“itemValue”] %>
  4 </div>

Skoro mamy już bazę do doświadczeń pora przejść do sedna problemu, a mianowiscie do obsługi ciastek. Jak zapewne zauważyliście kontroler w linii 25 ustawia czas wygaśnięcia ciastka na DateTime.MaxValue, czyli ciastko nigdy nie wygaśnie. Na pierwszy rzut oka nie widać problemu: wywołujemy akcję, akcja zmienia wartość ciastka, ciastko wraca do przeglądarki, klikamy ponownie, wartość wzrasta – super! Jednakże spójżmy jak faktycznie wygląda ciastko, które otrzymujemy:

Pierwsze wywołanie strony – tworzymy ciastko

Kolejne wywołanie strony – niestety jak widać poniżej czas wygaśnięcia ciastka przypadnie na koniec sesji:

Przez to po zamknięciu i ponownym uruchomieniu przeglądarki ciastko zostanie usuniete a tym samym licznik zostanie zresetowany…

Przyjrzyjmy się jak wygląda request i response. Korzystając z Fiddlera można podejrzeć treść nagłówka Cookies, w którym widać wszystko jak na dłoni:

Odpowiedź po pierwszym wywołaniu (ustawiamy ciastko)

Request przy kojelnych kliknięciach przycisku – jak widać brak przy żądaniu informacji o ekspiracji ciastka, co skuktuje opisanym zachowaniem.

Jak to ominąć? W przypadku, który miałem jako zadanie postanowiłem przy każdym takim wywołaniu ustawiać czas życia ciastka na DateTime.MaxValue, dzięki  czemu po ponownym uruchomieniu przeglądarki ciastko nadal tam jest…

  1 public ActionResult Modify()
  2 {
  3     HttpCookie cookie = Request.Cookies[CookieName];
  4     if (cookie == null)
  5     {
  6         cookie = new HttpCookie(CookieName, “0”);
  7         cookie.Expires = DateTime.MaxValue;
  8     }
  9
10     cookie.Expires = DateTime.MaxValue;
11     int v = int.Parse(cookie.Value);
12     cookie.Value = (++v).ToString();
13     Response.Cookies.Add(cookie);
14     ViewData[“itemValue”] = cookie.Value;
15     return View();
16 }

W wyniku tej modyfikacji informacja o ciastkach znajdująca się w odpowiedzi wygląda następująco

dzięki czemu przy kolejnym uruchomieniu przeglądarki ciastko nadal tam będzie gotowe do użycia :)


Przeklikaj swój świat! – kontrola zdarzeń myszki

Myszka – z pozoru urządzenie, które bez ludzkiej ręki nie jest w stanie nic zrobić. Błąd! Istnieje możliwość nadania jej “życia” poprzez wywoływanie odpowiednich zdarzeń z kodu aplikacji. Aby to osiągnąć przydatne może być wykorzystanie poniższego helpera, a właściwie szablonu helpera, który można w łatwy sposób rozszerzyć o kolejne metody:

  1 using System.Drawing;
  2 using System.Runtime.InteropServices;
  3 using System.Windows.Forms;
  4
  5 namespace ConsAppClicker
  6 {
  7     public static class MouseHelper
  8     {
  9         #region Internal
10         [DllImport(“user32.dll”, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
11         private static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);
12
13         private const int MOUSEEVENTF_LEFTDOWN = 0x02;
14         private const int MOUSEEVENTF_LEFTUP = 0x04;
15         private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
16         private const int MOUSEEVENTF_RIGHTUP = 0x10;
17         #endregion
18
19         #region LMB
20         public static void RaiseDoubleClick()
21         {
22             int x = Cursor.Position.X;
23             int y = Cursor.Position.Y;
24             RaiseLeftClick(x, y);
25             RaiseLeftClick(x, y);
26         }
27
28         public static void RaiseLeftClick()
29         {
30             int x = Cursor.Position.X;
31             int y = Cursor.Position.Y;
32             RaiseLeftClick(x, y);
33         }
34
35 private static void RaiseLeftClick(int x, int y)
36 {
37     mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, x, y, 0, 0);
38 }
39         #endregion
40
41         #region RMB
42         public static void RaiseRightClick()
43         {
44             int x = Cursor.Position.X;
45             int y = Cursor.Position.Y;
46             RaiseRightClick(x, y);
47         }
48
49         public static void RaiseRightClick(int x, int y)
50         {
51             mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, x, y, 0, 0);
52         }
53         #endregion
54
55         #region Position
56         public static void SetPosition(int x, int y)
57         {
58             Cursor.Position = new Point(x, y);
59         }
60         #endregion
61     }
62 }
63

Oferuje on możliwość ustawienia odpowiedniej pozycji kursora myszy oraz wywołania najważniejszych jej zdarzeń dla aktualnej pozycji. Jak widać przy pomocy PInvoke możemy wykorzystać wywołanie zdarzenia znajdujące się w bibliotece user32.dll, która przyjmuje flagę zdarzenia (bitowa flaga, lub ich suma) oraz współrzędne zdarzenia. Eksperymentując z tym helperem w
pewnym momencie zapewne zauważycie, że zdarzenie jest uruchamiane dla aktualnej pozycji kursora niezależnie od tego co jest podane w linii 51 (wywołanie mouse_event)… Dziwne zachowanie, być może zależy od czynników, do których jeszcze nie dotarłem podczas drążenia tematu. W związku z tym można by korzystać tylko z metody SetPosition oraz ze zmienionej postaci Raise*Click, na przykład:

  1 public static void RaiseRightClick(int x, int y)
  2 {
  3     mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
  4 }
 

Oto przykład wykorzystania, który przy domyślnych ustawieniach pulpitu i ikon (“Mój” komputer” w lewym gornym rogu) po dwóch sekundach od uruchomienia otworzy okno eksploratora plików.

  1 using System;
  2
  3 namespace ConsAppClicker
  4 {
  5     class Program
  6     {
  7         static void Main(string[] args)
  8         {
  9             Console.WriteLine(“Console mouse click demo”);
10             System.Threading.Thread.Sleep(2000);
11             MouseHelper.SetPosition(20, 20);
12             MouseHelper.RaiseDoubleClick();
13             Console.WriteLine(“Done!”);
14             Console.ReadLine();
15         }
16     }
17 }
 

Teraz ożywienie poczciwego “szczura” jest już w zasięgu ręki. Miłej zabawy!


Stopwatch – zmierz się z czasem!

Podczas naszej pracy często zdarza się nam zastanawiać jak szybko działa dany fragment kodu. Aby to sprawdzić wystarczy skorzystać z klasy Stopwatch znajdującej się w przestrzeni nazw System.Diagnostics.

Najczęściej będziemy korzystać z oferowanych przez obiekt tego typu metod Start() i Stop() oraz właściwości Elapsed. Sprawdźmy zatem jak długo potrwa pusta pętla przez cały zakres Int32:

  1 private static void StopwatchDemo()
  2 {
  3     Console.WriteLine(“For loop from 1 to {0} time test”, Int32.MaxValue);
  4     Stopwatch sw = new Stopwatch();
  5     sw.Start();
  6     for (int i = 0; i < Int32.MaxValue; i++) ;
  7     sw.Stop();
  8     Console.WriteLine(“Elapsed time {0}”, sw.Elapsed);
  9     Console.WriteLine(“Press [Enter] to close”);
10     Console.ReadLine();
11 }

A oto wynik działania kodu:

Jest też możliwość wielokrotnego wykorzystania obiektu Stopwatch używając metody Reset(), która zeruje jego wartość:

sw.Reset();
 

Jeżeli nie zresetujemy obiektu, wówczas wykonanie metody Start() spowoduje naliczanie czasu począwszy od jego poprzedniej wartości.

  1 private static void StopwatchNoResetDemo()
  2 {
  3     Console.WriteLine(“Stopwatch without Reset() test”);
  4     Stopwatch sw = new Stopwatch();
  5     for (int i = 0; i < 5; i++)
  6     {
  7         sw.Start();
  8         for (int j = 0; j < 10000000; j++) ;
  9         sw.Stop();
10         Console.WriteLine(“Elapsed time for i={0} loop: {1}”, i, sw.Elapsed);
11     }
12     Console.WriteLine(“Press [Enter] to close”);
13     Console.ReadLine();
14 }

 

A oto wynik:

 

Jak widać ta prosta do wykorzystania klasa pozwala dokładnie znaleźć miejsca, które są najwolniejsze i być może uda się je zoptymalizować…


SQL Search – koniec z ręcznym przeszukiwaniem struktur bazy!

SQL Search – narzędzie (DARMOWE) stworzone przez Red Gate pozwala nam spać spokojnie (a przynajmniej spokojniej) w momencie gdy wprowadzamy do bazy zmiany. Nie musimy już analizować różnic między wersjami bazy danych, mozolnie przeklikiwać się przez poszczególne procedury i funkcje w poszukiwaniu odwołań do wybranego przez nas pola w tabeli. Owszem, w Sql Server Management Studio mamy do dyspozycji drzewo zależności. Mamy tam procedury składowane, funkcje, tabele widoki, ale! Niestety nie możemy wyświetlić drzewa zależności dla pojedynczej kolumny. Dostając wynik zależności dotyczących tabeli [Persons].[Contats] nie wiemy tak naprawdę, która jej część jest użyta.

Przyjmijmy taki oto scenariusz:
Korzystamy z bazy [AdventureWorks], w niej znajduje się tabela [Person].[Contact], w niej mamy do dyspozycji następujące pola:
    [ContactID]
    [NameStyle]
    [Title]
    [FirstName]
    [MiddleName]
    [LastName]
    [Suffix]
    [EmailAddress]
    [EmailPromotion]
    [Phone]
    [PasswordHash]
    [PasswordSalt]
    [AdditionalContactInfo]
    [rowguid]
    [ModifiedDate]

Pewnego dnia ktoś, z pewnych przyczyn chce zmienić nazwę kolumny [AdditionalContactInfo] na dajmy na to [AdditionalInfo]. Mając do dyspozycji drzewo zalezności nie wiemy tak naprawdę gdzie ta kolumna jest wykorzystana. Musimy zatem sprawdzić każdą z zależności pod kątem jej wystąpienia. Dodatkowo nie dysponujemy możliwością szybkiego podglądu/przeniesienia do obiektów zależnych – musimy je ręcznie wyszukać.

Z pomoca przychodzi SQL Search. Pierwsza praca z bazą danych wymaga zaindeksowania jej struktury. Trwa to od chwili do kilku minut, w zależności od rozległości bazy.

  1. Integruje się on w pełni z SQL Server Management Studio nawet w wersji Express! Wystarczy skorzystać z przycisku na toolbarze, lub wcisnąć Alt + Ctrl + D.
  2. Mamy możliwość doprecyzowania co nas interesuje czyli: możemy wybrać dokładne dopasowanie, typ obiektu, bazę do przeszukania oraz serwer.
       
  3. Przeszukiwanie odbywa się w sposób ciągły/dynamicznie (“as you type”). Dzięki czemu od razu widzimy wyniki naszego działania.
  4. W przeciwieństwie do drzewa zależności możemy przenieść się do obiektu który wybraliśmy, dzięki czemu odpada nam kolejna część pracy, czyli mozolne przeszukiwanie.

Wyniki wyszukiwania dają nam informację o sposbie dopasowania – czy jest to dopasowanie tekstu, kolumny, nazwy klumny. Dodatkowo dla przejrzystości odnaleziona fraza jest podświetlana…

Czego brakuje? Szukam, szukam, ale narazie nie znalazłem :) Zachęcam do pobrania (przypomnę, że produkt jest darmowy!) i przetestowania


Publikowanie kodu – CodeHTMLer

Poszukując wygodnego sposobu na publikację kodu przy użyciu Windows Live Writera, którego używam do wygodniejszej publikacji trafiłem na CodeHTMLer. Po ściągnięciu paczki, która zajmuje zaledwie 23KB i jej rozpakowaniu mamy do dyspozycji 4 pliki:

To co należy zrobić to uruchomić plik install.bat – należy pamiętć, by zrobić to w trybie administratora. Dlaczego? Spójrzmy na jego zawartość:

  1 @echo off
  2 REM To Install the CodeHtmler LiveWriter Plugin
  3 REM Copy CodeHtmler.dll and CodeHtmler.LiveWriterPlugin.dll into %Program Files%\Windows Live\Writer\Plugins
  4
  5 setlocal
  6
  7 set PLUGINDIR="%ProgramFiles%\Windows Live\Writer\Plugins\"
  8 set CODELOCATION=%~dp0
  9
 10 IF "%1" NEQ "" set CODELOCATION=%~dp1
 11
 12 XCOPY /D /Y /R "%CODELOCATION%CodeHtmler.dll" %PLUGINDIR%
 13 XCOPY /D /Y /R "%CODELOCATION%CodeHtmler.LiveWriterPlugin.dll" %PLUGINDIR%
 14
 15 endlocal

Instalacja polega na przekopiowaniu CodeHtmler.dll i CodeHtmler.LiveWriterPlugin.dll do katalogu pluginów Live Writera. Wybór należy do was.

Co dobrego daje nam ta wtyczka? Przede wszystkim ławtość użycia. Po zainstalowaniu obok innych wtyczek (Hyperlink, Picture, Photo album, …) pojawia nam się opcja “Code”. Po jej wybraniu mamy takie oto okno:

Do wyboru oprócz numerowania linii mamy 8 predefiniowanych kolorowań składni dla najpopularniejszych języków, dzięki czemu nie trzeba tracić czasu na ich definiowanie i można zacząć pracę od zaraz. Jeżeli jednak coś jest nie tak i wymaga zmiany, zawsze można wybrać opcję “Edit languages”. Udostępnia ona możliwość edycji wszystkich elementów kodu (zaznaczone na zielono) do której możemy przy pomocy wyrażeń regularnych w prosty sposób dodać nasze własne elementy.

A oto wynik transformacji kodu, który widać w okienku “Insert code”:

  1 /// <summary>
  2 /// Summary description for Main.
  3 /// </summary>
  4 static void Main(string[] args)
  5 {
  6   // string variable
  7   string myString = “myString”;
  8
  9   /* integer�
10      variable */

11   int myInt = 2;
12 }
 

Dla osób, które nie korzystają z Live Writera istnieje alternatywa w wersji online na tej stronie. Nie oferuje ona edycji kolorowania składni, lub też własnego definiowania tych elementów, jednakże taki urok online :)


Visual Studio 2010 – box selection i multi-line editing

Box selection to funkcjonalność, która pojawiła się już wcześniej w Visual Studio 2008. Dzięki niej możemy inaczej niż do tej pory (w sposób ciągły) zaznaczyć fragment kodu a następnie na przykład w jego obrębie coś zmienić (np atrybut dostepności pól publicznych na pola prywatne.

Tak to było kiedyś – standardowe zaznaczenie:

Coraz lepiej – zaznaczenie typu box oraz szybka podmiana:

 

Jak to zrobić? Wystarczy podczas zaznaczania wcisnąć lewy przycisk ALT – wówczas w miejsce zaznaczania linia po linii pojawia nam się box wyznaczony przez ruch kursora.

Tak to wyglądało w poprzedniej wersji. Podczas prac nad Visual Studio 2010 zabrakło tej opcji w wersjach przed RC, natomiast w wersji finalnej IDE była na swoim miejscu. Godne uwagi, a może wręcz przydatniejsze niż box selection jest multi-line editing. Na czym to polega? Nie trzeba już używać “podmiany” tekstu.

Jak? Zaznaczamy z użyciem lewebo przycisku ALT, a następnie zwyczajnie zaczynamy pisać. W każdej z linii objętych zaznaczeniem zacznie pojawiać się tekst, który właśnie wpisujemy.

 

W analogiczny sposób możemy zmieniać np prefixy właściwości klasy, lub dodawać komentarz

 

Obie funkcjonalności moim zdaniem godne polecenia i zapewne przydatne w codziennej pracy z kodem.
Filmik na Youtube
Wiecej na blogu Visual Studio


Sql Server Management Studio – Saving changes is not permitted

Gdy podczas edycji tabeli przy użyciu Sql Server Management Studio pojawi się komunikat:

“Savin changes is not permitted. The changes you have made require the following tables to be dropped and re-created ….”

Aby tego uniknąć wystarczy uruchomić Menu –> Tools –> Options –> Designers –> Table and Database Designers i odznaczyć pole “Prevent saving changes that require table re-creation”

Gotowe!


Velocity – dynamiczna konfiguracja klienta

Od pewnego czasu zgłębiam tajniki projektu Velocity, czyli rozproszonego cache osadzonego w pamięci oferowanego przez Microsoft. Po tym jak przyjżymy się aplikacji (np webowej) zauważymy jeden bardzo dotkliwy problem. Wyobraźmy sobie dobrze zaprojektowany klaster serwerów obsługujących Velocity z wysoką dostępnością danych, regionami, odpowiednio ustalonymi politykami zarządzania obiektami w cache. Połączenie do klastra odbywa się poprzez leading host, który jest odpowiedzialny za komunikację pomiędzy klientem i klasterm. Jednakże co w przypadku, gdy taki host przestaje odpowiadać?

Pierwsze co robimy to wystartowanie hosta w klastrze, który będzie odpowiadał za komunikację.

W tym momencie możemy bez żadnych przeszkód uruchomić aplikację, w której host nie jest pobierany z pliku konfiguracyjnego, tylko ustawiany w kodzie jak widać poniżej:

Uruchomienie przebiega pomyslnie – czyli tak jak powinien. Zobaczmy zatem co dzieje się w przypadku niedostępności hosta. Aby móc to przetestować trzeba zasymulować padnięcie serwera.

Próba skorzystania z polecenia Stop-CacheHost w przypadku pojedynczego hosta w klastrze powoduje błąd kworum klastra – bo nie może on istnieć bez żadnego hosta… Oczywiste. Pozostaje zatem zatrzymanie całego klastra i zbadanie jak zachowa się aplikacja.

 

Jak to rozwiązać? W projekcie dodajemy klasę EndpointsProvider będącą definicją providera odczytującego informacje o endpointach czy to z bazy, czy nawet ze źródla RSS.

Przy użyciu powyższego kodu proces inicjacji fabryki trwa tak długo, aż utworzenie istancji cache nie spowoduje zrzucenia błędu typu DataCacheException (lub wyczerpania puli hostów, lecz uznaję to za przypadek mało prawdopodobny w momencie utworzenia klastra z kilkoma serwerami i leading hostami…)

Mam nadzieję, że ten prosty workaround pomoże wam w rozwiązaniu problemu dynamicznej konfiguracji aplikacji bez konieczności zmian w plikach konfiguracyjnych.


  • O mnie

    Maciej Grabek

    Moje profile na:

    MVP

    Codeguru.pl GoldenLine
    Twitter CodeProject

  • english version
  • Polecam

  • Copyright © Maciej Grabek. All rights reserved.
    Powered by WordPress
    %d bloggers like this: