maandag, juli 30, 2007

Aan de slag met NHibernate in 5 stappen

Wil je aan de slag met Object Relational Mapping?
Ik heb gekozen voor NHibernate, de .NET versie van het populaire Hibernate (J2EE).
Dankzij een paar websites had ik vrij snel een draaiende NHibernate implementatie. Ik volgde de volgende stappen:

  1. Download de NHibernate distribute (ik gebruikte versie 1.2.0.GA);
  2. Download het basic example uit het project NHibernate Best Practices with ASP.NET, 1.2nd Ed. gehost op CodeProject;
  3. Download de Northwind example database bij Microsoft;
  4. Maak een App_Data folder in het example project aan en kopieer de mdf en ldf naar deze map;
  5. Pas de connection-string aan in web.config als volgt, vrij overgenomen uit het project Eucalypto - ASP.NET CMS library using NHibernate gehost op CodeProject:

<property name="connection.connection_string">data source=.\SQLEXPRESS;Integrated security=SSPI;AttachDBFilename=|datadirectory|northwnd.mdf;User instance=true</property>

Draaien maar!

vrijdag, juli 20, 2007

RunBot leert zelf nieuwe loopjes

Vandaag verschenen op nrc.nl:
De tweebenige robot ‘RunBot’, verbonden aan de universiteit van Göttingen, leert zelf zijn manier van lopen aan te passen aan het terrein waarop hij loopt. Dat is knap voor robots.
Lees meer

Kijk zelf naar het filmpje:

woensdag, juli 18, 2007

Mobiele telefoon als 'universeel' woordenboek

Verschenen op Emerce.nl, dinsdag 17 juli:
Nederlanders die de Olympische Spelen bezoeken, kunnen zich volgend jaar moeiteloos in het Chinees verstaanbaar maken via hun mobiel telefoon. Het Nederlandse bedrijf Xs2TheWorld publiceerde reeds een handzame Chinees 'sprekende reisgids' en lanceerde vorige week een aantal Europese versies.
Lees meer

Ben heel benieuwd waar deze vorm van toepassingen zich naartoe gaat ontwikkelen. Briljant dat je je gewoon in de moerstaal verstaanbaar kan maken. Zoals in één van de commentaren bij het artikel is te lezen: Probleem blijft het interpreteren van het antwoord. Je zou de Chinees in kwestie eenzelfde toepassing voor hun taalgebied naar het Engels (liefst Nederlands natuurlijk ;-)) moeten voorleggen.

Ik maak zelf veelvuldig gebruik van bijv. Babelfish van Altavista voor het vertalen van teksten van taal x naar taal y. Zo zijn er verder websites die middels spraaksynthese teksten kunnen vertalen naar spraak. In principe hebben we dus alle gereedschappen al in handen om iets beter dan alleen met handen en voeten te kunnen communiceren!

zaterdag, juli 14, 2007

.NET User Controls en Internet Explorer: COM visibility

Het heeft me uren van mijn leven gekost, ik snapte maar niet waarom ik mijn eigen user control niet met JScript kon laten communiceren.

Blijkt dat Visual Studio 2005 standaard de COM visibility van assemblies op false heeft staan in AssemblyInfo.cs:

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]


Zet deze instelling dus snel op true!

Code Access Security zonder signed assemblies

Blijkt dat je ook gewoon codegroups kan toevoegen die van toepassing zijn op url's. Er is dus geen sprake van een verplichting dat online assemblies moeten zijn ondertekend. Voer bijvoorbeeld het volgende commando uit:

caspol -ag All_Code -url http://localhost/controls/upload.dll FullTrust -n UploadCodegroup -d "Toegevoegd middels caspol"

Hiermee geef je te kennen dat de bewuste assembly lid moet worden van de FullTrust permissionset.

.NET User Control en JScript in Internet Explorer

Ben weer verder gegaan met het client-side invoegen van een usercontrol in IE.
Als uitgangspunt ben ik de code aan het bestuderen afkomstig uit MSDN Magazine van januari 2002, artikel DHTML and .NET: Host Secure, Lightweight Client-Side Controls in Microsoft Internet Explorer van de hand van Jay Allen.

Jay heeft een stuk html opgesteld met daarin een aantal JScript eventhandlers:

<script event="BeginUpload" for="upload1">
window.status = "uploading files...please wait";
</script>

<script event="UploadComplete" for="upload1">
window.alert("Upload complete");
</script>

Er komt nogal wat bij kijken om deze eventhandlers te koppelen aan code in je usercontrol. Een hoop COM interface gedoe.

De events zijn in c# netjes gedefinieerd:
public event UploadCompleteHandler UploadComplete;
public event BeginUploadHandler BeginUpload;

De signatuur van de usercontrol ziet er al wat minder transparant uit:

[ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(IMultiUploadCtrlCOMEvents))]
public class MultiUploadCtrl : System.Windows.Forms.UserControl, IMultiUploadCtrlCOMIncoming

De interface IMultiUploadCtrlCOMIncoming is in de code als volgt gedefinieerd:

public interface IMultiUploadCtrlCOMIncoming
{
void UploadFiles();
bool FilesPending {get;}
int MaxSessionUpload {get; set; }
int BytesUploaded {get;}
string FileUploadURL {get; set; }
}

Op deze manier kan JScript middels deze properties en methods communiceren met onze usercontrol.

De interface IMultiUploadCtrlCOMEvents is in de code als volgt gedefinieerd:

[Guid("A59B958D-B363-454b-88AA-BE8626A131FB")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMultiUploadCtrlCOMEvents
{
[DispId(0x60020000)]
void UploadComplete();
[DispId(0x60020001)]
void BeginUpload();
}

Zoals Jay zelf schrijft in het commentaar bij deze definitie: "Disgusting, but it works."

Het COM event BeginUpload() wordt netjes aangeroepen in de volgende code:
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();

// Assert ability to call unmanaged code.
BeginUpload();
CodeAccessPermission.RevertAssert();

Het COM event UploadComplete() moet pas worden uitgevoerd als de upload-thread klaar is. Nu is het zo dat COM events alleen kunnen worden uitgevoerd door de thread waarin deze zijn gekoppeld.
De methode die Jay heeft uitgewerkt maakt gebruik van een Timer object om op een sneaky manier terug te komen in de main thread. In mijn configuratie werkt deze truc helaas niet: het Timer object triggert het elapsed-event pas als de usercontrol wordt afgebroken door bijvoorbeeld het afsluiten van het IE venster.

Ik probeer daarom middels Control.Invoke te springen naar de main thread:

this.Invoke(new TimerElapsedDelegate(timer1_Elapsed), new object[] { null, null });

(even voor het gemak een delegate TimerElapsedDelegate gedefinieerd)

Maar helaas, als ik hierdoorheen step met de debugger en ik voer deze Invoke uit, dan gebeurt er een paar secondes helemaal niets. En ineens verschijnt een SecurityException!
Erg onduidelijk waarom.

Maar goed, met mijn lompe boeren verstand probeer ik het volgende:

new SecurityPermission(SecurityPermissionFlag.AllFlags).Assert();
this.Invoke(new TimerElapsedDelegate(timer1_Elapsed), new object[] { null, null });
SecurityPermission.RevertAssert();

// geen zin om uit te zoeken welke flag precies nodig is voor een invoke!

En ja hoor, het werkt! Geweldig.

vrijdag, juli 13, 2007

Microsoft .NET 2.0 Code Access Security (3)

OK, zoals je in de twee voorgaande blogs kan nalezen: ik wilde in mijn ASP.NET website een client-side .NET user control toegang geven tot het lokale bestandssysteem. Voor het gemak wilde ik deze assembly dus Full Trust geven. Ik kon daar geen gebruikersvriendelijke manier voor vinden.

De manieren die ik heb op kunnen maken uit de geraadpleegde bronnen om een assembly Full Trust te geven:
  1. Via de .NET Framework 2.0 Configuration MMC snap-in (mscorcfg.msc);
  2. Via het uitvoeren van een specifieke caspol.exe opdrachtregel;
  3. Via het uitvoeren van een mooi voorbereid Windows Installer Package .MSI bestand;
  4. Via het direct toevoegen van je permission rule aan het configuratiebestand security.config.

Ik heb ze allevier uitgeprobeerd.

1. MMC snap-in ---

De MMC snap-in werkt mbv wizards. Dat is wel zo prettig. Twee wizards zijn hier relevant:

  1. Increase Assembly Trust;
  2. Create Deployment Package.

Ad 1. Geef hier rechtstreeks de url op van de assembly die je Full Trust wilt toekennen. Blijkt dat je assembly wel strongly signed moet zijn! Logisch ook, anders kan iedere willekeurige assembly op van die lokatie wordt gedownload per ongeluk Full Trust krijgen.

Ad 2. Middels de MMC snap-in is dit de enige manier om settings te exporteren en op een andere computer te importeren. Deze wizard genereert een MSI met daarin de volledige security.config. Niet echt heel handig want je wilt specifiek maar één instelling wijzigen.

Het lompe van de MMC snap-in is dat je niet echt inzicht krijgt in waar de wizard precies zijn instellingen heeft weggeschreven. Daaraan toegevoegd het feit dat je gewoon keer op keer opnieuw je assembly FullTrust kan geven. De MMC snap-in helpt je dus niet echt in het vergaren van inzicht.

2. Caspol ---

Ik ging kijken naar caspol.exe. Ik voerde caspol.exe -m -af uit. Caspol zei netjes "Success". Bij de tweede keer uitvoeren de melding: ERROR: This assembly is already fully trusted.

Blijkt echter dat IEHost zich weinig aantrekt van deze status. IEHost genereert nog steeds een exception. Klaarblijkelijk zag ik hier iets over het hoofd. Caspol is dus ook niet een tool die een beginner echt op weg helpt.

3. MSI ---

Ik heb nog even vluchtig gekeken of ik een eenvoudige MSI kon genereren met één instelling erin. Ik heb een aantal MSI unpackers geprobeerd, maar na een paar pogingen begon ik me te realiseren dat MSI eigenlijk een vrij obscuur "database" formaat is waar ik misschien maar niet te veel tijd in moest steken.

4. Security.config ---

En dan komen we eindelijk uit waar ik wezen wilde, inzicht! Security.config is zoals alle config-files binnen het .NET framework xml-gestructureerd.

Ik gok erop dat er op drie niveaus een security.config leeft:

  1. Enterprise;
  2. Machine;
  3. User.

Ik richt me nu even op het machine-niveau, maar ik neem aan dat het volgende inzicht ook van toepassing is op het user-niveau.

Security.config blijkt te bestaan uit vier blokken gekenmerkt door de volgende elementen:

  1. SecurityClasses; hierin staan .NET classes verantwoordelijk voor het interpreteren van verdere xml data in het bestand;
  2. NamedPermissionSets; een reeks PermissionSets waaronder de PermissionSet "FullTrust";
  3. geneste CodeGroup elementen, waaronder de door de MMC snap-in wizard gegenereerde codegroup "Wizard_0" met omschrijving "Codegroup generated by the .NET Configurationtool";
  4. FullTrustAssemblies; een hele lijst assemblies met fully trusted status.

Caspol blijkt de drie laatste blokken netjes te kunnen listen:

  1. Caspol -lp; list permissionsets;
  2. Caspol -ld; list codegroups met descriptions;
  3. Caspol -lf; list fully trusted assemblies.

Standaard opereert caspol op het niveau van de machine.

Ik keek naar de codegroup die door de snapin wizard was toegevoegd:

<codegroup class="UnionCodeGroup" description="Codegroup generated by the .NET Configuration tool" version="1" permissionsetname="FullTrust" attributes="LevelFinal" name="Wizard_0">

<imembershipcondition class="StrongNameMembershipCondition" version="1" name="Upload" publickeyblob="ABC..." assemblyversion="1.0.2749.38494">

</codegroup>

En jawel! De puzzelstukjes vielen in elkaar: Een assembly met naam Upload met publickey ABC... en versie 1.0.2749.38494 wordt door het systeem gezien als member van de permissionset FullTrust. En dat wilden we bereiken!

Maar goed, leuk al dat inzicht maar dat brengt me nog niets verder. Ik heb nog steeds geen gebruikersvriendelijke manier om de gewenste permissies te vragen.

Misschien naar .NET ClickOnce kijken? Ik gok erop dat dit niet werkt in combinatie met ASP.NET. ClickOnce richt zich op geïsoleerde Windows Forms applicaties die direct kunnen worden gestart door te klikken op een link à la Java Web Start van Sun.

Is het mogelijk om een MSI te bakken die maar één codegroup toevoegt aan security.config?

In de tussentijd plaats ik op mijn website maar een batchfile met daarin een caspol-opdracht...

Of toch met SilverLight aan de slag?

Microsoft .NET 2.0 Code Access Security (2)

Spannend wordt het bijvoorbeeld als de user control het lokale bestandssysteem moet kunnen raadplegen.

Nou heb ik een beetje gekeken naar het Code Access Security model, en het is verdraaid gedetailleerd. Je kunt in principe op assembly-niveau aangeven wat deze assembly mag.

Een paar mooie artikelen die mij op weg hebben geholpen:

Klaarblijkelijk is het realiseren van een client-side user control nog steeds actueel!

Stap 1 is om je user control überhaupt aan de praat te krijgen in de IEHost container. Dan is het erg makkelijk als je weet dat IEHost een debug log kan wegschrijven, zie dus KB313892.

Zodra de user control eenmaal wordt gerenderd in Internet Explorer en je krijgt een security permission exception, dan is het prettig als je weet welke permissie je control precies moet krijgen. De uitgebreide exception tekst helpt je hier helaas niet bij!

Hoe achterhaal je dan de precieze gewenste permissie dan wel? Na wat googlen kwam ik de volgende blog tegen: stackenbloggen - "getting root on the managed world"; de bijdrage van 12 april 2007: CAS Tools & Best Practices. Hij schrijft over een toolset die hij heeft gemaakt in de context van een project die je mag downloaden. Helaas werkt de download-link niet.

Ik zit dus nog steeds met mijn handen in het haar, wat wil mijn control nou precies?

Omwille van desinteresse en tijdgebrek heb ik besloten om mijn control Full Trust te geven. Sssst, niet doorvertellen...

Wat ook een teleurstelling is, de gebruiker krijgt niet zoals bij een ActiveX control een mooie dialoog waarmee hij de control de rechten kan toekennen!

In de volgende blog meer.

Microsoft .NET 2.0 Code Access Security

Ben de afgelopen dagen bezig met het doorgronden van het Code Access Security bouwwerk dat we van Microsoft cadeau hebben gekregen bij de intrede van .NET 2.0.

Wat wil ik namelijk bereiken? Ik wil mijn ASP.NET 2.0 applicatie verrijken met een client-side .NET 2.0 user control, zoals we vroeger gewend waren ActiveX componenten op onze websites te gebruiken.

Misschien word ik zo langzamerhand overigens alweer ingehaald door de tijd, de methode die ik nu probeer te begrijpen stamt al uit 2002. Inmiddels is Microsoft hard bezig met het nieuwe rich internet client platform Silverlight.

Maar goed, altijd al interesse gehad in Code Access Security, dus waarom neem ik mijn huidige doel niet gewoon als case-studie?

Het blijkt enorm eenvoudig om een user control op een dergelijke website te krijgen:
  1. Je bouwt een assembly met daarin een class die overerft van één van de classes die afstammen van de class System.Forms.Control.
  2. De assembly zet je op een ASP.NET 2.0 webserver.
  3. Je bouwt verder een html-file met daarin een object tag waarin je een referentie opneemt naar de assembly en class, op een specifieke .NET 2.0 manier.
  4. De html-file zet je vervolgens op dezelfde ASP.NET 2.0 webserver.
  5. Draaien maar!

Deze stappen worden beschreven op http://samples.gotdotnet.com/ quickstart/winforms/doc/WinFormsIeSourcing.aspx

Het wordt echter lastiger als je je client-side .NET 2.0 user control méér wilt laten doen dan standaard is vastgelegd in de Code Access Security Policies.

Volgende blog meer.