Asp .Net Textbox OnKeyDown

Valamiért sikerült kihagyni pár Event kezelését az ASP .Net kontrolokból. Lehet annyira biztosra akartak menni, hogy senki nem csinál “butaságot”, hogy inkább kihagyták az ilyen jellegű eventeket. Nincs onKeyDown, nincs probléma.
De ha mégis kell, akkor mi a teendő?
Első körben illik írni egy scriptet, ami elfedi a különböző böngészők által megvalósított event kezelés problémáját. A Példa projektben ez a WebApplication1\WebApplication1\js\EventAddon.js fájl.
Ezt használjuk majd ügyesen, hogy kliens oldali JavaScript eseményekre feliratkozzunk. Mivel a .Net az .Net ezért illik szépen (.Net-esen) használni a JavaScriptet, azt pedig az alábbi módon kell:

1; A Script managernek megmondjuk mi az a script amit használni akarunk:

<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference path="js/EventAddon.js" />
</Scripts>
</asp:ScriptManager>

2; Ha már betöltöttünk egy scriptet, használjuk is:

<script type="text/javascript">
Sys.Application.add_init(appInitHandler); //ha betöltésre került az oldal, akkor inicializáljuk a scriptet
function appInitHandler() {
var textBoxKD = $get("TextBox1"); //elkérjük a textbox kontrollt
XBrowserAddHandler(textBoxKD, "keyup", KeyDownHandler); //lekezeljük a keyup eventet
}

function KeyDownHandler(e) {
__doPostBack('TextBox1', 'TextChanged'); //ha keyup event van szólunk a .net-nek hogy textchanged (ez alap esetben csak enternél vagy fókuszvesztésnél történik meg)
}
</script>

3; örülünk

A teljes project (VS 2008 SP1 C#) megtalálható itt:
http://voji.hu/media/blogs/voji/development/csharp/OnKeyDown_WebApplication1.zip

SVCgen batch processing, and parameters

Az SVC technológia kapcsán (ami egyébként kivételesen ötletes) az az érzése lehet az embernek, mintha nem lett volna rá idő rendesen beintegrálni a Visual Studio 2008-ba, ugyanis nincs módunk a kliens stub-ok generálására studióból. Vagy legalábbis én még nem jöttem rá erre. De sebaj, van megoldás. Írni kell két bat filét.

svc.bat

@echo off
echo Starting servicestub generation 
cmd /V:ON /C svcgen.bat

svcgen.bat

@echo off
set serviceList=system/system.svc,other/other1.svc,common/common.svc,admin/admin.svc

set serviceHost=http://localhost:3467/services/
set outputDir=.\client\serviceproxy\servicestubs\
set outputConfig=.\..\..\..\services_app.config
set resourceFile=.\..\common\bin\Debug\common.dll
set svcTool="c:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\SvcUtil"

set wsdlPostFix=?WSDL
set commonParams=/noLogo /target:code /l:cs /ser:datacontractserializer /importxmltypes

 
set cmdLine=%commonParams% /r:%resourceFile% /config:%outputConfig% /d:%outputDir%

del %outputDir%%outputConfig%
del /Q %outputDir%\*.* 

set firstrun=true

for %%a in (%serviceList%) do (        
  echo Processing service: %%a       
  echo ------------------- 
  rem echo %svcTool% %cmdLine% %serviceHost%%%a%wsdlPostFix%
  
  if "!firstrun!" == "false" (  
    %svcTool% %cmdLine% /mergeConfig %serviceHost%%%a%wsdlPostFix%   
 )
    
  if "!firstrun!" == "true" (
     %svcTool% %cmdLine% %serviceHost%%%a%wsdlPostFix%     
     set firstrun=false
 )  
)

A szolgáltatásokat a serviceList listába kell felvenni, vesszővel elválasztva.
A /r: paraméter arra szolgál, hogy azon osztályok, amik szerepelnek a megadott dll-ben nem kerülnek legenerálásra a kliens oldalon.

Ha igazán széppé akarjuk tenni a megoldást, akkor kell írnunk egy alkalmazást, ami a végeredményül kapott services_app.config fájlt bele tudja illeszteni az app.config fájl megfelelő xpath helyére.

C# Singleton

Generics mint fogalom létezik a .net-ben. És ez jó. Gondoltam csinálok egy singleton ősosztályt mert az legalább olyan jó mint a generics.

   public abstract class Singleton<T> System.Object, new()
    {
        private static T _instance;

        public static T get()
        {
            if (_instance == null)
            {
                _instance=new T();
            }
            return _instance;
        }
    }

Öröm boldogság, gondoltam. De a fordító nem örült, és ezt mondta:

Error 1 Constraint cannot be special class ‘object’

Ejnye. Megnéztem a helpet.

Compiler Error CS0702
The following types may not be used as constraints: System.Array, System.Delegate, System.Enum, or System.ValueType.

Szerencsére, mint a Microsoft termékeknél általában, mindig van egy alternatív megoldás.

    public abstract class Singleton<T>
    {
        private static T _instance;

        public static T get()
        {
            if (_instance == null)
            {
                _instance = System.Activator.CreateInstance<T>();
            }
            return _instance;
        }
    }

Szolgáltatás és a Timer

Naivan azt gondolhatnánk, hogy ha egy Timer komponenst használunk a szolgáltatásunkban az működni fog. Pedig nem. A .Net rendelkezik pár Timer osztályal számunkra most kettő érdekes (az ismertetés csak felületes, akit érdekel nézze meg msdn-en ügyesen):
System.Threading.Timer: mint neve is mutatja külön szálat hoz létre, és az végzi az üzemezést
System.Windows.Forms.Timer: ezt használja a gui, azon keresztül történik az ütemezés
A feladat csak annyi, hogy amikor a szolgáltatásunk elindul, eldöntsük azt melyiket is kell használnunk. Célszerű erre egy burkoló osztályt létrehozni, ami a külső használók elöl elrejti, hogy milyen timer is működik a háttérben valójában.
Az én implementációm nagyon egyszerű, egy szempont volt: működjön. Letölthető itt.

Windows Service

Mai kis írásom a windows szolgáltatásokról fog szólni, mégpedig a .Net és a Windows Services kapcsolatáról. Mint tudjuk lehet .Netben szolgáltatást csinálni, nem nagy trükk.
Amit nem reklámoznak, hogy lehet olyan szolgáltatást is csinálni, ami ha szolgáltatás módban indul az alkalmazás akkor szolgáltatás módban indul el, ha pedig csak úgy elindítják akkor normális windows gui alkalmazásként. Ez hasznos lehet pl. ha fejlesztünk és normális teszt környezetet szeretnénk kialakítani, vagy logot, vagy bármi mást.
Ezt az alábbi módon tudjuk megvalósítani:

static void Main()
{
if (System.Environment.UserInteractive)
{
System.Windows.Forms.Application.Run(new Form1());
}
else
{
ServiceBase[] ServicesToRun = new ServiceBase[] { new Service1() };
ServiceBase.Run(ServicesToRun);
}

}

Ahol Service1 a szolgáltatás osztály, és Form1 a windows formunk.
Természetesen a szolgáltatás nem indul el magától ha a formot indítjuk el, de a szolgáltatás elindítása triviális:
Service1 service=new Service1();
service.OnStart(null);