10/12/2008

Czemu zdarzenia nie działają???

Home

Ostatnio pomogłem rozwiązać dwa problemy z "nie działającymi" zdarzeniami. Jak to najczęściej bywa, znając rozwiązanie, problem wydaje się banalnie prosty. Ponieważ jednak dojście do rozwiązania nie zawsze jest już tak proste postanowiłem napisać ten post.

Ogólnie problem został mi przedstawiony mniej więcej w taki sposób (luźny cytat): Podczepiłem się pod zdarzenia kilku kontrolek ale po wykonaniu post back'a do strony, metody obsługi zdarzeń nie są wołane.

W obu wspomnianych sytuacjach obserwowany efekt był taki sam (metody obsługi zdarzeń nie były wołane), natomiast przyczyna błędu troszeczkę inna. Błędu, ponieważ to oczywiście nie bug w maszynerii ASP.Net tylko najzwyklejszy w świecie błąd programisty.

Problem numer 1

W pierwszym przypadku programista dynamicznie tworzył kontrolkę, subskrybował jej zdarzenia, a następnie dodawał ją do strony. Dla ustalenia uwagi przyjmijmy, że była to kontrolka ListBox. Opisywany kod mógł więc wyglądać następująco:
...
ListBox lb = new ListBox();
lb.AutoPostBack = true;
lb.SelectedIndexChanged += new EventHandler(lb_SelectedIndexChanged);
lb.Items.Add("a");
lb.Items.Add("b");
lb.Items.Add("c");

this.Panel.Controls.Add(lb);
...
Sam w sobie, kod ten jest jak najbardziej poprawny. Błąd polegał na tym, że kod ten był wykonywany tylko w przypadku inicjalnego odwołania do strony. W przypadku post back'a czyli kiedy właściwość IsPostBack była równa true już nie. A skoro kontrolka nie została utworzona to zdarzenie nie mogło zostać wygenerowane.

Problem numer 2

W drugim przypadku programista używał statycznie osadzonej na stronie kontrolki DataList, zasilał ją danymi i wołał metodę DataBind. Kod strony przypominał koncepcyjnie kod poniżej:
...
this.DataList.DataSource = new string[] { "a", "b", "c" };
this.DataList.DataBind();
...
...
<asp:DataList ID="DataList" runat="server" EnableViewState="false">
   <ItemTemplate>
      <asp:Button ID="Button" runat="server" Text="<%# Container.DataItem %>" OnClick="OnClick" />
   </ItemTemplate>
</asp:DataList>
...
Podobnie jak wcześniej, strona nie działała tak jak powinna, ponieważ w przypadku post back'a nie była wołana metoda DataBind kontrolki DataList i przyciski nie były tworzone i w związku z tym zdarzenia nie mogły zostać wygenerowane. W tym jednak przypadku, pośrednią przyczyną błędu był fakt, że View State został wyłączony. Gdyby był włączony, przyciski zostałyby odtworzone na jego podstawie.

Wnioski

Konkluzja jest bardzo prosta. W przypadku dynamicznego tworzenia kontrolek, czy to bezpośrednio czy to przy okazji użycia kontrolek data bound zawsze należy pamiętać aby dynamiczne kontrolki były tworzone nie tylko przy inicjalnym odwołaniu do strony ale również przy kolejnych.

08/12/2008

Włączanie i wyłączanie kaskadowych arkuszy stylów

Home

Jeśli potrzebujemy szybki i łatwo zaimplementować włączanie i wyłączanie kaskadowych arkuszy stylów na stronie możemy zastosować taki kod:
...
<head runat="server">
    <link id="link" 
        type="text/css" 
        rel="Stylesheet"
        href="~/style.css" 
        runat="server" />
</head>
...
Teraz wystarczy sterować widocznością serwerowej kontrolki Html. Jeśli kontrolka nie będzie widoczna:
this.link.Visible = false;
to nie zostanie wzięta pod uwagę podczas renderowania strony i styl nie zostanie zastosowany do strony. Odwrotnie, jeśli kontrolka będzie widoczna:
this.link.Visible = true;
to podczas renderowania strony zostanie uwzględniona i styl zostanie zastosowany do strony. Bardzo proste ale skuteczne.

04/12/2008

Transformacje Xsl i przestrzenie nazw XML

Home

Przy używaniu transformacji Xsl należy pamiętać o przestrzeniach nazw Xml. Załóżmy, że mamy dokument Xml i transformację Xsl do jej przetwarzania:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type='text/xsl' href='Transformation.xsl'?>
<A>
   <B>
      bbb
   </B>
   <B>
      bbb
   </B>
</A>
Transformajca wygląda natomiast tak:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" standalone="no" omit-xml-declaration="yes" encoding="windows-1250" />

<xsl:template match="B" >
   <LI>
      <xsl:value-of select="current()"/>
   </LI>
</xsl:template>

<xsl:template match="A" >
   <HTML>
      <HEAD>
      </HEAD>
      <BODY>
         <UL>
            <xsl:apply-templates select="B"/>
         </UL>
      </BODY>
   </HTML>
</xsl:template>

</xsl:stylesheet>
Wynikiem działania przedstawionej transformacji na przykładowym dokumencie Xml powinna być lista:
  • bbb
  • bbb
Wynik będzie zupełnie inny jeśli zmodyfikujemy dokument Xml w następujący sposób:
...
<A xmlns="a.b.c">
...
Po tej zmianie otrzymamy taki, mało przyjazny rezultat transformacji:
bbb bbb
Aby rozwiązać problem należy zmodyfikować definicję transformacji poprzez jawne wskazanie przestrzeni nazw z jakiej pochodzą przetwarzane węzły dokumentu Xml. Po pierwsze należy podać definicję nowej przestrzeni nazw poprzez dodanie do węzla xsl:stylesheet atybutu xmlns:test="a.b.c". Oczywiście można podać inną skróconą nazwę przestrzeni nazw niż test. Następnie należy dodać przedrostek test: przed każdym odwołaniem do węzła z dokumentu np.:
...
<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:test="a.b.c">
...
...
<xsl:template match="test:B" >
   <LI>
      <xsl:value-of select="current()"/>
   </LI>
</xsl:template>
...

01/12/2008

LoadControl

Home

Czy poniższy kod zawierający wywołanie metody LoadControl wydaje się wam poprawny? Jeśli tak to zapraszam do dalszej lektury.

protected void Page_Load(object sender, EventArgs e)
{
    ...
    Control control = LoadControl("~/MySimpleUserControl.ascx");
    PlaceHolder1.Controls.Add(control);

    ((MySimpleUserControl)control).BackColor = Color.Yellow;
    ...
}
Niestety ale kod ten będzie działał poprawnie tylko do momentu kiedy dla kontrolki zostanie włączony mechanizm Output Cache, na przykład w następujący sposób:

<%@ OutputCache Duration="60" VaryByParam="None" %>
W takim przypadku, przy następnym ładowaniu strony, na której umieszczono kontrolkę, pojawi się wyjątek InvalidCastException z komunikatem: "Unable to cast object of type ‘System.Web.UI.PartialCachingControl’ to type ‘MySimpleUserControl’.". Dzieje się tak ponieważ metoda LoadControl, w przypadku kiedy włączone jest cache'owanie dla kontrolki, zwraca obiekt klasy PartialCachingControl, a nie klasy MySimpleUserControl jak mogłoby się wydawać. W takie sytuacji do kontrolki możemy się dostać przez właściwość PartialCachingControl.CachedControl. Poprawny kod powinien, więc wyglądać tak:

protected void Page_Load(object sender, EventArgs e)
{
    ...
    Control control = LoadControl("~/MySimpleUserControl.ascx");
    PlaceHolder1.Controls.Add(control);

    MySimpleUserControl c = control as MySimpleUserControl;
    if(c == null)
    {
        PartialCachingControl pc = control as PartialCachingControl;
        c = pc.CachedControl as MySimpleUserControl;
    }

    if(c != null)
       c.BackColor = Color.Yellow;
    ...
}
Dodatkowe sprawdzenie if(c != null) jest potrzebne ponieważ właściwość PartialCachingControl.CachedControl zwróci null jeśli kontrolka znajduje się już w cache'u. Innymi słowy wartość różna od null zostanie zwrócona tylko wtedy kiedy kontrolka nie została jeszcze umieszczona w cache albo zawartość cache przestała być ważna.

Należy również pamiętać aby odwołanie do PartialCachingControl.CachedControl było zawsze poprzedzone umieszczeniem kontrolki na stronie np.: PlaceHolder1.Controls.Add(control);. W przeciwnym wypadku właściwość PartialCachingControl.CachedControl zawsze zwróci null.

W przypadku kiedy korzystamy z cache'owania i mamy na stronie statycznie osadzone kontrolki również należy zachować ostrożność. Jeśli kontrolka zostanie pobrana z cache to nie zostanie zainicjowana i nie możemy w związku z tym odwołać się do niej w kodzie naszej strony. Oczywiście jest to jak najbardziej prawidołe zachowanie - na tym polega idea mechanizmu Output Cache.

28/11/2008

Modelowanie procesów biznesowych

Home

Ostatnio zainteresowałem się modelowaniem procesów biznesowych. Spodziewałem się istnienie kilku standardów ale rzeczywistość naprawdę mnie zaskoczyła. Świat BPM okazał się naprawdę bogaty. Sądzę, że porównanie do dżungli będzie nawet bardziej odpowiednie. Mamy więc: BPDM, BPEL4WS, BPML, BPMN, UML Activity Diagram, WSFL, XLANG, XDPL i sporo więcej. W poście tym chciałbym troszeczkę usystematyzować ten bałagan i wyjaśnić jak jak to rozumiem.

Wstęp

Zacznijmy od tego, że w procesie BPM należy wyróżnić dwa zasadnicze poziomy:
  • Poziom modelowania – poziom, w którym działają analitycy, konsultanci itd.
  • Poziom wykonania – poziom, w którym pracują inżynierzy oprogramowania itd.
Na styku tych dwóch (ale moim zdaniem bardziej na poziomie modelowania) poziomów znajduje się analityk procesów biznesowych.

Poziom modelowania

Użytkownicy pracujący na tym poziomie posługują się wysoko poziomowymi narzędziami i notacjami do zamodelowania procesów biznesowych. Odpowiednich narzędzi jest bardzo dużo ale niewątpliwie najpopularniejszą i najbardziej rozpowszechnioną notacją jest BPMN – Business Process Modeling Notation, która została zaproponowana przez BPMI – Business Process Modeling Initiative (od 2005 połączone z OMG).

BPMN to nie tylko notacja. Definiuje nie tylko elementy diagramu ale również ich semantykę. Specyfikacja BPMN nie określa natomiast sposobu w jaki stworzony diagram ma zostać zapisany (zserializowany). Do tego celu bardzo często używa się innej specyfikacji zaproponowanej przez IBM i Microsoft: XDPL – XML Process Definition Language.

W tym miejscu należy wspomnieć o najnowszym członku rodziny BPM czyli o specyfikacji zaproponowanej przez OMG: BPDM – Business Process Definition Metamodel. Finalna wersja tej specyfikacji jest bardzo świeża - pochodzi z czerwca tego roku. BPDM stanowi w pewnym sensie połączenie wymienionych wcześniej standardów: XDPL oraz BPMN ale nie tylko. Przyszłość tego rozwiązania nie jest jeszcze określona i należy poczekać czy zdobędzie popularność. Z pewnością pokłada się w niej duże nadzieje.

Istnieje również kilka innych rozwiązań ale odnoszę wrażenie, że są mało popularne dlatego nie przytacza, ich opisu w tym poście.

Poziom wykonania

Po zdefiniowaniu procesu chcielibyśmy zapewne zasilić nim jakiś silnik, ktory go wykona. W tym celu należałoby przetłumaczyć diagram do formatu/opisu zrozumiałego przez określoną technologię. W obecnej chwili najpopularniejsze wydają się dwie specyfikacje (oparte o XML): BPEL – Business Process Execution Language oraz BPML4WS – Business Process Modeling Language For Web Services. Pierwsza została zaproponowana przez BPMI, a druga przez IBM, BEA Systems oraz Microsoft. Należy zauważyć, że BPML4WS to następca BPML, który nie jest już wspierany. BPEL został oparty o WSFL oraz XLANG.


Rysunek pochodzi z: The BPMN-XPDL-BPEL value chain

Do poczytania

Zarządzanie procesami biznesowymi – standardy notacji i nie tylko

http://modelowanie.wordpress.com/category/bpmnbpml/

Business Process Modeling and Standarization

XPDL,BEPL,JPDL,BPMNS,BPDM et al.. Standards and More Standards

The BPMN-XPDL-BPEL value chain

BPMN, BPEL, BPML and XPDL, an attempt to make some order in the business modeling jungle

A Comparison of XPDL, BPML and BPEL4WS Cape Visions

Business Process Model and Notation (BPMN) 2.0 Request For Proposal