Wie stellen Sie Ihre .NET-Webanwendung bereit? (Empfehlungen bitte!)


10

Wir haben kürzlich unsere ASP.NET- Website auf eine Webanwendung aktualisiert und sind schockiert über den plötzlichen Schwierigkeitsgrad bei der Bereitstellung. In Anbetracht der Häufigkeit dieser Aufgabe habe ich mich gefragt, mit welchen Plug-Ins / Software-Benutzern ein sich schnell entwickelndes, remote gespeichertes Projekt (z. B. eine Website) bereitgestellt wird.

Es muss einen besseren Weg geben, als nur in Visual Studio zu "veröffentlichen" und dann die geänderten Dateien manuell per FTP zu übertragen. Nicht zuletzt, weil die Website beim Hochladen unserer DLLs ausfällt.

Es gibt so viele fummelige Dateiausnahmen, dass ich den Prozess lieber so weit wie möglich automatisieren möchte, um versehentliche Uploads zu verhindern.

Mit unserer alten Lösung (auf unserer Website) haben wir Dispatch for ASP verwendet, was den gesamten Prozess mit einem Klick erschütterte. Leider ist es nicht gut für DLLs (wie bereits erwähnt).

Wie macht Ihr Team das?

Vielen Dank für jeden Rat.

PS - Ich habe gelesen, dass Visual Studio 2010 diese Mängel in VS2005 / 08 beheben soll, aber bis dahin ...


3
das ist für stackoverflow, nein?
Cicik

1
Bereitstellen einer Website auf einem Server? Ich glaube nicht - es hat nichts mit Programmierung zu tun.
Django Reinhardt

Klicken alle dann einfach auf "Veröffentlichen" und FTP-Upload? :( Es muss einen besseren Weg geben!
Django Reinhardt

Welche Schwierigkeiten hatten Sie nach dem Wechsel von der Website zur Webanwendung?
Chris

Wenn wir eine Website hatten, überwachte unsere alte Bereitstellungslösung (Dispatch) automatisch, welche Dateien geändert wurden. Diese Dateien können dann mit einem einzigen Klick in Visual Studio auf die Produktionssite hochgeladen werden (wobei bestimmte Dateien und Ordner ignoriert werden). Es war im Nachhinein Glückseligkeit.
Django Reinhardt

Antworten:


5

Ich würde die Verwendung von Continuous Integration dringend empfehlen.

Wir verwenden eine Kombination aus TeamCity für CI, Rake und Albacore, um den Build zu automatisieren.

TeamCity überprüft den Code aus Ihrem Quellcode-Repository und erstellt dann mithilfe von Rake die Anwendung, führt Komponententests durch und führt auf Wunsch sogar Ihre Datenbankskripte aus. Nach einer erfolgreichen Erstellung können Sie Ihren Quellcode in eine Zip-Datei packen oder an ein Ziel Ihrer Wahl kopieren.

Wir verwenden Git, obwohl TeamCity mit allen Versionsverwaltungssystemen funktioniert.

Die Verwendung von TeamCity und Rake ähnelt der Verwendung von CruiseControl und NANT ohne die Bearbeitung der XML-Datei. Natürlich können Sie TeamCity mit NANT verwenden, wenn Sie dies bevorzugen.

Ein kurzes Beispiel aus einer rakefile.rb, die den Build ausführt. IMHO, einfacher zu lesen und zu debuggen als eine XML-Datei.

require 'albacore'
require 'rexml/document'
require 'find'

VERSION_NO = "1.0"

OUTPUT_PATH = "output"
WEBOUTPUT_PATH = "output/web"
ADMINOUTPUT_PATH = "output/admin"

CONFIG = "Release"

WEB_PATH = "app/Company.Website.Web"
ADMIN_PATH = "app/Company.Website.Admin"
PACKAGE_PATH = "build/package"
DB_SCRIPT_PATH = "Company.Website.DB"
SOLUTION = "Company.Website.sln"

ARTIFACTS_PATH = "d:/build/artifacts/"

DEPLOY_WEB_PATH = "d:/deploy/company/website/"
DEPLOY_ADMIN_PATH = "d:/deploy/company/admin/"

task :default => ['setuptest','assemblyinfo','config','msbuild','createdb','sqlcmd','deploy']


task :setuptest do |setup|
  if ENV['BuildNumber'].nil? then ENV['BuildNumber'] = "000" end

  VERSION_NO = VERSION_NO + '.' + ENV['BuildNumber']
  puts 'Version Number : ' + VERSION_NO

  ZIPFILE_WEB = 'Company.Website.Web.' + VERSION_NO
  ZIPFILE_ADMIN = 'Company.Website.Admin.' + VERSION_NO  

  DB_SERVER = "WEB2"
  DB_DATABASE = "Website"  
  CREATEDB_SCRIPT = "app/Company.Website.DB/00CreateDatabaseTEST.sql"
end

  assemblyinfotask do |asm|
    asm.version = VERSION_NO
    asm.company_name = "Company Name"
    asm.copyright = "Copyright 2010"
    asm.output_file = "CommonAssemblyInfo.cs"
  end

  task :config do
    FileUtils.cp 'NHibernate.test.config', 'NHibernate.config'
  end

  msbuildtask do |msb|
    msb.properties = { :configuration => :Debug }
    msb.targets [:Clean, :Build]
    msb.solution = "Company.Website.sln"
  end

  sqlcmdtask :createdb do |sql|
    puts "executing sql scripts..."
    sql.log_level = :verbose
    sql.path_to_command = "sqlcmd.exe"
    sql.server = DB_SERVER
    sql.database = "master"
    sql.scripts << CREATEDB_SCRIPT
  end

  sqlcmdtask do |sql|
    puts "executing sql scripts..."
    sql.log_level = :verbose
    sql.path_to_command = "sqlcmd.exe"
    sql.server = DB_SERVER
    sql.database = DB_DATABASE
    sql.scripts << "app/Company.Website.DB/01CreateTables.sql"
    sql.scripts << "app/Company.Website.DB/02InsertReferenceData.sql"
  end

  task :deployprep do

    FileUtils.remove_dir 'app/Company.Website.Web/obj'
    FileUtils.remove_dir 'app/Company.Website.Admin/obj'

  end

  ziptask :zipweb do |zip|
    puts "creating zip package in " + ZIPFILE_WEB
    zip.directories_to_zip = ["app/Company.Website.Web"]
    zip.output_file = ZIPFILE_WEB  + '.zip'
    zip.output_path = File.dirname(__FILE__)
  end

  ziptask :zipadmin do |zip|
      puts "creating zip package in " + ZIPFILE_ADMIN
    zip.directories_to_zip = ["app/Company.Website.Admin"]
    zip.output_file = ZIPFILE_ADMIN  + '.zip'
    zip.output_path = File.dirname(__FILE__)
  end  

Albacore ist eine Suite von Rake-Aufgaben, die speziell für die Bereitstellung von .NET-Anwendungen erstellt wurden.


dumme Frage: Gibt es eine ähnliche Lösung für ein Dreamweaver-Projekt?
Djangofan

Ich weiß nicht, dass Sie tatsächlich Dreamweaver-Projekte erstellen, aber Sie könnten trotzdem kontinuierliche Integrations- und Dateikopieraufgaben verwenden, die in Rake integriert sind.
Jason Watts

3

Unter Linux habe ich Fabric (fabfile.org) und Capistrano (capify.org) verwendet, die Automatisierungstools zur Unterstützung von Remote-SSH- und SCP-Befehlen sind. Wenn Sie Cygwin auf Ihren Windows-Hosts installiert haben, sollten Sie diese als Bereitstellungstools wiederverwenden können.


2
Entschuldigen Sie, dass ich unglaublich beschissen bin, aber wie können diese mit Visual Studio verwendet werden? (Ich denke, sie können nicht?)
Django Reinhardt

3

Das "Veröffentlichen" einer Webanwendung in Visual Studio kann über die Befehlszeile als ausgeführt werden msbuild "C:\proj\yourprojectpathandfilename.csproj" /deploydir:"C:\some\deploy\dir". Das Zielverzeichnis ist eine bereitstellbare Webanwendung.

Die anderen Antworten auf Ihre größere Frage sind gut. Ich möchte auch hinzufügen, dass Sie sich mehrere Open-Source-Webanwendungsprojekte ansehen und den Build-Prozess kopieren sollten, den Sie am meisten mögen.


3

Ich stimme Scott zu, dass dies sehr kompliziert und leicht übersehen werden kann. Die Bereitstellungsstrategie ist ebenfalls sehr anwendungsspezifisch. Wenn Ihre App vollständig in einem Ordner enthalten ist, ist dies möglicherweise einfacher als eine App, die auf den GAC verweist. Dies ist möglicherweise noch einfacher als ein Server, der mehrere Versionen einer App verwalten muss, die auf mehrere Versionen von Assemblys im GAC verweist. Wir möchten hier nicht über Richtliniendateien sprechen :).

Die Kombination des Microsoft Web Deployment Tools mit dem Routing von Anwendungsanforderungen ist jedoch eine gute Option. In IIS7 ist es möglich, Installationspakete mit dem Tool zu erstellen. Es ist auch möglich, das Tool auf eine Webanwendung zu verweisen und die gesamte App in einem Anwendungsarchivordner zu sichern. Sie können dann von diesem Archivordner auf einem IIS6- oder IIS7-Webserver bereitstellen (IIS5 wird nicht unterstützt). Ich würde das Routing von Anwendungsanfragen verwenden, wie Scott vorgeschlagen hat, um Live- und Test-Websites zu trennen. Sobald Sie überprüft haben, ob die neu veröffentlichte Website ordnungsgemäß ist, können Sie ARR so einstellen, dass die Route zur neuen Version weitergeleitet wird.


2

PyroBatchFTP funktioniert hierfür hervorragend. Es werden nur die Änderungen übertragen, und Sie können ein Skript erstellen, sodass Sie mit einem Doppelklick auf eine Batchdatei eine Übertragung durchführen können.

Bei Vaasnet haben wir die Traumlösung für uns selbst eingerichtet, aber die Einrichtung ist ziemlich kompliziert , aber es lohnt sich, einige oder alle dieser Elemente zu verwenden, wenn Sie können. Folgendes ist es:

  • SVN auf allen unseren Entwicklungsmaschinen
  • SVN auf unserem Build / Deployment Server
  • Cruisecontrol.net sucht nach Änderungen an SVN und erstellt und stellt nur die erforderlichen Dateien in einem Staging-Ordner bereit
  • Mit PyroBatchFTP pushen wir zu einer Staging-Site (ausgelöst durch Cruisecontrol, damit dies automatisch geschieht).
  • Mit IIS7 und Application Request Routing (ARR) sowie URL Rewrite haben wir das folgende Staging- / Produktions-Setup:
    • ARR im Voraus leitet den Datenverkehr entweder an die Instanz 01 oder 02 weiter, je nachdem, welche "live" und welche "inszeniert" ist.
    • Das FTP-Konto ist immer an "Staging" gebunden.
    • Ich habe eine andere Mini-Admin-Site, die die Inszenierung austauscht und mit einem einzigen Klick lebt. Es dauert nur 1 Sekunde, um ohne Ausfallzeit zu wechseln, und wir können wieder zurückschalten, wenn wir feststellen, dass mit dieser Version etwas nicht stimmt (obwohl dies selten vorkommt, da wir es so einfach testen können, bevor wir live gehen).

Das Nettoergebnis ermöglicht es uns, in SVN einzuchecken und es automatisch erstellen und ohne manuelle Interaktion in die Produktion übertragen zu lassen. Nachdem wir unsere Staging-URL getestet und festgestellt haben, dass sie betriebsbereit ist, melden wir uns bei einer einfachen Site an und mit einem Klick ist sie live.


Ich wünschte, das Produkt wäre kostenlos. es sieht ziemlich cool aus.
Djangofan

Das klingt genau so, wie wir es suchen. Ich werde ein bisschen mehr darüber recherchieren, aber danke fürs Posten!
Django Reinhardt

Ja, es ist nicht kostenlos, aber es macht sich innerhalb der ersten Stunde Ihrer Zeit, die es spart, bezahlt. Das kommt in einer solchen Bereitstellungssituation ziemlich schnell.
Scott Forsyth - MVP

schön, eine Frage. Sie erwähnen, dass die Instanz 01 oder 02 live geschaltet werden kann und bei Problemen auf eine andere Instanz zurückgeschaltet werden kann. Was passiert während dieser Zeit mit Benutzerdaten in der Datenbank? Die Hälfte würde auf Instanz 1 DB sein und auf anderer Instanz DB ruhen?
Saurabh Kumar

1

Für einen anderen Weg, der nicht vorgeschlagen wurde, verweise ich Sie auf die Gu- und Web-Setup-Projekte

Dadurch wird im Grunde ein MSI-Installationsprogramm für Ihre .NET-Anwendung erstellt. Dieses Beispiel ist für VS2005, aber ich habe VS2010 und der Projekttyp ist noch vorhanden. Dies kann Ihnen viele Anpassungen ermöglichen, wenn Sie es benötigen, oder nur die Grundinstallation, wenn Sie dies nicht tun.

Persönlich, wo ich arbeite, führen wir nur eine Bereitstellung im Xcopy-Stil durch, aber ich möchte schließlich einfach ein Paket an die Servergruppe übergeben, um ihnen die Kontrolle darüber zu geben, wann und wie es bereitgestellt wird. (Ich denke, dies könnte es auch einfacher machen, Massenbereitstellungen mit so etwas wie Gruppenrichtlinien durchzuführen, aber ich bin damit nicht allzu vertraut.)


0

Es gibt viele Möglichkeiten, diese Katze zu häuten. Dies hängt wirklich davon ab, wie viel Zugriff Sie auf Ihren Server haben können. Meine persönliche Lieblingsmethode in letzter Zeit ist es, ein Build-Skript innerhalb des Projekts einzurichten (normalerweise mit MSBUILD), das alle Bereitstellungsdateien verpackt, und diese dann mithilfe von SVN in die Produktion zu überbrücken. Und um die Produktionsdateien zu versionieren.

In Bezug auf die Datenbank ist es am besten, ein Migrationsframework zu verwenden. Wieder ein paar von denen, die herumlaufen und keine wirklich klare Antwort haben.


0

Persönlich verwende ich nur ein vbs-Skript, das ich selbst geschrieben habe, um Ordner bestimmter Dateitypen auf den Entwicklungsserver zu kopieren (dh CS-Dateien usw. wegzulassen).


Unser Entwicklungsserver ist nur über FTP verfügbar, und ich hatte gehofft, wenn möglich eine maßgeschneiderte Lösung vermeiden zu müssen.
Django Reinhardt

0

Als ich bei einem großen .com-Unternehmen gearbeitet habe, haben wir dies mit unseren .net-Bereitstellungen getan.

Alle unsere Quellcodes und gespeicherten Prozeduren wurden in SVN gespeichert. Jede Nacht wird ein Datenbankjob ausgeführt, die in der Produktion gespeicherten Prozesse werden abgerufen und in ein Verzeichnis auf SVN verschoben, sodass die Quellcodeverwaltung immer die aktuellste Version enthält.

Am Tag der Bereitstellung für ein Projekt verwenden wir ein nAnt-Skript, um die Projekte aus SVN abzurufen, eine benutzerdefinierte Erstellung der Projekte durchzuführen und alle Abhängigkeiten abzurufen, die diese Projekte benötigen. Sobald das nAnt-Skript ausgeführt wurde, wurde es in eine selbstextrahierende Zip-Datei gepackt. Gespeicherte Prozesse, die mit dieser Bereitstellung verknüpft waren, wurden in die Quellcodeverwaltung eingecheckt und ein Excel-Spreed-Sheet mit den auszuführenden Skripten und in welcher Reihenfolge aktualisiert.

Beim Start des Bereitstellungsmenüs wurde die selbstextrahierende Zip-Datei auf den Server übertragen, auf dem sie gestartet wurde. Alle Dateien wurden in die richtigen Verzeichnisse extrahiert und der DBA führte die gespeicherten Prozesse in der Produktionsdatenbank aus.

Bei einer typischen Bereitstellung mit diesem System haben wir die Bereitstellung von fünf bis sechs Stunden auf weniger als eine Stunde oder weniger erhöht.

Viel Glück und Hoffnung, dies hilft einigen bei der Erarbeitung einer Methode zur Bereitstellung Ihrer Anwendung.


0

Es muss einen besseren Weg geben, als nur in Visual Studio zu "veröffentlichen" und dann die geänderten Dateien manuell per FTP zu übertragen.

Occams Rasiermesser ist normalerweise der bevorzugte Ansatz: Je einfacher, desto besser. FTP ist einfach mit wenig bis gar keinen Komplikationen. Einige Benutzer verwenden XCOPY, Filezilla oder WSFTP, andere verwenden möglicherweise das MS Web Deployment Tool (mit dem ich noch nicht vertraut bin), aber insgesamt gibt es eine bessere Möglichkeit, ASP.NET-Webanwendungen (und andere) bereitzustellen Apps im Allgemeinen). IMO: Wenn die Bereitstellung von Beginn der Entwicklung an berücksichtigt wird, kann die Bereitstellung in die Web-App integriert werden, was in Zukunft eine relativ schmerzfreie und reibungslose Bereitstellung ermöglicht.

Als .NET-Entwickler, der in mehreren Unternehmen an der Entwicklung von ASP.NET-Webanwendungen gearbeitet hat, die sich in Größe, Komplexität und Anzahl der Benutzer (von mehreren hundert Benutzern bis zu Zehntausenden) unterscheiden, ist die IMO-Bereitstellung häufig das "flüssigste" Thema. Einige Organisationen gehen in Bezug auf die Bürokratie zu weit, während andere überhaupt keine Probleme mit der Bereitstellung ansprechen. Nach meiner Erfahrung fallen Probleme mit der Bereitstellung in Bezug auf Schwierigkeiten / Fehler in eine oder mehrere von drei Kategorien:

  1. Die Bereitstellung wird während der Entwurfsphase eingehend ignoriert / vergessen: Die meisten Web-Apps enthalten in der Regel einen Webserver und eine Datenbank. Abgesehen von Anwendungscode, möglicherweise einigen gespeicherten Prozeduren und Datenbanktabellen, erfordert die Bereitstellung nicht viel Nachdenken. ASP.NET ist mehr als fähig , bei der Bereitstellung von Unterstützung , aber die meisten Entwickler oft in Bezug abgelenkt werden , um die tatsächliche Anwendung immer laufen und dabei die es Aufgabe während verlassen , wie der Einsatz als separates Thema.

  2. Die Bereitstellung ist systemübergreifend und spielerisch komplex: Komplexität ist eine Hündin. Von MSMQ, gespeicherten T-SQL-Prozeduren und -Triggern, Reporting Services, SOAP / XML-Messaging, AD-Authentifizierung, SSAS / SSIS usw. usw. erhöht die Anzahl der verwendeten Technologien die Anzahl der beteiligten Personen. Am schlimmsten ist jedoch, dass all diese verschiedenen Komponenten normalerweise von verschiedenen Entitäten innerhalb einer Organisation verwaltet werden. Wenn nicht alle miteinander synchronisiert sind, kann die Komplexität von Bereitstellungen schnell zunehmen und zu mehreren Fehlerquellen führen.

  3. Faulheit, Apathie oder mangelnde Kommunikation und / oder Verwaltung: Von wenig bis gar keiner Dokumentation bis hin zu mangelnder koordinierter Kommunikation und Protokollierung ist es einfach, einen relativ einfachen Prozess zu vermasseln. Die Bereitstellung sollte ein einfaches Verfahren sein, bei dem zahlreiche Überprüfungen durchgeführt werden, während dokumentiert wird, was getan wurde. Oft ist dies jedoch nie der Fall. Die meisten Leute wollen nur, dass die verdammte Seite in Betrieb ist. Nach meiner Erfahrung kümmern sich Leute (Nicht-Programmierer) nicht wirklich darum, bis etwas wirklich fubar wird. Die Verantwortung liegt selten bei nur einer Person, um die Bereitstellung tatsächlich durchzuführen, da niemand wirklich der Grund für das Scheitern sein möchte, sodass die Verantwortlichkeit normalerweise verstreut ist.

Es gibt so viele fummelige Dateiausnahmen, dass ich den Prozess lieber so weit wie möglich automatisieren möchte, um versehentliche Uploads zu verhindern. Wie macht Ihr Team das?

Ich kenne keine Anbieter, die die Bereitstellung automatisieren könnten, obwohl ich mich nicht wundern würde, wenn es einige gäbe. Sie könnten wahrscheinlich eine Lösung über VBScript / WMI oder ein Batch-Skript erstellen, aber in Wirklichkeit müssen Sie eine Lösung für komplexere ASP.NET-Sites zusammenstellen. Bei einfachen Websites, die aus Seiten, Datenbankkonnektivität und nichts anderem bestehen, müssen Sie nicht annähernd so viel tun, um Ihre Bereitstellungsbemühungen an die Komplexität der Anwendung selbst anzupassen.

Bisher erfolgt die Bereitstellung bei meiner aktuellen Arbeit noch über FTP und das Verschieben einer Reihe von Dateien. Es ist hässlich, leicht zu vermasseln und es gibt keinen Sinn für eine genaue Geschichte. Zugegeben, Sie könnten FTP-Protokolle durchkämmen, niemand stört sich wirklich daran. Unsere Apps sind ziemlich einfach, ohne dass über FTP hinaus viel benötigt wird. Wie mein Team unsere Web-Apps bereitstellt, ist für Sie von geringem bis gar keinem Nutzen. Stattdessen möchte ich diese Gelegenheit lieber nutzen, um bessere Praktiken vorzuschlagen .

  • Nimm nichts an. Benutzerkonten, R / W / X Privilegien, ACLs, Firewalls, Timing (wenn zu implementieren und wie viel Zeit Sie haben , es zu tun), und , wenn möglich, Testbereitstellung für alle Umgebungen vor dem letzten „Starttermin“.
  • Bevor die Entwicklung tatsächlich beginnt, sollten Sie die Bereitstellung in die Entwicklung einbeziehen. Wenn es eine einfache Seite ist, soll es so sein. Wenn es zahlreiche bewegliche Teile gibt, berücksichtigen Sie alles und erstellen Sie einen Plan, in dem sich alle Komponenten (Code, Datenbank, Berichte, Warteschlangen usw.) auf demselben Plan befinden.
  • Koordinieren Sie mit anderen Paritäten und kommunizieren Sie effektiv und effizient.
  • Dokumentieren Sie so viele relevante Informationen wie möglich.
  • Umgebung: ein Webserver vs. Webfarm; 32-Bit vs. 64-Bit; Finden Sie einen Weg, um Protokolle / Fehler / Rotationen usw. zu überwachen.
  • Suchen (oder Erstellen) von Tools, die bei der Bereitstellung helfen können.
  • Wenn möglich für eine programmierbare Bereitstellung, wählen Sie ein Paradigma und bleiben Sie dabei. Wenn Sie beispielsweise einen Datenbankserver als primäres Mittel zum Ausführen des Status, der Bereitstellung, des Zugriffs usw. einer Anwendung verwenden möchten, backen Sie ihn in die Anwendung und bleiben Sie dabei. Wenn Sie XML-Dateien (wie web.config) unbedingt lesen möchten, halten Sie sich einfach an ein konsistentes Paradigma für die Bereitstellung der Anwendung. Ein weiteres Beispiel: Einige Organisationen belassen web.config als statische Datei in jeder Umgebung, die nicht in anderen Umgebungen bereitgestellt werden sollte . Das Programm web.config von Other ist so, dass es fehlerfrei in verschiedenen Umgebungen bereitgestellt werden kann.

Mir ist klar, dass dieser Beitrag für die ursprünglich gestellte Frage möglicherweise übertrieben ist. Leider ist die Bereitstellung nicht einfach, da die Komplexität der Anwendungen variieren kann. Ich wette, dass die meisten Organisationen, die komplexe ASP.NET-Apps bereitstellen, im Laufe der Zeit bestimmte Strategien entwickelt haben, um (zumindest) zuverlässig zu arbeiten.


lol ... ich liebe es, wie du Sparsamkeit zitierst, aber dann gibst du die komplexeste Antwort. lol.
Djangofan

1
Ja, mir ist klar, dass meine Antwort sich selbst widerspricht. Ich habe gerade zahlreiche Bereitstellungen erlebt, die schief gehen, und ich bin es sehr leid. Entschuldigung für die Schimpfe!
Osij2ist


@ Matthew Evans - schön! Ich schaue gerade auf die URL. War dies eine Neuerwerbung durch Dritte oder ein eigenes Produkt?
Osij2is

Ich denke, es ist ihr eigenes Produkt. Sie haben es intern für alle ihre eigenen Bereitstellungen entwickelt und verwendet - was vielversprechend klingt. Wird auf meine eigene Bewertung aktualisieren, wenn ich dazu komme
Matt Evans
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.