Running Blazor Web App

My web site is running on Linux/Apache server. So, I wanted Blazor Web App to run on that server too.

Developing Blazor app was quite easy and straight forward process but writing the right .htaccess file was not so easy. I searched the internet and found sample on Microsoft web pages (https://docs.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/?view=aspnetcore-6.0&tabs=visual-studio), but provided .htaccess file sample was not enough.

I think that running Blazor on Apache is interesting for others too, so here is .htaccess file I am using in production (just update string ‘sub-directory’ (2x) with correct directory path of your app on Apache file system).

Link to GitHub gist: Apache .htaccess file for running Blazor Web App (github.com)

<IfModule mod_headers.c>
    # Serve brotli compressed files if they exist and the client accepts brotli.
    RewriteCond "%{HTTP:Accept-encoding}" "br"
    RewriteCond "%{REQUEST_FILENAME}\.br" "-s"
    RewriteRule "^(.*)\.(js|json|css|dll|dat|blat|wasm)$" "$1\.$2\.br" [QSA]

    # Serve gzip compressed files if they exist and the client accepts gzip.
    RewriteCond "%{HTTP:Accept-encoding}" "gz"
    RewriteCond "%{REQUEST_FILENAME}\.gz" "-s"
    RewriteRule "^(.*)\.(js|json|css|dll|dat|blat|wasm)$" "$1\.$2\.gz" [QSA]
    
    # Serve correct content types, and prevent double compression.
    RewriteRule "\.css\.br$" "-" [T=text/css,E=no-brotli:1]
    RewriteRule "\.js\.br$"  "-" [T=text/javascript,E=no-brotli:1]
    RewriteRule "\.json\.br$"  "-" [T=application/json,E=no-brotli:1]
    RewriteRule "\.dll\.br$"  "-" [T=T=application/octet-stream,E=no-brotli:1]  
    RewriteRule "\.dat\.br$"  "-" [T=application/octet-stream,E=no-brotli:1]  
    RewriteRule "\.blat\.br$"  "-" [T=application/octet-stream,E=no-brotli:1]  
    RewriteRule "\.wasm\.br$"  "-" [T=application/wasm,E=no-brotli:1]  
    
    # Serve correct content types, and prevent double compression.
    RewriteRule "\.css\.gz$" "-" [T=text/css,E=no-gzip:1]
    RewriteRule "\.js\.gz$"  "-" [T=text/javascript,E=no-gzip:1]
    RewriteRule "\.json\.gz$"  "-" [T=application/json,E=no-gzip:1]
    RewriteRule "\.dll\.gz$"  "-" [T=T=application/octet-stream,E=no-gzip:1]  
    RewriteRule "\.dat\.gz$"  "-" [T=application/octet-stream,E=no-gzip:1]  
    RewriteRule "\.blat\.gz$"  "-" [T=application/octet-stream,E=no-gzip:1]  
    RewriteRule "\.wasm\.gz$"  "-" [T=application/wasm,E=no-gzip:1]  
    
    <FilesMatch "(\.js\.br|\.css\.br|\.json\.br|\.dll\.br|\.dat\.br|\.blat\.br|\.wasm\.br)$">
      # Serve correct encoding type.
      Header set Content-Encoding br
      # Force proxies to cache brotli & non-brotli
      Header append Vary Accept-Encoding
    </FilesMatch>
    
    <FilesMatch "(\.js\.gz|\.css\.gz|\.json\.gz|\.dll\.gz|\.dat\.gz|\.blat\.gz|\.wasm\.gz)$">
      # Serve correct encoding type.
      Header set Content-Encoding gzip
      # Force proxies to cache gzipped & non-gzipped
      Header append Vary Accept-Encoding
    </FilesMatch>
</IfModule>

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /sub-directory/
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /sub-directory/index.html [L]
</IfModule>

Parse XML documents in JavaScript!

The problem on webpage was simple. Read XML file and process it. 1,2,3 and script was written, except it wasn’t working in IE. Ok, IE is an odd creature, but still. It wasn’t working even in IE 11!

The problem was .innerHTML property which (at first, I thought) was returning undefined, but then I found out that the method was undefined, it was not there!

JavaScript DOM object in IE didn’t have .innerHTML property! WTF

After few lost hours I found the bug!

If you parse XML string with this code:

return (new window.DOMParser().parseFromString(xmlStr, <strong>'text/xml'</strong>))

you get totally different object than this one:
return (new window.DOMParser().parseFromString(xmlStr, <strong>'text/html'</strong>))

If you use ‘text/html’ instead of ‘text/xml’ in IE everything works as expected. All objects (all nodes, elements …) will have all the expected properties!

As I said; few lost hours 🙁

Davčne blagajne

V januarju 2016 bo v Sloveniji obvezna uporaba davčnih blagajn za vse gotovinska plačila. Na spletni strani FURS-a si lahko preberete vse tehnične specifikacije potrebne za davčno potrjevanje računov.

Kako poteka davčno potrjevanje računov

V osnovi je to zelo preprost in uporaben sistem. Pred izpisom (izdajo računa) se morate namreč povezati na strežnik davčne uprave in nanj prenesti podatke o računu, FURS pa vam vrne edinstveno številko EOR (Edinstvena Oznaka Računa), ki jo morate izpisati na računu in s katero dokazujete, da ste račun tudi zares poslali na FURS.

Ozadje

Seveda pa se podrobnosti vedno skrivajo v ozadju in povezava na FURS niti ni tako trivialno preprosta oz. povezava je preprosta, saj gre za standarden internetni protokol, vendar pa je tja potrebno poslati digitalno podpisan račun in tukaj se stvari malce zapletejo.

Zastonj rešitev na dlani

Da bi se ne bilo potrebno vsakumur ukvarjati s:

  • podrobnostmi digitalnega podpisa,
  • podrobnostmi izračuna zaščitne številke (ZOI)
  • podrobnostmi izrisa QR kode

sem na GITHub-u odprl rešitev, ki je vsakomur na voljo povsem brezplačno. Za uporabo rešitve potrebujete le računalnik z operacijskim sistemom Windows. Ker je v SLO še kar nekaj blagajn, ki tečejo na operacijskem sistemu Windows XP, je podprt tudi slednji.

Minimalne zahteve za uporabo te povsem zastonj rešitve je:

  1. Win XP, SP 3, .NET 4.0 – ali seveda katerikoli novejši WIN sistem
  2. Uporaba .NET razvojnega okolja (C#, VB.NET ali pa tudi kakšnega bolj eksotičnega, a teh verjetno ni veliko 🙂 )

Izgled testnega programa
Izgled testnega programa

Kaj pa če ne uporabljate .NET razvojnega okolja

V tem primeru pa seveda ponujene knjižnice ne morete neposredno izkoristiti, a dokler vaš program teče v WIN okolju je problem rešen. Ponudim vam lahko namreč sledeč možnosti povezave:

  1. EXE program, ki ga pokličete iz vašega programa in slednji
    • Pregleda račun ali slednji vsebuje vse zahtevane elemente
    • Izračuna zaščitno kodo (ZOI)
    • Obda račun z zahtevano ovojnico
    • Ga digitalno podpiše in pošlje na FURS
    • Od FURS-a sprejme odgovor in ga posreduje v vaš program
    • Podroben opis EXE programa najdete tukaj.
  2. WIN service, ki nadzoruje dve poljubni mapi in čim vi odložite podatke o računu v prvo mapo, jih program vzame, obdela, pošlje na FURS (enako kot v primeru EXE programa) in rezultat izpiše v izhodno mapo
  3. V kolikor želite uporabiti knjižnico sami in elemente zvezati neposredno v vaš program, vam lahko ponudim ActiveX komponento, ki naredi vse našteto
  4. Če imate zares veliko blagajn pa lahko vse skupaj zavrtite na nekem strežniku in ponudim vam lahko ASP.NET spletne storitve ki izvedejo vse omenjeno.

V kolikor torej potrebujete rešitev pišite na info@matjazev.net in rešitev boste dobili na dlani 😉

XAML DataGrid using one DataTable as lookup

Problem:

I have a DataTable with lookup column into another table. Another table is a small table so all the records can fit in small combobox and the user wants to be able to select lookup record with combobox.

Solution:

XAML has DataGridComboBoxColumn, but it is difficult to bind, because DataGridComboBoxColumn can’’t bind to Windows binding source. It is obviously quite know problem, but I could’n’t find an easy solution.

Test tables:

MAIN_TABLE 
{ 
  ID, 
  SubTableID, 
  ... other fields ...
}

SUB_TABLE 
{ 
  ID, 
  Description 
}

Naive

Naive solution, that doesn’’t work

<DataGrid ItemsSource="{Binding mainTable}">
  <DataGrid.Columns>
    <DataGridTextColumn Header="ID" 
                        Binding="{Binding ID}" />
    <DataGridTextColumn Header="SubID" 
                        Binding="{Binding SubTableID }" />
    <DataGridComboBoxColumn Header="Desc" 
                            ItemsSource="{Binding subTable}}" <!-- can't bind! -->
                            SelectedValueBinding="{Binding SubTableID}"
                            SelectedValuePath="ID" 
                            DisplayMemberPath="Description" />
  </DataGrid.Columns>            
</DataGrid>

The solution doesn’’t work because – for some reason– DataGridComboBoxColumn can’’t bind subTable even if it is defined exactly as mainTable in datasource for the whole xaml window.

Solution

The solution is quite easy. Create a resource that binds to sub table and then use that resurce sa data source 🙂


<DataGrid ItemsSource="{Binding mainTable}">
  <DataGrid.Resources>
    <CollectionViewSource x:Key="cvsSubTable" 
                          Source="{Binding subTable }"/> <!-- can bind! -->
  </DataGrid.Resources>
  <DataGrid.Columns>
    <DataGridTextColumn Header="ID" 
                        Binding="{Binding ID}" />
    <DataGridTextColumn Header="SubID" 
                        Binding="{Binding SubTableID }" />
    <DataGridComboBoxColumn Header="Desc" 
                            ItemsSource="{Binding Source={StaticResource cvsSubTable }}"  <!-- now it is ok! --> 
                            SelectedValueBinding="{Binding SubTableID}"
                            SelectedValuePath="ID" 
                            DisplayMemberPath="Description" />
  </DataGrid.Columns>            
</DataGrid>         

Lost 4 hours on that! Grrrr..

Številčenje v SQL podatkovnih bazah IV

Naslednji način pridobivanja številke (prvi del, drugi del, tretji del) pa je poenotena tabela za avtomatično številčenje različnih (poljubnih) elementov. Spet velja, da je to smiselno za MSSql in SQLite podatkovni bazi, saj Oracle pač uporablja sekvence.

Definirajmo torej enotno tablo za številčenje. Tabela bo imela 3 polja. Prvo polje je pač primarni ključ. Za to rešitev ga ne potrebujemo, vendar pa sem osebno pristaš pravila, da mora imeti vsaka tabela primarni ključ. Drugo polje je nek opis števca saj je želja, da se za vsak različen števec neodvisno številči. Tretje polje pa je pač števec sam. tabela s podatki bi torej izgledala takole:

ID   OPIS       ŠTEVILO
1    Dobavnica      1
2    Predračun      1
3    Predračun      2
4    Račun          1
5    Predračun      3
6    Račun          2
7    Dobavnica      2
8    Dobavnica      3
9    Dobavnica      4
10   Predračun      4
11   Dobavnica      5
12   Račun          3
13   Dobavnica      6

Definicija tabele

MSSql:

CREATE TABLE SEKVENCA
( ID        INT   IDENTITY(1,1)  NOT NULL
, OPIS      VARCHAR(15) NOT NULL
, STEVILO   INT         NOT NULL
);

SQLite:
CREATE TABLE SEKVENCA
( ID        INTEGER     NOT NULL
, OPIS      VARCHAR(15) NOT NULL
, STEVILO   INTEGER     NOT NULL

, PRIMARY KEY(ID)
);

Pridobivanje nove številke:

MSSql:

BEGIN TRANSACTION;
INSERT INTO SEKVENCA (OPIS, STEVILO) VALUES('racun', (SELECT COALESCE(MAX(STEVILO) + 1, 1) FROM SEKVENCA WHERE OPIS = 'racun'));
COMMIT TRANSACTION;

SQLite:
BEGIN TRANSACTION;
INSERT INTO SEKVENCA (OPIS, STEVILO) VALUES('racun', (SELECT COALESCE(MAX(STEVILO) + 1, 1) FROM SEKVENCA WHERE OPIS = 'racun'));
COMMIT TRANSACTION;

OPOMBA: Uporaba transakcije je obvezna! Na pogled se zdi, da se izvaja INSERT stavek, ki je avtonamna akcija, toda znotraj INSERT stavka se izvaja še SELECT stavek in vmes se lahko vsebina podatkov spremeni!

Številčenje v SQL podatkovnih bazah III

Naslednji način pridobivanja številke (prvi del, drugi del) je lastna tabela za vsako številčenje. Izmed omenjenih SQL podatkovnih baz (Oracle, MSSql in Sqlite) je Oracle že od nekdaj uporabljal sekvence in avtomatičnega številčenja primarnih ključev ne pozna. Za MSSql in SQLite pa je to osnovni način avtomatičnega številčenja. Kot omenjeno že zadnjič je MSSql sekvence dobil šele v reinkernaciji iz leta 2012, SQLite pa jih še vedno ne pozna.

Za avtomatično številčenje na podlagi primarnega ključa je torej potrebno to določiti že v definiciji tabele:

MSSql:

CREATE TABLE SEQ_RACUNI
(
  SID INT IDENTITY(1,1)
);

SQLite
CREATE TABLE SEQ_RACUNI
(
  SID INTEGER NOT NULL

, PRIMARY KEY(ID)
);

V obeh primerih smo določili tabelo z enim samim poljem, ki se bo avtomatično povečevalo v kolikor mu številke ne določimo. Torej:
INSERT INTO SEQ_RACUNI DEFAULT VALUES

Na ta način torej v MSSql in SQLite podatkovnih bazah dobimo avtomatično številčenje.

POZOR: Seveda pa – glede na sekvence – obstaja velika razlika. Pri sekvencah vsak zahtevek po novi številki samo poveča trenutno vrednost sekvence; v primeru avtomatičnega številčenja primarnih ključev pa se številke zapisujejo v podatkovno bazo in tako imamo za prvih 1000 številk v tabeli 1000 zapisov. To se seveda lahko preprosto reši s periodičnim brisanjem podatkovne tabele:

DELETE FROM SEQ_RACUNI WHERE SID &lt; (SELECT MAX(SID) FROM SEQ_RACUNI)

Številčenje v SQL podatkovnih bazah II

Zadnjič sem vam omenil tri načine avtomatičnega številčenja v SQL podatkovnih bazah, danes pa vam bom prikazal prvega. Posamezne načine vam bom prikazal na primeru treh popularnih SQL baz: Oracle, MSSQL in Sqlite.

Sekvence (SEQUENCE)

Izmed omenjenih treh podatkovnih baz poznata sekvence Oracle in MSSQL (vendar MS samo od letnika 2012 dalje!). Postopek dela s sekvencami je skrajno preprost.

  1. Najprej definiramo novo sekvenco
  2. Ko potrebujemo naslednjo številko jo iz sekvence zahtevamo

To je očitno zelo dober način za pridobivanje avtomatičnih številk. Sekvenco določimo z najmanj petimi parametri (ime sekvence, minimalna vrednost, maksimalna vrednost, preskok in začetna vrednost):

CREATE SEQUENCE sequence_name
  MINVALUE value
  MAXVALUE value
  START WITH value
  INCREMENT BY value;

Primer:
CREATE SEQUENCE seq_racuni
  MINVALUE 1
  MAXVALUE 99999999
  START WITH 1
  INCREMENT BY 1;

Kot je vidno sekvenca ni omejena na zaporedno številčenje, temveč lahko številčimo tudi s korakom večjim od 1 (INCREMENT BY). Ravnotako ni nujno, da se sekvenca začne z 1 (START WITH).

OPOMBA: Seveda je z uporabo najpreprostejše srednješolske matematike tako ali tako preprosto napisati poljubno funkcijo številčenja tako da pač napišemo neko funkcijo y = F(x), kjer X pač raste od 1 do N, y pa je številka, ki nas zanima. Recimo, če želimo začeti številčiti z 8 in potem nadaljevati s korakom 15: y = 8 + 15 * (x – 1)!

Uporabiti takšno sekvenco pa je še bolj preprosto.

V Oracle jo preprosto zahtevamo s funkcijo .nextval:

SELECT seq_racuni.nextval FROM dual;

oziroma
INSERT INTO racuni
  (stevilka_racuna, znesek, datum...)
VALUES
  (seq_racuni.nextval, 1123.4, SYSDATE...);

V MSSQL pa s konstruktom NEXT VALUE FOR:
SELECT NEXT VALUE FOR seq_racuni;

oziroma
INSERT INTO racuni
  (stevilka_racuna, znesek, datum...)
VALUES
  (SELECT NEXT VALUE FOR seq_racuni, 1123.4, SYSDATE...);

Oracle Data Provider For .NET – What is Number?

Grrr… Oracle Data Provider for .NET just cost me time, (some) money and above all reputation.

My .NET application was using MS Oracle Data Provider which was OK. Many are not satisfied with it, but I had no particular problems… Until I hit BLOBs.

To be honest BLOBs are not often used in business application, so I didn’t have much knowledge on how to use it in c#. It is quite easy, but MS Oracle data provider is not fond of them.

So I was forced to use ORACLE Data provider for .NET… And – o my god – database is full of NUMBER fields so MS is using OracleType.Number, but Oracle for .NET does not know “numbers” so I was forced to change the source code from OracleType.Number to OracleDbType.Int32 or OracleDbType.Double (or something like that).

And there I made a typical programming error – typo – I one procedure I changed OracleType.Number to OracleDbType.Int32, but it was used as amount field (so double)… 🙁

And all “of the sudden” amounts were rounded to integers. Nobody noticed for 14 days… and then panic – everything is wrong – who is to blame – me – I admit (ashamed)…

BUT: Thanks Oracle, maybe guys from DB team can teach guys from .NET team what are “numbers” in DB terms…

Številčenje v SQL podatkovnih bazah

V razvoju prej ali slej naletimo na problem, ko moramo zapise številčiti. Vsakemu dokumentu pač moramo določiti edinstveno številko, ki pa mora biti ob tem še zaporedna.

Vse SQL podatkovne baze poznajo avtomatično številčenje primernega ključa – ko torej v tabelo dodamo nov zapis, slednji dobi naslednjo zaporedno številko. To imenujemo tehnično številčenje zapisov. Problem pa se pojavi, ko potrebujemo vsebinsko številko dokumenta.

Za lažje razumevanje problema, si predstavljajmo tipično podatkovno tabelo, v kateri imamo poslovne dokumente – predračune, račune, dobavnice… Vsi različni dokumenti so v isti tabeli, a vsak med njimi mora imeti lastno vsebinsko številko. Primer:

#  DOKUMENT     VSEB. ŠT.   OSTALI PODATKI

1  Predračun    PR-1/2013   ... itd ...
2  Predračun    PR-2/2013   ... itd ...
3  Račun        RA-1/2013   ... itd ...
4  Dobavnica    DO-1/2013   ... itd ...
5  Predračun    PR-3/2013   ... itd ...
6  Predračun    PR-4/2013   ... itd ...
7  Račun        RA-2/2013   ... itd ...
8  Dobavnica    DO-2/2013   ... itd ...
9  Dobavnica    DO-3/2013   ... itd ...

Kot je lepo vidno v tabeli ima vsak tip dokumenta lastno številčenje.

Kako določiti vsebinsko številko?

Opcij je seveda več a nekako jih lahko uredimo v tri sklope:

  1. Sekvence – če jih podatkovna baza podpira.
  2. Lastna tabela za vsak tip številčenja – za vsak tip dokumenta narediti lastno tabelo, ki določi naslednjo številko
  3. Ena tabela za vso številčenje – za vse številčenje uporabiti eno samo tabelo

Sekvence

Dobro

  • Rešitev namenjena temu konkretnemu problemu

Slabo

  • Ne poznajo jo vse podatkovne baze

Lastna tabela za vsako številčenje

Dobro

  • Deluje v vseh SQL bazah
  • Zelo podobna rešitev kot sekvence

Slabo

  • Veliko malih tabel
  • Vse tabele je potrebno ustvariti vnaprej ali pa v programu vedno preverjati ali tabela obstaja ali ne.

Za vso številčenje uporabiti eno samo tabelo

Dobro

  • Deluje v vseh SQL bazah
  • Preprosta rešitev
  • Ni veliko dodatnega dela

Slabo

  • Ni primerna za SQL baze z veliko hkratnimi uporabniki

V naslednjih prispevkih bom podrobneje predstavil vsako izmed možnosti…

Seznami opravil

Danes vam bom predstavil zanimivo in uporabno VBA proceduro, ki vam lahko v Excelu olajša delo s seznami opravil.

Ljudje si namreč večkrat izdelujemo sezname opravil in se jih potem bolj ali manj držimo :). A danes ne bom govoril o vztrajnosti, temveč o tem, kako nam lahko Excel pomaga hitro označiti katere naloge smo že opravili in katere ne.

Ideja je preprosto v tem, da si v Excelu naredimo nek seznam opravil (recimo v stolpcu B), potem pa želimo v stolpcu A kljukico, če smo neko opravilo že izvedli oz. prazno mesto, če ga še nismo izvedli.

Continue reading Seznami opravil