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ć…


MTS – przygotuj swój harmonogram!

Dziś o godzinie 00:00 na stronie MTS została udostępniona opcja przygotowania harmonogramu na nadchodzącą konferencję. Dwa dni wcześniej została otworzona rejestracja na sesje dla osób, które jako pierwsze zarejestrowały się na konferencję (lub wygrały na nią wstęp) zgodnie z informacją o pierwszeństwie widniejącą na stronie. Co wybrałem?

Po sesji generalnej posłucham o “Tworzenie wydajnych usług w technologii WCF”, jako że pasjonuje mnie ta technologia. Po przerwie obiadowej przyjdzie czas na “VS 2010 IDE Tips and Tricks” – takich informacji nigdy za wiele :) , w następnej kolejności  “Wiele Ciekawych Funkcji 4.0, czyli leniwym żyje się łatwiej” – lenistwo to jedna z wymaganych cech programistów :). Na koniec dnia “Lap around new things in .NET Framework 4.0”.

Środę rozpocznę od “Wprowadzenie do F#” – jakoś nie mogę się zabrać do autowprowadzenia do F# :), dalej Bartek Pampuch opowie o “Visual Studio 2010 – Deep Dive” – na Bartka zawsze można liczyć!. Po obiedzie “Budowanie aplikacji biznesowych w Silverlight 4 i WCF RIA Services” – ku poszerzaniu horyzontów a na sam koniec “Asynchroniczny model programowania w .Net.”.


WCFTestClient – edycja konfiguracji testowanego serwisu

Pewnego razu korzystając z WcfTestClient przyszło mi dla testów zmienić konfigurację wiązań (binding). Nie byłem pewien, czy narzędzie to udostępnia taką możliwość, ale zostałem mile zaskoczony. Posłużę się bibliteką z poprzedniego posta. Pod prawym przyciskiem w drzewie “projektu” WcfTestClient dla pliku Config File jest dostępne kilka opcji – między innymi poszukiwana przeze mnie zmiana konfiguracji.

Edycja odbywa się poprzez SvcConfigEditor, który jest całkiem wygodny i pozwala uniknąć niektórych błędów konfiguracji.

W razie konieczności można oczywiście przywrócić domyślną konfigurację wybierając opcję “Restore to Default Config”.


WCFTestClient – korzystanie z tablic

Jeżeli mamy do przetestowania przy pomocy WcfTestClient serwis oferujący kontrakt z obiektami typu List<someType> lub someType[] na pierwszy rzut oka może to być problem. Żeby móc to zaprezentować zmieniłem nieco standardowo wygenerowany przez Visual Studio projekt WcfServiceLibrary:

  1     [DataContract]
  2     public class CompositeType
  3     {
  4         [DataMember]
  5         public List<int> IntListProperty { get; set; }
  6
  7         [DataMember]
  8         public int[] IntArrayProperty { get; set; }
  9
10         [DataMember]
11         public string ResultString { get; set; }
12     }

 

Po uruchomieniu projektu (F5) uruchamia się WCF Service Host i WcfTestClient

Aby wprowadzić wartości, które nas interesują należy w polu value wpisać ile ich chcemy podać. Wówczas jak poniżej wygenerują się odpowiednie pola i będziemy mogli je uzupełnić.

Analogicznie sprawa wygląda dla typów przekonwertowanych na ArrayOfSomeType.


Ostatni dzień promocji na Microsoft Technology Summit!

Microsoft Technology Summit 2010

Już tylko do końca dnia jutrzejszego obowiązuje promocja na MTS – 690zł (dla grupowiczów 540zł), zatem jeżeli jeszcze się nie zarejestrowałaś/eś zrób to teraz.

Ciekawą rzeczą, którą można znaleźć na stronie MTS 2010 jest możliwość powiadomienia o konferencji swojego szefa i przesłania mu rzeczowo przygotowanego emaila poprzez szablon oferowany na stronie.


Microsoft Technology Summit 2010, zniżki dla grup offline

W tym roku po raz kolejny bedziemy mogli uczestniczyć w jednej z największych w Polsce konferencji poświęconych technologii czyli Microsoft Technology Summit 2010, która odbędzie się w Warszawie w dniach 5-6 października 2010. Statystyki mówią same za siebie: około 100 sesji tematycznych, prelegenci z calego świata, 11 obszarów tematycznych, strefy ask the expert, laboratoria i wiele wiele innych, zatem każdy znajdzie coś dla siebie.

Czy warto? Warto. Jeżeli nie przekonują Cię statystyki, to dodatkowo będzie możliwość spotkania się z nami, czyli grupami offline na naszym stoisku społecznościowym. Po raz kolejny bedzie możliwość wystartowania w konkursie Speaker Idol, w którym oprócz nagród rzeczowych (którymi w tym roku jest na przykład Xbox 360!) można wygrać możliwość poprowadzenia własnej sesji podczas następnej koferencji!

Do końca czerwca obowiązuje zniżka 690 zł. Czy to dużo? Więcej niż podczas poprzednich edycji, jednakże i w tym roku Microsoft wyszedł na przeciw społecznościom i dla osób, które zarejestrowały się na spotkania lub wydarzenia organizowane przez grupy offline pomiędzy wrześniem 2009 a końcem maja 2010 otrzymują w pierwszej fazie rejestracji zniżkę 540zł, a później 790zł – warunkiem koniecznym jest rejestracja przy wykorzystaniu adresu email takiego jak na portalu ms-groups.pl oraz kodu promocyjnego, który powinniście otrzymać od lidera grupy, do której należycie. W przypadku problemów zawsze można się z nami skontaktować poprzez witrynę ms-groups.pl lub adresy email, które od nas otrzymaliście. Tak czy inaczej sądzę, że warto namówić szefa, lub też samego siebie na wydanie tych pieniędzy by móc uczestniczyć w tym wielkim wydarzeniu branży IT.

Spotkajmy się zatem na MTS2010 – ja tam będę!


Rysunkowe wyjaśnienie systemu motywacji

Oryginalne w swojej formie przemyślenia dotyczące systemów motywacji. Początkowo znalezione na antyweb.pl. Zgodzę się z Grzegorzem – fenomenalne podsumowanie dotyczące wolontariatu dla dobra wspólnego :)

Więcej tego typu filmów można znaleźć na stronie RSA Comment.


Zdjecia z Visual Studio 2010 Community Launch w Toruniu

Na witrynie TGD.NET dodałem zdjęcia z toruńskiej edycji VS2010CL. Możecie je znaleźć tutaj. Serdecznie zapraszam!


  • 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: