OLE DB Zugriff: C# auf MDB (Microsoft Access Datenbank) mit JET Treiber

Selektionsanweisung mit Parametern

public ArrayList getWeekPlan(string kapno, string woche)
{
   ArrayList weekPlan = new ArrayList();

   OleDbConnection conn = new OleDbConnection(
   "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\\\\pfad1\\db.mdb");

   try
   {

      conn.Open();
      OleDbCommand comm = new OleDbCommand();
      comm.Connection = conn;
      comm.CommandText = "SELECT [Datum],[KapazitätNo] "+
      "FROM [qry_TagesAnsichtMengen] WHERE [KapazitätNo]=@kapno "+
      "AND [DINKW]=@woche";

      comm.Parameters.AddWithValue("kapno", kapno);
      comm.Parameters.AddWithValue("woche", woche);
      
      OleDbDataReader reader = comm.ExecuteReader();
      
       while (reader.Read())
       {
          WeekPlanVO vo = new WeekPlanVO();
          vo.datum = reader.GetValue(0).ToString();
          vo.menge = reader.GetValue(1).ToString();
          weekPlan.Add(vo);
        }
   }
   catch (Exception e)
   {
     WeekPlanVO vo = new WeekPlanVO();
     vo.datum = e.Message;
     vo.menge = e.Message;
     weekPlan.Add(vo);
     return weekPlan;
   }
   finally
   {
      conn.Close();
   }
  return weekPlan;
}

Manipulationsanweisung ohne Parameter

public string updateDetailDate(DateTime neuesDatum, DateTime altesDatum, 
string neueKW, string alteKW, string kapazitaet, string material, string beleg)
{
  OleDbConnection conn = new OleDbConnection(
  "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\\\\pfad1\\db.mdb");

  
  try
  {
     conn.Open();
     OleDbCommand comm = new OleDbCommand();
     comm.Connection = conn;
     comm.CommandText = "UPDATE qry_Details_Akt SET [changed]=Now(), DinkW=" + neueKW + 
      ", WEWA_C='" + DateWrapper.GetServerDate(neuesDatum) + "', WEWA_C_OLD='" +
     DateWrapper.GetServerDate(altesDatum) + "' WHERE Beleg='" + beleg + 
     "'AND DinkW=" + alteKW + " AND Material='" + material + "' AND KapazitätNo=" + 
     kapazitaet;

     comm.ExecuteNonQuery();
  }
  catch (Exception e)
  {
      return e.Message+' '+e.StackTrace;
  }
  finally
  {
      conn.Close();
  }

  return "ok";
}

Flex 3: Bemalbares mx:Canvas mit FluorineFX-Messaging (Montagsmaler)

Aufgabenstellung

Unter Verwendung der FluorineFX Messaging-API soll eine Montagsmaler-Anwendung implementiert werden. Dies bedeutet dass ein User auf eine Leinwand zeichnet und die anderen Seitenbesucher in Echtzeit eine Aktualisierung auf dem Bildschirm erhalten. Dies kann auch als Grundlage für weitere Kollaborationsanwendungen genutzt werden, in denen man gemeinsam ein Dokument konstruieren möchte.

Ansatz

Nachdem die Zeichnenfunktionalität implementiert ist, werden die Bildpunkte beim loslassen der Maustaste (MOUSE_RELEASE_EVENT) an alle Clients übertragen. Die Clients reagieren bei einer einkommenden Menge an Bildpunkten und zeichnen sofort auf die Leinwand. Es wird immer die komplette Leinwand mit allen Bildpunkten beim Mouse-Release gesendet.

Durch das Publisher/Subscriber-Prinzip abonniert die Flex-Anwendung beim Start sofort die Datenquelle „painter„. Die Datenquelle erhält Bildpunkte und verteilt sie an alle Abonennten, wenn diese nach dem zeichnen die Maus gesehn lassen.

Vorraussetzungen

Die FluorineFX-Konfigurationsdatei wird angepasst, so das es eine neue Messaging Quelle „painter“ existiert.

Konfiguration des Backends

services-config.xml:

<?xml version="1.0" encoding="utf-8" ?> 
<services-config>
    <services>
        <service-include file-path="remoting-config.xml" />
        <service-include file-path="messaging-config.xml" />
    </services>
    
    <!-- Custom authentication -->
    <security>
    </security>
    
    <channels>
        <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
           <endpoint uri="http://{server.name}:{server.port}/{context.root}/Gateway.aspx" 
             class="flex.messaging.endpoints.AMFEndpoint"/> 
            <properties>
            </properties>
        </channel-definition>

        <channel-definition id="my-rtmp" class="mx.messaging.channels.RTMPChannel">
            <endpoint uri="rtmp://{server.name}:2037" 
            class="flex.messaging.endpoints.RTMPEndpoint"/>
            <properties>
                <idle-timeout-minutes>20</idle-timeout-minutes>
            </properties>
        </channel-definition>

    </channels>
</services-config>

messaging-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<service id="message-service" class="flex.messaging.services.MessageService" 
    messageTypes="flex.messaging.messages.AsyncMessage">

     <!-- DO NOT CHANGE <adapters> SECTION-->
    <adapters>
	<adapter-definition id="messagingAdapter" 
             class="FluorineFx.Messaging.Services.Messaging.MessagingAdapter" 
             default="true"/>
    </adapters>
    <destination id="chat">
	<adapter ref="messagingAdapter"/>
        <properties>
            <network>
                <session-timeout>0</session-timeout>
            </network>
        </properties>
        <channels>
            <channel ref="my-rtmp"/>
        </channels>
    </destination>
    <destination id="textchat">
	<adapter ref="messagingAdapter"/>
        <properties>
            <network>
                <session-timeout>0</session-timeout>
            </network>
        </properties>
        <channels>
            <channel ref="my-rtmp"/>
        </channels>
    </destination>
    <destination id="painter">
	<adapter ref="messagingAdapter"/>
        <properties>
            <network>
                <session-timeout>0</session-timeout>
            </network>
        </properties>
        <channels>
            <channel ref="my-rtmp"/>
        </channels>
    </destination>
    <destination id="opminboxrefresher">
	<adapter ref="messagingAdapter"/>
    	<properties>
	    <network>
            	<session-timeout>0</session-timeout>
            </network>
    	</properties>
    	<channels>
         	<channel ref="my-rtmp"/>
    	</channels>
    </destination> 
</service>

Konfiguration des Frontends

Bei den Frontend Konfigurationsdateien kann einfach die Datei services-config.xml und die Datei messaging-config.xml kopiert werden. Es können aber absolute Pfade anstelle der Platzhalter wie {server.name},{server.port},{context.root} genutzt werden. Hierdurch ist eine lokale Entwicklung der Flex-Anwendungen mit einem entfernten IIS Server möglich.

Lösung

PaintMessaging.mxml (Projektdatei)

<?xml version="1.0" encoding="utf-8"?>
<mx:Application creationComplete="{init()}" xmlns:mx="http://www.adobe.com/2006/mxml" 
	layout="absolute" xmlns:components="components.*">
	<mx:Script>
		<!&#91;CDATA&#91;
			import models.ModelLocator;
			import mx.controls.Alert;
			import mx.messaging.events.MessageFaultEvent;
			import mx.messaging.events.MessageEvent;
			import mx.messaging.messages.AsyncMessage;
			import mx.managers.CursorManager;
			&#91;Bindable&#93;
            &#91;Embed(source="../assets/stiftklein.png")&#93;
            private var stift:Class;
            
            public var cursorID:int;
            
            public function init():void 
            {
            	consumer.subscribe();
            }
            
            public function mouseOverHandler(event:MouseEvent):void
            {
            	
            }
            
            public function downEvent(event:MouseEvent):void 
            {
            	
            } 
            
            public function upEvent(event:MouseEvent):void
            {
            	
            }
            
	private function messageHandler(event:MessageEvent):void
    	{
    	    ModelLocator.getInstance().lines=event.message.body as Array;
    	    dc_main.invalidateDisplayList();
    	}
   
   	private function messagefaultHandler(event:MessageFaultEvent):void
   	{ 
   	   Alert.show(event.faultCode+' '+event.faultDetail+' '+event.faultString); 
   	}     		
            
	&#93;&#93;>
	</mx:Script>
	<mx:Consumer id="consumer" destination="painter" 
		message="messageHandler(event)" fault="messagefaultHandler(event)"/>
    <mx:Producer id="producer" destination="painter" 
    	fault="messagefaultHandler(event)"/>		

    <mx:Panel mouseOver="{ cursorID = CursorManager.setCursor(stift); }" 
    	mouseOut="{CursorManager.removeCursor(cursorID);}" 
    	layout="absolute" 
    	title="Montagsmaler by Björn Karpenstein" 
    	backgroundColor="#ffffff" 
    	borderThicknessBottom="10" left="20" 
    	right="20" top="20" bottom="20">
       <components:DrawableCanvas id="dc_main" backgroundColor="#ffff80" 
       	backgroundAlpha="0" width="100%" height="100%" y="0" x="0">
       </components:DrawableCanvas>
    </mx:Panel>
		
</mx:Application>

DrawableCanvas.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="300" 
       creationComplete="init()">
    
    <mx:Script>
        <!&#91;CDATA&#91;
            
            public var lineWidth:Number = 5;
            
            public var lineColour:uint = 1;
            
            public var lineAlpha:Number = 1;
            
            
            private var enabler:DrawingEnabler;
            
            private function init():void
            {
                enabler = new DrawingEnabler(this);
            }            
            
            protected override function updateDisplayList(unscaledWidth:Number,
                            unscaledHeight:Number):void
            {
                super.updateDisplayList(unscaledWidth, unscaledHeight);
            
                if( enabler != null ) enabler.drawLines(graphics, lineWidth, 
                lineColour, lineAlpha);
            }
        &#93;&#93;>
    </mx:Script>
</mx:Canvas>

DrawingEnabler.as

package components
{
import flash.display.Graphics;
import flash.events.MouseEvent;

import models.ModelLocator;

import mx.core.Application;
import mx.core.UIComponent;
import mx.messaging.messages.AsyncMessage;

public class DrawingEnabler
{
private var _target:UIComponent;

private var _curentLine:Array;

public function DrawingEnabler( target:UIComponent ):void
{
_target = target;
_target.addEventListener(MouseEvent.MOUSE_DOWN, downEvent);
_target.addEventListener(MouseEvent.MOUSE_UP, upEvent);
_target.addEventListener(MouseEvent.MOUSE_OUT, upEvent);
}

public function sendMessage(stream:Array):void
{
var message:AsyncMessage = new AsyncMessage();
message.body = stream;
Application.application.producer.send(message);
}

public function newLine():void
{
_curentLine = new Array();
ModelLocator.getInstance().lines.push( _curentLine );

if( ModelLocator.getInstance().lines.length > 10 )
ModelLocator.getInstance().lines.shift();
}

public function addPoint(xIN:int, yIN:int):void
{
_curentLine.push( { x:xIN, y:yIN } );
_target.invalidateDisplayList();
}

public function drawLines(graphics:Graphics,lw:Number,lc:uint,la:Number):void
{
graphics.clear();
graphics.lineStyle(lw,lc,la);

for( var j:int = 0; j

Flex 3 und Google Maps API

Aufgabenstellung

In eine Flex-Anwendung soll Google Maps integriert werden.

Ansatz

1.) Aufruf der Seite http://code.google.com/intl/de/apis/maps/documentation/flash/
2.) Runterladen der Flash-Bibliothek (SWC-Datei) und einfügen in das LIBS-Verzeichnis der Flex-Anwendung
3.) Anfordern des Schlüssels unter „Wie beginne ich…“ und eintragen in den Code unten.

Lösung

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
	<!&#91;CDATA&#91;
		import com.google.maps.overlays.Marker;
		import com.google.maps.controls.ZoomControl;
		import com.google.maps.geom.Attitude;
		import mx.controls.Alert;
		import com.google.maps.*;
		import com.google.maps.geom.*;
		import com.google.maps.services.GeocodingEvent;
		import com.google.maps.services.ClientGeocoder;
		import com.google.maps.controls.NavigationControl;
		import com.google.maps.controls.MapTypeControl;
		import com.google.maps.MapEvent;
		
		public function onMapReady(event:MapEvent):void
		{
			// Die Bedienelemente der Karte hinzufügen
			map.addControl(new MapTypeControl());
			map.addControl(new NavigationControl());
			this.geocodeLocation('Fulda, Am Rinnweg 15');
		}
		
		public function onMapPreinitialize(event:MapEvent):void
		{
			var myMapOptions:MapOptions = new MapOptions();
			myMapOptions.viewMode = View.VIEWMODE_2D;
			myMapOptions.mapType=MapType.NORMAL_MAP_TYPE;
			//myMapOptions.zoom=0;
			map.setInitOptions(myMapOptions);
		}
		
		private function geocodeLocation(location:String=''):void
		{
			var geocoder:ClientGeocoder = new ClientGeocoder();
			geocoder.addEventListener(GeocodingEvent.GEOCODING_SUCCESS,
			geoCodeSuccess);
			geocoder.addEventListener(GeocodingEvent.GEOCODING_FAILURE, 
			geoCodeFailure);

			if(location!='')
			{
				geocoder.geocode(location);
			}
			else
			{
				geocoder.geocode(search.text);
			}
		}
		
		private function geoCodeSuccess(event:GeocodingEvent):void
		{
			var placemarks:Array = event.response.placemarks;
			map.flyTo(placemarks&#91;0&#93;.point, 18, new Attitude(35,60,35), 
			3);
			var marker:Marker = new Marker(placemarks&#91;0&#93;.point); 
			map.addOverlay(marker); 
		}
		
		private function geoCodeFailure(event:GeocodingEvent):void
		{
			Alert.show('Also wissense, das find ich einfach ned....',
                                       'Ähm...');			
		}		
	&#93;&#93;>
</mx:Script>
	<mx:TitleWindow layout="vertical" width="100%" height="100%" 
              title="Finde versteckte Schätze... 
             (c) die 1st-level-caches Schludi&amp;Mephi ">
		<maps:Map3D xmlns:maps="com.google.maps.*" 
			  id="map" 
			  mapevent_mapready="onMapReady(event)" 
			  mapevent_mappreinitialize="onMapPreinitialize(event)"
			  width="100%" 
			  height="100%"
    		  key="HIER KOMMT DER BEANTRAGTE GOOGLE KEY REIN"/>
    	<mx:HBox horizontalAlign="center" width="100%" height="30">
			<mx:Label x="70" y="524" text="Da will ich hin:" 
                                        width="120" fontWeight="bold"/>
			<mx:Button x="421" y="520" label="Suchen ..." 
                                        click="{geocodeLocation()}"/>
			<mx:TextInput id="search" x="167" y="520" 
                                       width="246"/>
    	</mx:HBox>
	</mx:TitleWindow>
</mx:Application>

Beispiel

http://baugebiete.fulda.de

FluorineFX: Standard Authentifizierung über die Session

Aufgabenstellung

Im Internet sollen sich Benutzer an einer Anmeldemaske einer Flex-Anwendung anmelden. Die Berechtigungen sollen anhand des Benutzernamens festgelegt werden.

Ansatz

1.) FLEX: Erstellen der Anmeldemaske mit User/Passwort
2.) C#: Überprüfung ob die User/Passwort-Kombination in der Datenbank vorhanden ist
3.) C#: Falls JA: Benutzer in die sessionvariable USERNAME schreiben / Falls NEIN: Tue nichts
4.) C#: Überprüfung der Backend-Services: Ist USERNAME leer?
NEIN: Darf der User die Daten aufrufen?? (Dem Benutzer kann eine ROLLE zugewiesen sein, siehe Artikel „FluorineFX: Windows Authentifierung… Single Sign On“, und anhand der Rolle kann ermittelt werden ob sie berechtigt ist die Daten abzurufen).
JA: Keine Daten ausliefern!!!
5.) FLEX: Falls user authentifziert: Maskenaufbau in der Flexanwendung entsprechend Rolle

Lösung

Hier die wichtigsten Auszüge aus meiner Lösung:

FLEX:

...
<mx:Script>
public function getAuthenticationHandler(event:ResultEvent):void
{
   if( (event.result as Boolean) )
   {
     // Schalte ViewStack um (keine Loginmaske mehr)
     loginStack.selectedChild=tarzanScreen;

     // Speichere Username in Modellocator (evtl. auch Rolle holen)
     ModelLocator.getInstance().myUser=txtUsername.text;
   }
   else
   {
      Alert.show('Wrong username or password!');
    }						
}
</mx:Script>
...
<mx:TextInput id="txtUsername" />
<mx:TextInput id="txtPasswort" displayAsPassword="true"/>
...
<mx:RemoteObject id="authenticationService" destination="GenericDestination"  
                                          source="TarzanServices.AuthenticationService" 
                                          showBusyCursor="true" 
                                          fault="faultHandler(event)" >
    <mx:method name="getAuthentication" result="getAuthenticationHandler(event)"/>
</mx:RemoteObject>

C#: Benutzername ermitteln: Falls „none“ einfach nix in Maske/Service machen:

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Data.SqlClient;
using System.Web;
using FluorineFx;
using System.Security.Principal;
...
public string getSessionUser()
{
    if (FluorineFx.Context.FluorineContext.Current.Session["username"]==null) 
    return "none";

    return FluorineFx.Context.FluorineContext.Current.Session["username"].ToString();
}

C#: Überprüfe ob User/Kennwort-Kombination in der Datenbank vorhanden ist, falls JA, schreibe USERNAME in Sesseion und liefere TRUE zurück, damit Flex weiß das es von der Login-Maske weg darf.. (REAKTION IN FLEX).

public bool getAuthentication(string username, string password)
{
   SqlConnection conn = new SqlConnection(MyConfigurationManager.msSqlServerString);

   try
   {
      conn.Open();
      SqlCommand comm = new SqlCommand();
      comm.Connection = conn;
      comm.CommandText = "SELECT * FROM [users] WHERE [username]=@username "+
                                     "AND [password]=@passwort";
      comm.Parameters.AddWithValue("username", username);
      comm.Parameters.AddWithValue("passwort", password);

      int i = 0;
      SqlDataReader reader = comm.ExecuteReader();

       while (reader.Read())
       {
              i++;
       }

       if (i > 0)
       {
           // Schreibe USER in die Datenbank
           FluorineFx.Context.FluorineContext.
           Current.Session["username"] = username;
       }

       return i > 0;
   }
   catch (Exception e)
   {
        return false;
   }

   return false;
}

FluorineFX: Single-Sign-On per Windows Authentifizierung

Aufgabenstellung

In einem Windows Netzwerk mit Windows Servern sollen beim Aufruf einer Intranet-Web-Anwendung der angemeldete Benutzer automatisch ermittelt werden, so dass keine Benutzername/Kennwort-Maske zusätzlich erforderlich ist. Anhand des Benutzernamens können Berechtigungen festgemacht werden, die z.B. über ein Benutzerrollen-Konzept zugewiesen werden können.

Ansatz

Es wird die FluorineFX-API verwendet um den Windows User zu ermitteln. Dies kann im Preloader der Flex/Flash-Anwendung geschehen. Die Masken werden nachträglich anhand der Rolle aufgebaut bzw. angepasst.

Definition des Benutzerrollenkonzeptes

Eine Rolle ist eine Aufgabe, die eine Person in einem Unternehmen hat. In der Datenbank würde man auf relationaler Ebene 3 Tabellen benötigen, um ein Benutzerrollen-Konzept zu realisieren. Ein Benutzer hat keine, eine oder mehrere Rollen, wobei eine Rolle keinem, einem oder mehreren Benutzern zugewiesen werden kann. Man benötigt also eine Tabelle USER und eine Tabelle ROLE. Da es sich hierbei um eine M:N-Beziehung handelt, ensteht eine Zusatztabelle USERROLE, die die Foreign Keys der Tabelle USER und ROLE speichert.

Vorraussetzungen

In der Firma wird vorzugsweise der Internet-Explorer verwendet. Die Verwendung von Firefox ist möglich, benötigt aber eine Spezialkonfiguration für Windows-Authentifizierung.

Im IE:

Unter Extras / Internetoptionen / Erweitert / Integrierte Windows Authentifzierung aktivieren

Im Firefox:

  • in der Adressleiste „about:config“ eingeben
  • im Fenster rechte Maustaste, dann Neu -> String
  • Eigenschaftsnamen „network.automatic-ntlm-auth.trusted-uris“ eingeben
  • String-Wert: Name des Portalrechners. Wenn auf das Portal beispielsweise

über http://musterfirma/teamworks zugegriffen wird ist der korrekte Wert „musterfirma“ eingetragen

Im IIS Manager sollte mit der rechten Maustaste auf der Web-Anwendung / Eigenschaften der Haken „Windows Authentication“ gesetzt sein, sonst liefert der IIS nichts zurück.

Lösung

1.) Anlegen der 3 Tabellen USER, USERROLE und ROLE.
2.) Der Windows-User kann in einem ordinären Backendservice mit folgendem Code ermittelt werden:

System.Security.Principal.WindowsPrincipal p =
System.Threading.Thread.CurrentPrincipal as System.Security.Principal.WindowsPrincipal;
string strName = p.Identity.Name;
string userWithDeletedDomainPrefix = strName.Substring(strName.IndexOf("\\") + 1).Trim();

3.) Reaktion in der Flex-Anwendung auf die zugewiesenen Rollen (Maskenaufbau)
4.) Schützen der Backendservices anhand der zugewiesenen Rollen (Auch ohne Flex keine sicherheitskritischen Daten aufrufbar)

ASP.NET und C#: Excel Dateien im Web darstellen

Aufgabenstellung

Eine Excel Datei, die in einer Firma ständig aktualisiert wird, soll auf Smart Phones (Blackberrys, iPhones, Windows Mobiles, HTCs …) abrufbar sein.

Vorraussetzungen

Vorweg solllte der Artikel „WebDAV mit IIS einrichten“ durchgearbeitet werden, um Zugriff zu bekommen.

Ansatz

Die Datei wird ortstransparent auf einem WebDAV-Laufwerk (siehe Artikel WebDAV einrichten) eines Microsoft IIS Server gespeichert, der nach dem Verfahren von Artikel „WebDAV einrichten“ konfiguriert ist.. Der Microsoft JET Treiber verfügt über die Fähigkeiten, Excel Dateien zu laden (nur XLS, nicht XLSX oder XLSM). Im IIS Server wird eine ASP.NET Anwendung angelegt. Das nachfolgende Beispiel ist so eingerichtet, das es versuchen wird aus dem Web Root der Anwendung eine Datei test.xls zu laden.

Lösung

Anlegen eine ASP.NET Seite:

<%@ Page Language="C#" AutoEventWireup="true"  
CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Unbenannte Seite</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:GridView ID="GridView1" runat="server">
        </asp:GridView>
        &nbsp;</div>
        <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
    </form>
</body>
</html>

… mit dem folgenden Code:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.OleDb;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {

        string appPath = HttpContext.Current.Request.ApplicationPath;
        string physicalPath = HttpContext.Current.Request.MapPath(appPath).
                                                         Replace("\\","\\\\");

        string ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0; 
        Data Source="+physicalPath+"\\test.xls; Extended Properties="+
                                                              \"Excel 8.0;HDR=Yes\";";

        string CommandText = "select * from [Tabelle1$]";

        OleDbConnection myConnection = new OleDbConnection(ConnectionString);
        OleDbCommand myCommand = new OleDbCommand(CommandText, myConnection);

        myConnection.Open();

        GridView1.DataSource = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
        GridView1.DataBind();

        myConnection.Close();

        Label1.Text = physicalPath;
    }
}

Beispiel

Diese Datei kann per WebDAV bearbeitet werden:
http://178.77.69.22/test.xls

und wird on-the-fly in eine HTML-Seite umgewandelt:
http://178.77.69.22/exceltoweb/Default.aspx

Wie aktuell ist noch HTML 5?

HTML 5 ist nicht gleich HTML 5

HTML 5 entstand nicht durch das W3C-Konsortium, sondern war ursprünglich eine Spezifikation von WHATWG, einer Arbeitsgruppe von großen Browserherstellern. Nach einiger Zeit wurde das W3C darauf aufmerksam, wollte sich allerdings nicht der WHATWG anschließen und entwickelte an einer Kopie der Spezifikation weiter. Seitdem gibt es 2 unterschiedliche Versionen oder Auffassungen, die ein gemeinheitliches Verständnis von HTML 5 verhindern. Nach dem Verständnis von WHATWG, soll vom jetzigen Standpunkt eine rollierende, iterative Entwicklung stattfinden, so dass es kein HTML 6 geben wird… das W3C hingegen beruft sich auf Spezifikationsstände, die in einer Versionsnummer kenntlich gemacht werden sollen (wie bisher).

Wenn wir als Web-Entwickler von HTML 5 sprechen, müssen wir immer klar machen, auf welche Spezifikation wir uns beziehen und vor allem: ZU WELCHEM ZEITPUNKT. Momentan gibt es kein einheitliches Verständnis von HTML 5 und die meisten Internetnutzer fragen sich, über welche sinnlosen Dinge wir uns den Kopf zerbrechen, denn ihr Webbrowser „kann doch schon HTML 5″….

Browserunterstützung – Stand: 6. Januar 2011

Auf der Seite http://html5test.com/ lässt sich die Browserkompatibilität mit HTML 5-Seiten testen. Welcher Spezifikation das genügt, müsste man im Detail untersuchen.

  • Internet Explorer 7 ist das Schlusslicht: 21 von 300 Punkten
  • Internet Explorer 9 PPT hat bereits 79 von 300 Punkten
  • der aktuelle Firefox 3.6.13 erhält 139 von 300 Punkten
  • die Beta Version vom 4er Firefox erhält bereits 235 von 300
  • Opera 10.62 bekommt 203 von 300 Punkten
  • Apple Safari 5.0.1 erhält 178 von 300 Punkten
  • Gewinner ist Google Chrome / Chromium 7 mit 262 von 300 möglichen Punkten.

Bei dem beachtlichen Marktanteil vom Internet Explorer (immerhin über 50 Prozent) spielt es keine Rolle welcher Browser der bessere HTML 5 Interpreter ist … Internetseiten sollen barrierefrei und browserunabhängig für jeden Nutzer lesbar bleiben…

Wer unbedingt jetzt schon HTML5 nutzen will…

… kann das HTML 5 Boilerplate einsetzen. Hierbei handelt es sich um einige Bibliotheken, die nach der Einbindung bei älteren Browsern eine Ersetzung von HTML5-Tags in Browser-verständliche Elemente vornimmt. Die funktioniert in einigen Browsern wie dem Firefox aber nur bedingt…

Mein Fazit…

… ist, wenn sich die Herrschaften mal geeinigt haben, was HTML 5 ist, wird das mit Sicherheit eine tolle Sache. Bis dahin sollte man darauf verzichten. Die gerühmten Elemente wie WebGL, die das Erstellen von 3D-Objekten im Browser ermöglichen, sind eigentlich kein Bestandteil der Spezifikation, werden aber mit HTML 5 in Verbindung gebracht.

WebDAV-Laufwerk mit Microsoft Windows Server 2003 und IIS konfigurieren

Aufgabenstellung

Es soll auf ein Dateisystem eines Internetservers zugegriffen werden, um z.B. Internetseiten zu bearbeiten oder z.B. Daten (CSV-Dateien, Excel-Sheets, Access-DBs… ) zu übertragen.

Problem

Aus einem sicherem Firmennetzwerk sollen Dateien komfortabel auf einen entfernten Windows Server kopiert werden. Der Begriff „komfortabel“ bedeutet, das man völlig orts- und relokationstranparent mit diesem Speicherort umgehen kann, es also keine Rolle spielt ob ich von Photoshop aus meine PSD-Dateien lokal habe oder mit einem entfernten Ort arbeite. Das Firmennetzwerk erlaubt über einen Proxy-Server Internetzugriff lediglich auf Port 80, so das man Internetseiten aufrufen darf. Eine FTP-Verbindung mit einem Internet-Server ist nicht möglich, da der FTP-Port 21 geblockt wird.

Auch das Arbeiten mit einer Web2FTP-Lösung oder eines Tunnels über ein FTP-Uploadformular erscheint sehr unbefriedigend, da ich in Photoshop über „Speicher Unter…“ ja kein Webformular auswählen kann, sondern vorerst die Datei zwischenspeichern und hochladen muss.

Vorraussetzungen

Dieser Artikel geht davon aus, das sie den Microsoft Windows Server 2003 oder höher (32- oder 64-Bit) bereits für ein laufendes Netzwerk konfiguriert haben und mindestens IIS 6 sowie den IIS Manager installliert haben. Der IIS sollte durch Zugriff auf die IP-Adresse erreichbar sein.

Ansatz

Das WebDAV-Protokoll erlaubt das Mounten von Dateisystemen über den in Windows integrierten WebDAV-Client. Sollte dieser Dienst deinstalliert sein, oder aus irgendwelchen Gründen nicht funktionieren, bietet das kostenlose Freewartool „Netdrive“ einfachste Einstellmöglichkeiten für Proxyserver und entfernte HTTP-Locations (wie http://meinserver/webdavfreigabe).

Lösung

Zuerst wird IIS konfiguriert

* WebDAV muss eine erlaubte Webdiensterweiterung im IIS-Manager sein

* Unter Webdiensterweiterungen muss für 64-Bit-Systeme ebenfalls das x64 Modul für Webdav eingebunden werden:

C:\Windows\Syswow64\inetsrv\httpext.dll


* HTTP (TCP-Port 80) muss in der Firewall erlaubt sein

Anschließend das Verzeichnis freigegeben

Die Einrichtung erfolgt über einen Ordner im Dateisystem der mit Hilfe der Registerkarte Webfreigabe bei den Eigenschaften des Ordner freigegeben wird.
Wählen Sie einen Alias aus und legen Sie die Webseite fest unterhalb der Webdav-Freigabe sichtbar ist.

Anonymer Zugriff ermöglichen

Soll der Ordner anonym für jeden zugänglich sein, kann man den Internet Guest Account „IUSR_TEMPLATE“ in den Ordneroptionen hinzufügen

Authentifizierter Zugriff (Benutzername/Kennwort)

In den meisten Fällen möchte man eine Standard Authentifizierung haben, wo zumindest Benutzername und Kennwort abgefragt wird, um den WebDAV-Ort vor ungewollten Zugriffen zu schützen.

Zunächst legt man hierfür einen User auf dem Windows-Server an (z.B. Schludi) (Anmerkung: Ich habe ihn in die gleichen Gruppen gesteckt wie IUSR_TEMPLATE, weiß nicht ob das notwendig ist…) . Der User kann am Server über START, Administrative Tools, Computer Management angelegt werden:

Das Passwort, was man dem User gibt, ist gleichzeitig das Passwort für den WebDAV-Zugriff.

Anschließend weißt man in den Ordereigenschaften (hier der User schludi) dem Ordner den Nutzer zu:

Hat man dies getan sollte man die Default-Website im IIS markieren und F5 klicken (aktualisieren). Es erscheint im aufgeklappten „Default-Website“-Knoten ein Zahnrad-Icon mit dem Alias-Namen des Ordners. Hier klicken wir wieder mit der rechten Maustaste und wählen den Menüpunkt Properties/Eigenschaften. Unter dem Reiter „Directory Security“ wird der Haken „Enable anonymous access“ entfernt und die Authentifizierungsmethode auf Basic Authentication gestellt. Die Einstellungen sollten mit dem Apply/Übernehmen-Button gesichert werden.
Ich habe übrigens eine Default-Domain „CT42946\“ eingetragen, damit es nicht nötig wird, den Domainpräfix vor den Usernamen zu schreiben. Ich habe in internationalen Intranets die Erfahrung gemacht, das Server in unterschiedlichen Domainen oftmals den Benutzernamen nicht akzeptieren, wenn man den Default-Domainpräfix nicht angegeben hat.

Zugriffmöglichkeiten mit Windows Methoden

Es gibt nun diverse Möglichkeiten diese WebDAV-Location als Netzwerklaufwerk mit herkömmlichen Windows-Methoden zu mounten, wovon je nach Client-Konfiguration nicht jede funktionieren muss…
Generell sollte der Dienst „WebDAV-Client“ auf dem Client-Rechner unter Services installiert und aktiviert sein, dies kann über die Systemsteuerung/Control Panel unter „Dienste/Services“ vorgenommen werden.

Laufwerksbuchstabe über Kommandozeile/Eingabeaufforderung mounten

Es wird die MS DOS Eingabeaufforderung geöffnet und der folgende Befehl eingegeben:

net use u: http://serveroderip/webdavalias

Ist eine Basic Authentication nach der Vorgehensweise oben eingestellt worden, fragt die Eingabeaufforderung nun User und Kennwort ab. Sollte ein Proxy erforderlich sein, wird der Standard-Proxy der Interneteinstellungen (Systemsteuerung/Internet Explorer) genommen.
Nun sollte Laufwerk U: gemountet sein. Ist dies nicht der Fall empfehle ich testweise einen Zugriff per Netdrive (siehe einige Zeilen weiter unten) auszuprobieren. Probieren Sie auch aus, ihren Domain-Präfix vor den Username DOMAINPRÄFIX\User zu schreiben (siehe auch weiter oben im Text: Empfehlung zur Einstellung des Default-Domain-Präfix).

Netzwerklaufwerk über Explorer zuordnen

Nachdem man den Windows-Explorer geöffnet hat, gibt es die Möglichkeit mit einem Rechtsklick auf das Netzwerk-Icon die Option „Netzwerklaufwerk verbinden“ zu wählen. Hier öffnet sich ein Dialog, der normalerweise einen typischen Windows-Filesharingpfad erwartet, aber unten einen Link „Verbindung mit einer Website herstellen, auf der Sie Dokumente und Bilder speichern können“ hat. Dieser Link ermöglicht mit Bordmitteln von Windows das mounten eines Netzwerklaufwerkes.

Zugriff mit einem Netdrive-Client

Obwohl man ihn erst runterladen muss, finde ich die Nutzung des Netdrive-Clients viel komfortabler und weniger problematisch als die Nutzung der Windows-Bordmittel. Einfach mal nach „netdrive download“ googeln, und man findet irgendeinen Ort (z.B. CHIP-Server) wo er runterladbar ist.

Nach der Installation lässt sich einfach die Verbindung eintragen, der „Advanced“-Button ermöglicht die Angabe eines Proxyservers, über den Verbindung aufgenommen werden kann.

Resumee

WebDAV ist eine gute Methode um bei stabiler Internetverbindung mit entfernten Dateisystemen zu arbeiten, auch wenn der Zugriff nach außen lediglich über Port 80 möglich ist. Hierbei muss der Web-Server nicht umkonfiguriert werden, sondern lediglich ein WebDAV-ALIAS auf der Defaultwebsite hinzugefügt werden.

Spießer-Zensuren in Wikimedias

Faszinierend wieviele freiwillige Autoren bei Wikipedia unentgeltlich ihre Arbeit verrichten. Die Idee einer freien Kollaborationsanwendung / eines „Gedankentempels“ (Zitat von Jimmy Wales, Gründer von Wikipedia) scheint allerdings mit der Diskussion nach Sinnhaftigkeit von Artikeln und deren Existenzberechtigung zu stehen und zu fallen. Nachdem die Administratoren ihre Rechte bekommen haben um Artikel zu löschen, entpuppen sich viele als nervöse, bewaffnete Moralapostel mit dem Finger am Abzug. Das scheint bei einer Enzyklopädie erstmal sinnvoll. Lieber kein Artikel zusätzlich, als ein schlechter Artikel zusätzlich…

Aber wieso wird bei Stupipedia und Uncyclopedia Satire zensiert? Ich saß mit einem Bekannten in der Sylvesternacht am Tisch und trank ein Gläschen Eierlikör. Dieser kam auf die Idee dem Getränk den Namen „Hoden Brandy“ zu geben, was wir zunächst witzig fanden. Die Idee, man könne einen satirischen Artikel darüber verfassen, scheiterte schon nach der Artikelanlage.

Bei Uncyclopedia haben wir uns einen festen User registriert und den Artikel „Hodenbrandy“ angelegt. Nachdem die Sektion „Definition“ verfasst wurde, in der wir lediglich einige Sätze mit Andeutungen auf „Eierlikör“ schrieben, war der Artikel bereits beim zweiten oder dritten Mal speichern verschwunden. Wir dachten uns: „Okay, da dachte wohl jdm. das wär ein Spam-Artikel“… Also versuchten wir ihn nochmals anzulegen, allerdings war der Artikel gesperrt. Wir legten einen zweiten Artikel „Hoden Brandy“ (auseinander mit Leerzeichen) an. Kurz danach wurde unser Benutzer gesperrt.

Anschließend versuchten wir unser Glück auf Stupipedia. Wir kopierten den Text, den wir mit dem Wiki-Markup bereits vorsorglich in Notepad zwischengelagert hatten, hinein. Kurz danach kam der erste Kommentar „grenzwertig“. Durch das Setzen des „In-Use“-Tags erklärten wir, dass wir noch am Arbeiten sind, und den Artikel überdenken. Wir erstellten eine lustige Visio-Grafik mit einem Kaizen-Diagramm über den Produktionsprozess des Brandys… Ca. 10 Minuten später wurde der Artikel gelöscht, da es sich angeblich um einen sexistischen Inhalt handele.

Der Artikel war im vgl. zu anderen Satiren weder sexistisch noch eklig oder hätte es gerechtfertigt unseren Benutzer zu sperren. Es wurde niemand persönlich angegriffen, da auch keine Person
angesprochen wurde. Wenn man sich die Sprüche von Michael Mittermeier oder Mario Barth anhört, vernimmt man gelegentlich tollerierte sexistische Inhalte. Aber die Beschreibung von Eierlikör unter dem Namen „Hoden Brandy“ ist an Harmlosigkeit kaum zu überbieten.

Auf der einen Seite bewundere ich das Engagement der Administratoren, auf der anderen Seite ärgere ich mich über die Spießigkeit und frage mich ob eine längere Tätigkeit auf diesem Gebiet zu Abgestumpftheit führt. Die Interpretation der Richtlinien wird häufig am eigenen Maßstab festgemacht. Was die Erhaltung von Artikeln und den Umgang mit der Arbeit von fremden Personen betrifft, wünschte ich mir hier etwas Professionalität. Auf den Löschen-Button ist schnell geklickt und die Arbeit von Stunden zerstört.

Auf der anderen Seite kann man wirklich über die Sinnhaftigkeit von Satire in Uncyclopedia/Stupipedia streiten 😉 …
Definiert Wikipedia die Satire als „eine Spottdichtung, die mangelhafte Tugend oder gesellschaftliche Missstände anklagt“, sollte sie hier gegen ihr eigenes Rahmenwerk eingesetzt werden.

Hier ein netter Versuch – ein satirischer Artikel über den Vorfall bei den Stupidedia Administratoren:
http://www.stupidedia.org/stupi/Stupidedia_Administrator

… mal schauen wie langer er sich hält, er soll ab 11. Januar gelöscht werden, unten sieht man wie sich die Administratoren aufregen XD …