ABOUT
IN4OUT Logo
IN4OUT it solutions ist ein Dienstleistungsunternehmen
im Bereich der Informationstechnologie.
 
In diesem Blog berichten IN4OUT-Mitarbeiter über Erlebnisse und Abenteuer rund um Informatik-Probleme und -Lösungen, Web-Design und -Entwicklung, Microsoft Produkte, Social Computing sowie alles andere, was die Gedanken bewegt.

  Feed abonnieren

HTML5/CSS3 als Flash-Killer

by Markus Frey 20. January 2012 13:01

Asche auf mein Haupt. Unterschätzt habe ich sie. HTML5, CSS3 und vor allem JavaScript. Als minderwertig betrachtet, nicht geeignet für elegante, performante Web-Projekte, mehr Hype als praxistauglich.

Nach einer intensiven Auseinandersetzung mit der Materie - ja, Blut, Schweiss und Tränen - haben wir nun aber unsere Entwicklungsumgebung und Strategie gerne geöffnet. Man(n) lernt nie aus!

Hauptbedenken gegenüber HTML5 und CSS3 war die noch nicht flächendenkende Unterstützung in den Weiten des Internets: was nützen die schönen, glänzenden neue Features, wenn diese nur bei den aktuellsten Browsern unterstützt werden und gegen 50% der Besucher aussen vor bleiben? Hier kommt die Open-Source JavaScript-Library modernizr ins Spiel: diese bildet fehlende Funktionen über JavaScript-Funktionen auch für ältere Browser nach. Und dies erstaunlich gut!

Zudem: durch die in Visual Studio gegebenen Möglichkeiten bezüglich ProtoTyping, Entwicklung, prozess-übergreifendes Debugging, Load Test bis hin zur Projekt-Verwaltung mit dem Team Foundation Server sind wir zugegebenermassen ein wenig verwöhnt und argwöhnisch gegenüber losgelösten Werkzeugen. Doch ein Blick über die Visual Studio-Brille hinaus schadet nichts: die IE Developer Tools, das Firebug AddIn, YSlow sind inzwischen eine unentbehrliche Ergänzung.

Als erstes kleines Proof-of-Concept haben wir die News aus unserem .NET basierenden CMS im Header-Bereich animiert: kein Flash, nur HTML, CSS Transitionen und durch modernizr auch auf älteren Browsern immer in Bewegung.

Bei unseren Web-Projekte, bei welchen bis anhin für hochwertige Animationen und interaktives UI-Design (nein, wir erstellen keine Bandbreiten-vernichtende, spastische Krämpfe erzeugende Werbe-Banner ; ) Flash zum Einsatz kam können wir nun auf HTML5 und CSS3 setzen - und erschliessen uns so nebenbei die gesamte mobile Apple / IOS Welt.

What about your favorite Silverlight? Well, it's not dead. Not at all! Komplexere web-basierende Anwendungen, welche in unserem Umfeld praktisch nur im Intra-/Extranet-Umfeld zum Einsatz kommen, können wir weiterhin mit Silverlight realisieren, da wir hier das vorhandene PlugIn voraussetzen können.

Die Zukunft hat gerade begonnen, wir sind bereit!



Optimize it, please!

by Markus Frey 2. September 2011 15:16

Wir sind Web-Entwickler. Natürlich kennen wir die Theorie, wir setzen elegant um, wir beherrschen die Tricks und schicken unsere Projekte durch harte Stresstests.

Trotzdem: die laufende Optimierung der umgesetzten Websites im aktiven Tagesgeschäft und bei engen Deadlines kann durch die laufend hinzukommenden Features schon mal vernachlässigt werden (ja, genau, insbesondere auch bei der eigenen Website ; )

Die dunkle Seite: dutzende von verlinkten Script- und CSS-Dateien, Spaghetti-Code, unnötig grosse Bilder und weitere Speicher- und Bandbreiten-fressender Ungeheuer.

Dieser interessante Beitrag, welcher Optimierungs-Methoden sowie nützliche Tools wie YSlow beschreibt gibt Gegensteuer. Prädikat: wertvoll.

Dafür starte ich ausnahmsweise sogar den Firefox...



RIA: Wird Silverlight durch HTML5 abgelöst?

by Markus Frey 7. November 2010 12:57

Ein unüberhörbares Rauschen ging in den letzten Wochen durch die einschlägigen Foren: Aufgrund eine Interviews mit Bob Muglia, Präsident Entwicklung bei Microsoft and der PDC 2010 haben etliche Blogger und Newsportale das baldige Ableben der Silverlight Technologie verkündet.

Da wir selbst Silverlight als strategisch wichtige Technologie für unsere Software-Projekte betrachten wurde die Thematik auch innerhalb unseres Teams heftig diskutiert. Silverlight, aktuell in der Version 4 verfügbar, bietet für die Software-Entwicklung in unserem Umfeld gewaltige Vorteile bezüglich Funktionalität und effizienter Entwicklung. Ähnlich gelagert wie Flash, aber bestens eingebetet in unsere bestehende Entwicklungsumgebung, können wir attraktive animierte Apps im Web UND im Windows-Umfeld erstellen. Das erforderliche client-seitige Silverlight-Plugin ist dabei ein überschauberer Nachteil gegenüber reinen Web 2.0 Anwendungen. Zudem: Mittlere bis komplexe Web-Anwendungen mit tausenden Zeilen JavaScript umzusetzen macht, zumindest mir persönlich, eher wenig Spass...

Die faktische Gleichstellung von Silverlight und HTML5, welche eine Ablösung suggeriert, ist schlicht nicht nachvollziehbar. Meine Einschätzung ist einfach: Mit Sicherheit wird sich HTML5 durchsetzen - und Silverlight wird dort eingesetzt werden, wo HTML5 an seine Grenzen stösst. Also nicht "an Stelle von" sondern "ergänzend".

Nun stellt Microsoft selbst klar, wie die Aussagen von Bob Muglia zu interpretieren sind: http://team.silverlight.net/announcement/pdc-and-silverlight/

Die Aussage im Kern:

  1. Silverlight is very important and strategic to Microsoft.
  2. We’re working hard on the next release of Silverlight, and it will continue to be cross-browser and cross-platform, and run on Windows and Mac.
  3. Silverlight is a core application development platform for Windows, and it’s the development platform for Windows Phone. 

Was bleibt? Ein kritisches Hinterfragen von Meldungen im Zeitalter des Copy/Paste-Journalismus ist erlaubt, auch bei vermeintlich seriösen Quellen... 



WCF und Multiple Host Header oder "This collection already contains an address with scheme http. There can be at most one address per scheme in this collection. "

by Nicole Strebel 28. December 2009 13:17

Liebe Silverlight - Gemeinde

Nach einer kleinen Ewigkeit melde ich mich bei euch mit einem Problem zurück, in der Hoffnung, Hilfe oder Lösungen zu bekommen.
Das Problem hat sich im Zusammenhang von Silverlight-Applikationen auf Webseiten mit "mutliplen Host Headern" gezeigt. Wird zum kommunzieren von Client- und Server-Seite ein WCF Service benutzt, bekommt man unweigerlich die Fehlermeldung:

Wie schon erwähnt, tritt das Problem nur bei "multiplen Host Headern" auf.  Vereinfacht gesagt, werden "multiple Host Header" benötigt, wenn man über verschiedene URL's auf die gleiche Webseite gelangen will. Auf dem unteren Bild sieht man zwei solche Host Header.

Mit mehreren Host Headern wird unser hübscher WCF Service ein bisschen verwirrt und weiss nicht mehr wo er sich denn jetzt befindet. Und weil er das nicht weiss, findet er sich sozusagen selber nicht.
Nach kurzem googlen, hat sich herausgestellt dass man im "Web.config" - File nur ganz einfach folgendes eingeben muss, damit's funktioniert:

<serviceHostingEnvironment>
      <
baseAddressPrefixFilters
>
         
<add prefix="http://*****.in4out.ch"
/>
    
</baseAddressPrefixFilters
>
</
serviceHostingEnvironment>

Jetzt funktioniert der WCF Service allerdings nur noch auf der URL http://*****.in4out.ch, dafür aber nicht mehr auf http://*****.in4out-ag.local.
Es gibt auch keine Möglichkeit zwei solcher "baseAddressPrefixFilters" zu setzen, denn dann weiss der Webservice wieder nicht wo er sich befindet.

Nach weiterem googlen stiess ich dabei auf folgendes: CreateServiceHost
Dabei lautet die Definition von Microsoft:
"Erstellt eine Instanz der Dienstklasse, die über die angegebenen Basisadressen verfügt."

Nach dem Durchstöbern zahlreicher Foren, bin ich auf das Untenstehende gekommen.

1. Man mache eine neue Klasse im App-Code-Ordner und nenne diese "CustomHostFactory"
2. Man kopiere folgenden Code rein:

    Imports
Microsoft.VisualBasic
   
Imports System.ServiceModel.Activation
   
Imports System.ServiceModel
   
Imports System.IO
   
   
Public Class CustomHostFactory
            
Inherits ServiceHostFactory
               
Protected Overloads Overrides Function CreateServiceHost(ByVal serviceType As Type, ByVal baseAddresses As Uri()) As ServiceHost
                    
Dim host As ServiceHost
                     host =
New ServiceHost(serviceType, baseAddresses(0))
                     
Return host
               
End Function
    End
Class

3. Man setze im "svc"- File das "Factory"- Property:

    <%@ ServiceHost Language="VB" Debug="false" Service="i4BambiService" CodeBehind="~/App_Code/i4Bambi/i4BambiService.vb" Factory="CustomHostFactory"%>

Nun weiter zur Erklärung...

Meistens wird die Funktion "CreateServiceHost" automatisch mit dem Aufrufen des WCF als Teil der Dienstaktivierung aufgerufen, sodass die Methode nicht manuell gesetzt werden muss.
Um aber steuern zu können, welchen Host Header der Webservice nun nehmen soll, benötige ich die Methode hier. Man werfe doch nun bitte einen Blick auf den Parameter "baseAddresses" in dieser Methode.

In diesen Parameter werden alle verschiedene Host Header geschrieben. In meinem Fall also: http://*****.in4out.ch und  http://*****.in4out-ag.local.
Mit dem Integer in der Klammer (hier also "0") wird angeben welcher Host Header aus dem Array denn gewählt werden soll.
Wenn man nun noch mals folgendes betrachtet:

ist es in diesem Fall nun der erste Host Header, nämlich: http://*****.in4out-ag.local

Ich kann nun zwar im Code-Behind steuern, welchen Host Header ich denn gerne haben möchte, allerdings kann ich hier keine Abfragen machen und so den Integer auch nicht dynamisch werden lassen. Wie es scheint, wird nur jedesmal nach dem Compilieren der Host Header neu gesetzt. Ich kann auch den Pfad zum Webservice nicht dynamisch machen.

So und jetzt kommt ihr zum Zug. Habt ihr vielleicht eine Idee für mich, oder hab ich einfach was grundlegendes falsch verstanden? Ich bitte um eure Mithilfe.
Noch ne kurze Zusammenfassung: Ich suche nach einem Weg, wie mein Webservice bei beliebig vielen Host Headern funktionieren kann, ohne dass ich manuell etwas ändern oder absolute Pfade vergeben muss.
Ich danke euch schon mal im Vorraus.



HOW TO:Silverlight 3 Applikation im Web

by Nicole Strebel 28. August 2009 16:58

Seit einiger Zeit ist Silverlight ja nun auf dem Markt. Da die IN4OUT gerne auf dem neusten Stand ist, habe wir eine Bilderverwaltung mit Silverlight 3 gemacht, welche an eine Microsoft SQL Datenbank gebunden ist. Um euch alle in die Geheimnisse von Silverlight 3 Entwicklung einzuweihen, schreib ich diesen HOW TO - Eintrag.

So, damit ihr auch etwas über den Ablauf und die Technik von Silverlight wisst, hier noch einen kurzen Abschnitt über die Architektur:

Wie man auf dem obigen Architekturschema sehen kann, befinden sich auf der Serverseite die Datenbank, ein ClassContainer und Webservice. Clientseitig befindet sich dann die eigentliche Silverlight-Applikation. Um das Ganze noch etwas genauer zu veranschaulichen, gebe ich ein Beispiel:>

Was passiert wenn aus der Datenbank Daten geladen werden, welche in einem Datagrid angezeigt werden.

  1. In der Datenbank wird eine ganz normale Stored Procedure geschrieben um die Daten aus der entsprechenden Tabelle zu lesen.
  2. Im Webservice wird der Zugriff auf die Stored Procedures gemacht. Normalerweise machen wir das über die DB-Klassen im App_Code-Ordner gemacht. 3.Da Silverlight keine 
    Datasets und  Datareader kennt, werden dann die Daten in den ClassContainer geschrieben. In diesem ClassContainer befinden sich nur Propertys.  
  3. Auf der Clientseite im Programmcode wird dann der Zugriff auf den Webservice gemacht und die gespeicherten Daten aus dem ClassContainer herausgelesen. Diese Daten können dann wie gewohnt an ein Datagrid, eine Listbox oder weitere Controls gebunden werden.
  4. Diese Daten können dann wie gewohnt an ein Datagrid, eine Listbox oder weitere Controls gebunden werden.

Weiter darf man nicht vergessen, die verschiedenen Packages von Silverlight zu installieren. Siehe dazu HOW TO: UPgrade von Silverlight 2 zu Silverlight3

Zuerst muss ein neues Projekt erstellt werden. Dafür wählt man in der Sprache Visual Basic ein Silverlight-Projekt. Wichtig ist dabei, dass das .NET Framework 3.5  ausgewählt ist. Wenn dann auf OK geklickt wird, erscheint ein weiterer Bildschirm. Visual Studio fragt nach ob die Silverlight-Applikation bereits in eine Webseite integriert werden soll. Wir lassen die Standardeinstellungen und klicken auf OK. So haben wir bereits genau dieselbe Umgebung wie wir es später im i4Portal benötigen. Nun ist das Projekt erstellt und die XAML-Seite Page.xaml geöffnet. Mit F5 kann die Applikation bereits gestartet werden.
Nicht vergessen denn Connectionstring im Web.config anzugeben. In der Datenbank schreiben wir eine Stored Procedure, welche uns alle Bilder aus der Datenbank liest. Diese Bilder wollen wir später in einem Datagrid anzeigen lassen.
Wenn wir mit ASP.NET arbeiten würden, würden wir in der Klasse ImageDB den Zugriff auf die Datenbank machen. Mit Silverlight ist dies alles ein bisschen speziell. Wir müssen einen Webservice machen. Dafür klicken wir mit Rechts auf das Web-Projekt und mit „Add – New item“ wählen wir den „Silverlight-enabled WCF Service“ aus und nennen in SLService. Der Webservice wird generiert und hat bereits eine vorgefertigte Funktion namens „DoWork()“.

Imports System.ServiceModel

Imports System.ServiceModel.Activation

<ServiceContract(Namespace:="")> _

<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)> _

Public Class SLService

    <OperationContract()> _

    Public Sub DoWork()

        ' Add your operation implementation here

    End Sub

    ' Add more operations here and mark them with <OperationContract()>

End Class

Wie bereits in Kapitel 3 erwähnt, kennt Silverlight keine Datareader oder Datasets, deshalb müssen die Daten welche mit dem Webservice ausgelesen werden, in  Propertys zwischen gespeichert werden. Man erstellt also im Web eine normale VB-Klasse und macht aus den einzelnen Spalten die man mit der Stored Procedure ausgelesen hat Propertys. Jetzt wagen wir uns an den Webservice. Auf einer Seite zuvor kann man das Grundgerüst erkennen. Statt der Funktion „DoWork()“ können wir dort einfach unsere Funktion benutzen.

<OperationContract()> _

Public Function GetImagesByCategory(ByVal CategoryID As Integer) As List(Of Category)

' Create Instance of Connection and Command Object

Dim myConnection As New SqlConnection(ConfigurationManager.AppSettings("connectionString"))

myCommand.Parameters.Add(parameterModuleID)

myConnection.Open()

Dim result As SqlDataReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection)

If result IsNot Nothing Then

Do While result.Read()

Dim cust = New Category With {.ImageID = result.GetInt32(0), .ImageFriendlyName = result.GetString(1), .ImageCreatedDate = result.GetDateTime(11), .ImageFormat = result.GetString(8), .ImageWidth = result.GetInt32(5), .ImageHeight = result.GetInt32(6), .ImageSize = result.GetInt32(9)}

custList.Add(cust)

Loop

End If

Return custList.ToList()

End Function

Dabei wird das <OperationContract()> immer benötigt wenn eine Funktion dann clientseitig erreichbar sein Interessant ist auch der eingekreiste Teil der Funktion. Dort kann man nämlich sehen wie die Ergebnisse aus dem Resultset in die einzelnen Propertys der Klasse geschrieben werden. ">Da nun also der serverseitige Teil abgeschlossen ist, machen wir uns an die Clientseite. Damit wir unsere Daten überhaupt anzeigen können, müssen wir den Webservice zuerst einbinden. Als wir den Webservice erstellt haben, wurde das Web.Config-File automatisch angepasst. Nehmen wir an, dass unser Webservice „SLService.svc“ heisst, sieht es in unserem Web.Config-File folgendermassen aus.


 
<system.serviceModel>

  <behaviors>

   <serviceBehaviors>

    <behavior name="Silverlight.Web.SLServiceBehavior">

     <serviceMetadata httpGetEnabled="true" />

     <serviceDebug includeExceptionDetailInFaults="false" />

    </behavior>

   </serviceBehaviors>

  </behaviors>

  <bindings>

   <customBinding>

    <binding name="customBinding0">

     <binaryMessageEncoding />

     <httpTransport />

    </binding>

   </customBinding>

  </bindings>

  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

  <services>

   <service behaviorConfiguration="Silverlight.Web.SLServiceBehavior"

    name="Silverlight.Web.SLService">

    <endpoint address="" binding="customBinding" bindingConfiguration="customBinding0"

     contract="Silverlight.Web.SLService" />

    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

   </service>

  </services>

 </system.serviceModel>

Dabei müssen die eingekreisten Teile des neuen Web.Config-Teil’s geändert werden.


<
system.serviceModel>

<bindings>

<basicHttpBinding>

binding name="ServicesBinding" maxReceivedMessageSize="200000000" maxBufferSize="200000000">

     <readerQuotas maxArrayLength="200000000"  maxStringContentLength="200000000"/>

</binding>

</basicHttpBinding>

</bindings>

  <behaviors>

   <serviceBehaviors>

    <behavior name="Silverlight.Web.SLServiceBehavior">

     <serviceMetadata httpGetEnabled="true" />

     <serviceDebug includeExceptionDetailInFaults="false" />

    </behavior>

   </serviceBehaviors>

  </behaviors>

  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

  <services>

   <service behaviorConfiguration="Silverlight.Web.SLServiceBehavior"

    name="Silverlight.Web.SLService">

    <endpoint address="" binding="basicHttpBinding" bindingConfiguration="ServicesBinding"

     contract="Silverlight.Web.SLService" />

    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

   </service>

  </services>

 </system.serviceModel>

</configuration>

Nun können wir testen ob der Webservice funktioniert. Wir rufen den Webservice direkt im Browser auf: Wenn der Webservice wie auf dem linken Screen aussieht, kann er der Silverlight-Applikation problemlos hinzugefügt werden. Der rechte Screen meldet uns einen Fehler bezüglich des Webservices. Auf Fehlersuche geht man sowieso nur über den Browser. Probiert man einen fehlerhaften Webservice einer Silverlight-Applikation hinzuzufügen, kommt immer der Not-Found 404 – Fehler, welcher nicht sehr aussagekräftig ist.
Um den Webservice hinzuzufügen klicken wir mit Rechts auf „References“ und dann auf „Add Service Reference“. Nun können wir die URL des Services direkt angeben oder einfach nach allen Services suchen mit dem Klick auf „Discover“. Jetzt sehen wir dort genau unsere Methode welche auf die Stored Procedures in der Datenbank zugreift.
Unsere Webservice-Referenz nennen wir der einfachheithalber mal „Reference“.

Nachdem wir nun den Webservice hinzugefügt haben, machen wir uns an die XAML-Seite. Dort fügen wir auf der GUI-Seite ein normales Datagrid ein.


<
UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"    

    x:Class="Silverlight.MainPage"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">

       <Grid x:Name="LayoutRoot">

       <data:DataGrid x:Name="dgImages" Width="500" Height="500"></data:DataGrid>

        </Grid>

</UserControl>                     

Das x:Name ist sozusagen die ID von Objekten in ASP.NET. Danach öffnen wir die Code-Behind-Seite und geben zum Binden der Daten an das Datagrid folgenden Code an. (Der grüne Text bezeichnet dabei Kommentare.)


Partial
Public Class MainPage

Inherits UserControl

Public Sub New()

InitializeComponent()

'*** Hier wird nochmals angegeben, wie der Pfad zum Webservice heisst.

Dim uri As New Uri(Application.Current.Host.Source, "/SLService.svc")

Dim client As New Reference.SLServiceClient("BasicHttpBinding_SLService", uri.AbsoluteUri)

'*** Dieser Handler wird augerufen wenn das Abrufen der Dates

'*** aus der Datenbank über die Klasse,

'*** über den Webservice fertig ist und die asynchrone Methonde(siehe unten)

'*** ausgeführt wurde

AddHandler client.GetImagesByCategoryCompleted, AddressOf client_GetImagesByCategory

'*** Asynchrone Methonde. Die zwei in der Klammer steht dabei für die

'*** benötigten Parameter.

client.GetImagesByCategoryAsync(2)

End Sub

Private Sub client_GetImagesByCategory(ByVal sender As Object, ByVal e As Reference.GetImagesByCategoryCompletedEventArgs)

'*** Wenn alle Daten geladen sind, werden die Resulate an

'*** das Datagrid gebunden.

dgImages.ItemsSource = e.Result

End Sub

End Class              

Wenn  ich die Applikation nun starte, habe ich bereits das gefüllte Datagrid! Juchee!