Abou Chleih

{the magic lies between the brackets}

Menü Schließen

Schlagwort: C (Seite 1 von 3)

ASP.NET Core App via Apache bereitstellen #2 – Konfiguration Apache

Um eine weitere Apache Instanz zu erstellen, gibt es bereits ein Skript, welches einem einige Arbeit abnimmt.
Die grundsätzliche Idee dahinter ist jedoch einfach: Man kopiert die originale Instanz (apache2) , also Konfigurationsdateien, Binaries, etc. in einen zweiten Ordner (apache2-xxx).

Je nach System findet sich das Skript in
/usr/share/doc/apache2.2-common/examples/setup-instance <instance>
oder
/usr/share/doc/apache2/examples/setup-instance <instance>

<instance> ist hierbei der Name der Instanz, die erstellt werden soll: /usr/share/doc/apache2/examples/setup-instance netcore

Dies erstellt also die entsprechenden Verzeichnis und Dateien /etc/apache2-netcore, /etc/logrotate.d/apache2-netcore, /var/log/apache2-netcore sowie das Init-Skript für den Boot /etc/init.d/apache2-netcore.

Um die entsprechenden Links zu aktivieren, also apache2-netcore als Service verfügbar zu machen. Führen wir nun ein update-rc.d apache2-netcore defaults aus.
Dies verlinkt die executables in /etc/rcX.d/, also dem entsprechenden Runlevel für den Boot Prozess.

Nun können wir den Service mit init.d oder service starten: /etc/init.d/apache2-netcore start oder service apache2-netcore start

Nun können wir uns an die Konfiguration de Apache2 Instanz NetCore machen. Dazu navigieren wir ins Verzeichnis /etc/apache2-netcore/sites-available/ und bearbeiten das file 000-default.conf (HTTP) oder default-ssl.conf (HTTPS).

Diese Dateien haben folgenden Aufbau (in diesem Beispiel hört die ASP.NET Core Application auf localhost:5000):

<VirtualHost *:8080>
     ServerName sub.mydomain.com 
     ErrorLog ${APACHE_LOG_DIR}/errorNetCore.log 
     CustomLog ${APACHE_LOG_DIR}/accessNetCore.log combined 
     ProxyPass / http://localhost:5000/ 
     ProxyPassReverse / http://localhost:5000/ 
     ProxyPreserveHost On
</VirtualHost>

ServerName: Hört auf Aufruf von sub.mydomain.com
ErrorLog: Schreibt Error Log in entsprechendes File, (Apache bspw. PHP Fehler kommen hier rein)
CustomLog: Schreibt alle Aufrufe in File (=AccessLog Config)
ProxyPass: Forward Proxy Config, leitet alle Anfragen von http://sub.mydomain.com:8080/ an http://localhost:5000/ weiter
/ steht hier für das Top Directory, ProxyPass /sub/ http://localhost:5000/ würde bspw. http://sub.mydomain.com:8080/sub/ an http://localhost:5000/ weiterleiten
ProxyPassReverse: Reverse Proxy, leitet Response um. Schreibt alle Urls in der Rückantwort um, bspw. sollte http://localhost:5000 zu http://sub.mydomain.com:8080 umgeschrieben werden.
ProxyPreserveHost: Header bleibt erhalten

Nun speichern wir die Seite und aktivieren sie mit a2ensite sub.mydomain.com und starten die Instanz neu service apache2-netcore restart.

Anschließend starten wir die ASP.NET Core Applikation: dotnet PFADZURDLL

ASP.NET Core App via Apache bereitstellen #1 – Compiling & Vorbereitung

Mit .NET Core ist es seit einiger Zeit problemlos möglich cross-plattform Applikationen zu erstellen.
Darunter fallen auch ASP.NET Core Web-Anwendungen.
Um diese Anwendungen allerdings allgemein bereitzustellen, müssen wir diese zuerst für den allgemeinen Zugriff aus dem Internet freigeben.
Dies geschieht auf Grund der Plattformunabhängigkeit natürlich ohne Microsoft IIS. In diesem Beispiel wird ein Apache2 Webserver in der Standardkonfiguration genutzt.
Voraussetzung sind daher ein installierter Server mit funktionaler Apache2 Installation und natürlich eine ASP.NET Core Anwendung.

Was werden wir hier nun genau machen?

  • Compilen der ASP.NET Core Anwendung
  • Konfigurieren einer eigenen Apache Instanz, die als Reverse Proxy fungiert
  • Bereitstellen der Applikation

Um die ASP.NET Anwendung bereitzustellen, müssen wir diese zuerst compilen, dies mache ich bevorzugt auf meiner Entwicklungsmaschine (hier: Windows).
Wir gehen als in das Projektverzeichnis ({Solutionpath}\src\{Projectpath}) und öffnen dort eine Kommandozeile oder PowerShell.

Mit dem Befehl dotnet publish -c Release (-c = –configuration) starten wir nun den Build Prozess (im Release Modus).
Sollten nun Fehler kommen, dass „bower“ nicht gefunden werden kann, so kann dies an zwei Dingen liegen.

  • Bower nicht installiert
  • Path-Variable nicht korrekt

Um Bower zu installieren, geben wir in der PowerShell einfach npm install bower ein, das entsprechende Node.js Projekt wird dann geladen und installiert.
Anschließend installieren wir noch Gulp via npm install gulp, eine weitere Abhängigkeit.

Sollte der Fehler immer noch erscheinen, so müssen wir die Path-Variable auf das Web Verzeichnis unserer Visual Studio Installation verweisen lassen:
PowerShell: $env:path = $env:path + ";C:\Program Files (x86)\Microsoft Visual Studio 14.0\Web\External"
Die VS Version entsprechend anpassen (hier: VS 2015).

Nun sollte das Projekt compilen und die lauffähige Version unter {Solutionpath}\src\{Projectpath}\bin\Release zu finden sein.

Diesen Ordner jetzt auf den Linux Server laden.

Um die Applikation jetzt ausführen zu können, benötigen wir die .NET Core Runtime auf dem Server (hier: Debian).
Um diese zu installieren, laden wir uns das Archiv (tar.gz) herunter und entpacken es:
Die Befehle dazu finden sich auf der entsprechenden Microsoft-Website:

Für v1.0.3:
sudo apt-get install curl libunwind8 gettext
curl -sSL -o dotnet.tar.gz https://go.microsoft.com/fwlink/?linkid=847105
sudo mkdir -p /opt/dotnet && sudo tar zxf dotnet.tar.gz -C /opt/dotnet
sudo ln -s /opt/dotnet/dotnet /usr/local/bin

Für v2.0.0:
deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-trusty-prod trusty main" > /etc/apt/sources.list.d/dotnetdev.list
apt-get update
apt-get install dotnet-sdk-2.0.0

Anschließend sollte man das Projekt starten können, zum Testen reicht hier: dotnet {Projektname}.dll im Pfad {App}\publish\.

Observer Pattern (Beobachter-Muster) in Java und C#

Wie benachrichtige ich mehrere Clients möglichst ohne Zeitverlust und ohne das Rad neu zu erfinden?
Eine weitverbreitete Möglichkeit ist das Observer Pattern (und erweitert, das Subscriber Pattern).
Es ist push-basiert, der Beobachtete gibt also allen Beobachtern Bescheid, was eine Benachrichtigung an die Beobachter in kürzester Zeit ermöglicht.

ObserverPattern

Was wir in Java dafür brauchen sind folgende Klassen und Interfaces, welche wir im Code referenzieren. In C# gibt es keine äquivalenten Klassen, wir müssen etwas selber schreiben.
[tabs]
[tab title=“Java“]

import java.util.Observable;
import java.util.Observer;

[/tab]
[/tabs]

Erstellen wir nun die Klasse, welche später beobachtet werden soll.
In C# nutzen wir EventHandler für eine asynchrone Benachrichtigung:

[tabs]
[tab title=“Java“]

public class Beobachteter extends Observable

[/tab]
[tab title=“C#“]

public class Observable
	{
		private bool changed;
		event EventHandler notifier;
		
		public void addObserver(Observer obs)
		{
			notifier += obs.update;
		}
	
		private void notifyObservers(dynamic obj)
		{
			if (this.changed) {
				if(notifier != null)
					 notifier(obj, EventArgs.Empty);
			}
			this.changed = false;
		}
		
		public void setChanged()
		{
			this.changed = true;
		}
		
		public void doIt(){
			setChanged();
			notifyObservers(32123);
		}
		
	}

[/tab]
[/tabs]

Wir lassen unseren Beobachteten die Klasse Observable im Namespace java.util.* erben. (Siehe oben)
Dadurch bekommt die Klasse u.A. folgende Methode vererbt, welche wir im Folgenden nutzen:
[tabs]
[tab title=“Java“]

public void AddObserver(){
       Beobachteter.addObserver(Observer o);
}

[/tab]
[tab title=“C#“]

 Durch die eigene Implementierung, stehen uns die identischen Methoden zur Verfügung. 

[/tab]
[/tabs]

Wie man auf dem Bild sieht, muss man nun die Beobachter (Observer) einem Beobachtbaren (Observable) hinzufügen, im Folgenden nenne ich diesen dann Beobachteten.
Wir erstellen verschiedene Beobachter und fügen diese nun einem Objekt der Klasse Beobachteter zu, welche – der Einfachheit halber – direkt in den Beobachtern erstellt wird.
Die Beobachter implementieren das Interface von java.util.Observer.

[tabs]
[tab title=“Java“]

public class Beobachter implements Observer{
    public Beobachter(){
         Beobachteter observable = new Beobachteter();
         observable.addObserver(this); //fügt dem Beobachteten mich als Beobachter hinzu.
    }
}

[/tab]
[tab title=“C#“]

 	public class Observer
	{
		string name;
		
		public Observer()
		{
		}
		
		public Observer(string name){
			this.name = name;
		}
	
		public void update(object message, EventArgs args){
			//Console.WriteLine(this + "received: "+message+obs);
		}
		
		public override string ToString()
		{
			return "{Observer,"+this.name+"}";
		} 
	}

[/tab]
[/tabs]

Nun haben wir einen oder mehrere Beobachter und einen Beobachteten.
Wie lassen wir die Beobachter nun wissen, wenn sich etwas ändert?
Die Klasse Observable bietet hier einige passende Methoden. Ich fokussiere mich hier allerdings auf folgende zwei:

[tabs]
[tab title=“Java“]

 setChanged(); 
 notifyObservers(message);

[/tab]
[tab title=“C#“]

setChanged();  
notifyObservers(message);

[/tab]
[/tabs]

Durch das dynamic keyword können wir dem EventHandler „notifier“ jegliche Daten als Parameter durchreichen, diese Implementierung vereinfacht das Handling der Daten extrem.

setChanged() ist von Nöten, da ein Beobachter auch nur benachrichtigt wird, wenn sich auch etwas geändert hat.
In Java ist es zudem sehr praktisch, dass man jede Art von Daten in der Methode

notifyObservers();

versenden kann. Mit dieser werden die Beobachter auch benachrichtigt.

Im Java Observer wird nun die Methode

update(Observable _ob, Object message)

, welche wir durch das Interface implementierten, ausgeführt.
In C# rufen der EventHandler die Observer-Methode

 update(dynamic message, EventArgs empty) 

aus.

Im Anhang befindet sich das C# Test Projekt, als .sln Solution:
ObserverPattern

Programmiertechnisch Windows Forms-Anwendungen erstellen

In C# gibt es verschiedene Techniken, GUIs zu erzeugen:

  • winforms
  • wpf

In Windows Forms (kurz meist winforms) ist das relativ einfach, da man hier komplett in C# arbeiten muss und nicht im „Backend-Code“ (C#) und im „Frontend-Code“ (XAML), wie in WPF.

Zu Beginn müssen wir zuerst einen Frame (hier: Form), der alle Controls (Textboxen, Labels, etc.) hält, erstellen und soweit vorbereiten.
Dazu legen wir eine Klasse MyForm an, welche von Form erbt:

 public partial class MyForm:Form 

Nun müssen wir noch die Attribute, wie bspw. Größe und Art des Rahmens anpassen. Dazu greifen wir auf die Properties der Klasse zu und setzen diese:

this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; //Setzt den Rahmen auf einen nicht vergrößerbaren, schmalen Rahmen ohne Min./Max-Boxen
this.ClientSize = new Size(Breite, Höhe);
this.Name = "Meine Form"; //Setzt den Namen der Form
this.ResumeLayout(false); //Unterdrückt Änderungen an der GUI
this.PerformLayout(); //Lässt Änderungen an der GUI zu und lädt diese 

Nun erstellen wir ein Objekt dieser Form:

 MyForm myFrmObj = new MyForm(); 

Um jetzt Controls (hier werden wir eine Textbox hinzufügen) zur Form hinzuzufügen, müssen wir ein Objekt dieses Controls erstellen:

 TextBox txtContent = new TextBox(); 

Anschließend greifen wir wieder auf die Attribute zu und ändern diese zu unseren Wünschen ab.

 txtContent.Size = new Size(Width, Height);
txtContent.Location = new Point(X,Y); 

Achtung die Position (Location) ist relativ, d.h. X = 0, Y = 0 sind im linken oberen Eck der Form, nicht des Bildschirms.

Nun fügen wir das Control zu unserer Form hinzu:

myFrmObj.Controls.Add(txtContent);

Natürlich kann man auch andere Attribute setzen, hier verweise ich auf das MSDN von Microsoft, in dem die Attribute von Klassen erklärt sind.
Aber auch IntelliSense hilft hier weiter.

Was jetzt noch wichtig ist, ist die Option

txtContent.AutoSize = true;

. Diese lässt Controls automatisch abhängig vom Content wachsen.

Um nun noch Events hinzuzufügen, erstellen wir die entsprechende Methode private void myMethod(object sender, EventArgs e) und fügen den Handler diesem Event zu:

this.txtContent.Click += new System.EventHandler(this.myMethod);

Zu guter letzt muss man die Controls beim Aufruf der Form initialisieren lassen, sodass man Zugriff während der Laufzeit bekommt.
Hierzu fügt man im Konstruktor der Form den Befehl InitializeComponent(); ein:

public MyForm()
{
     InitializeComponent();
}

Mehr Informationen zum Handlern und Events findet man im MSDN.

Generelle Infos findet man auf der Supportseite von Microsoft.

Release des Valve Server Tools für Windows Phone 8

Gestern war es soweit, das Valve Server Tool ging im Windows Phone Store online und kann nun auf Windows Phone 8.1 Geräten installiert werden.

„Das Valve Server Tool ist eine App zur Abfrage von Server-Daten der HLDS (Half-Life-Dedicated Servers) und SRCDS (Source Dedicated Servers), bspw. Counter-Strike:Source Servern für Game-Server Admins.
Welche Map läuft gerade auf dem Server und wie viele Spieler befinden sich auf diesem? Welche Regeln sind für diesen gerade aktiv?

Features:
* Klassische Server Information über das Valve Query Protokoll (A2S_INFO)
* Informationen über die aktuellen Spieler auf dem Server (A2S_PLAYER)
* Informationen über die, auf dem Server gültigen Regeln (A2S_RULES)

App-Sprache: Englisch“

Zur Projektseite geht’s hier entlang.

Update:
– Fixed connection issues to servers

Screenshots:
Serverdata_wvga PlayerStats_wvga Mainmenu_wvga Rules_wvga

[C#/.NET] Eigene Erweiterungen für den Windows Explorer mit SharpShell erstellen

In meinem letzten Beitrag habe ich beschrieben, wie man mit Hilfe einer Microsoft Library eigene Dateiattribute hinzufügen kann.
Auf Grund der Tatsache, dass der Windows Explorer nur die Standardattribute anzeigt (siehe Grafik), müssen wir zur Anzeige der eigenen Attribute entweder

  • ein eigenes Programm entwickeln (Handhabe umständlich)
    oder
  • eine Erweiterung für den Windows Explorer erstellen.

Standardattribute:
Standardattribute_Details

Und um letzteren Punkt handelt dieser Beitrag.

Achtung: Die Library verwendet .NET Framework 4, d.h. eine Erstellung ist nur mit dieser .NET Version möglich und einer IDE, welche diese unterstüzt (VS2010 und höher)

Um zu beginnen, benötigen wir die Library, mit welcher eine Extension erstellt werden kann. Diese findet ihr entweder auf unserer Downloadseite (SharpShell Project) oder auf der Projektpage.

Wir erstellen nun ein neues Projekt vom Typ „Windows Forms-Steuerelementenbibliothek“ (man kann auch einfach eine Klassenbibliothek erstellen) und fügen eine Referenz auf die DLL ein.

Rechtsklick auf das Projekt -> Verweis hinzufügen… ->Durchsuchen -> Durchsuchen -> Datei auswählen.

Nun können wir mit dem eigentlichen Coden beginnen.
SharpShell bietet einige Extensions an, unter Anderem sogenannte Shell Property Sheets/Pages (Erweiterung der Eigenschaftsseite einer Datei/eines Ordners), auf die wir hier näher eingehen.

Zuerst beginnen wir mit dem Sheet, welches alle Pages hält.
Wir erstellen also eine Klasse (ich nenne sie hier einfach mal Sheet) und lassen sie von der abstrakten SharpPropertySheet-Klasse erben. Diese Klasse hält alle nötigen Funktion, welche noch ausgecodet werden müssen.
Die Methoden sind die folgenden:

protected abstract bool CanShowSheet();
protected abstract IEnumerable CreatePages();

Erstere Methode gibt an, ob die Seite angezeigt werden soll.
Letztere gibt die Pages zurück, welche angezeigt werden sollen.

protected override bool CanShowSheet()
{
            return SelectedItemPaths.Count() == 1; //Sobald mindestens eine Datei angewählt, soll die Seite angezeigt werden
}

protected override IEnumerable CreatePages()
{
            CustomPage page = new CustomPage(); //Erstelle eine Page oder mehrere
            return new[] { page }; //und schreibe sie in das Array, welches zurückgegeben wird.
} 

Nun existiert die Klasse CustomPage noch nicht, wir müssen sie erst erstellen.
Da wir ein „Windows Forms-Steuerelementenbibliothek“-Projekt erstellt haben, haben wir schon eine von der IDE vordefinierte Klasse.
Diese nutzen wir nun und benennen wir in „CustomPage“.
Anschließend lassen wir sie von der SharpPropertyPage-Klasse im Namespace „SharpShell.SharpPropertySheet erben.
In den Konstruktor der Klasse schreiben wir einfach mal den Page-Titel:

public CustomPage()
{
     InitializeComponent();
     PageTitle = "Custom Properties";      //Definiert den Page-Titel
}

Diese Klasse hat einige virtual Methoden, wovon wir eine zwingend benötigen:

 public virtual void OnPageInitialised(SharpPropertySheet parent);

Diese Funktion wird aufgerufen, sobald die Seite initialisiert wurde, also ähnlich der Funktion

Form.Load();

Hier bauen wir unsere Logik ein, bspw. können wir hier eine MessageBox aufrufen, welche den Pfad der markierten Datei zurückgibt, bzw. den Pfad der ersten markierten Datei.

    MessageBox.Show(parent.SelectedItemPaths.First().ToString()); 

Oder wir können die CustomProperties, welche wir gesetzt haben auslesen.
Dazu einfach die DSO-Library einbinden und die CustomProperties auslesen.
Ich habe dazu eine ListView eingebettet und fülle diese mit dem Key Bezeichner und dem Wert des Properties:

 public override void OnPageInitialised(SharpPropertySheet parent)
        {
            filePath = parent.SelectedItemPaths.First(); //Pfad der Datei speichern
            OleDocumentProperties myFile = new DSOFile.OleDocumentProperties();
            myFile.Open(@filePath, false, DSOFile.dsoFileOpenOptions.dsoOptionDefault);
            int ctr = 1;
            foreach (DSOFile.CustomProperty property in myFile.CustomProperties)
            {
                ListViewItem key = new ListViewItem(property.Name);
                key.SubItems.Add(property.get_Value());
                lstVw_keys.Items.Add(key);
                ctr++;
            }
            myFile.Close(true);
        } 

Voila, schon ist man eigentlich fertig.
Nun müssen wir allerdings noch ein paar Parameter definieren.
Wir gehen zurück in die Sheet-Klasse und definieren einmal, wie die Clients mit dem verwalteten Code umgehen:

     [ComVisible(true)] 

Nun müssen wir noch definieren, welche Dateien überhaupt betroffen sind:

 [COMServerAssociation(AssociationType.ClassOfExtension,".txt",".css",".js")] 

In diesem Fall also Dateien mit den Endungen .txt, .css und .js.

Jetzt können wir die DLL compilen und schließlich per regAsm einbinden (sehr kompliziert und nervenaufreibend).
Alternativ kann man auch den ServerManager, welcher Teil der SharpShell-Tools ist, benutzen.
Ich zitiere hier jetzt einfach mal meinen Stackoverflow-Beitrag:

I had the same problem while using regasm.exe.
Furthermore there are many things to mention when registering an assembly through regasm.
For example you have to use the x64/x86 version of the regasm.exe, depending on your system.

x64: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regAsm.exe
x86: C:\Windows\Microsoft.NET\Framework\v4.0.30319\regAsm.exe
After having so many problems, I switched to the ServerManager.exe, which is part of the SharpShell Tools. It can be downloaded on the project page.
The usage is quite easy:

  • Load the DLL with „Load server…“
  • Click on „Install Server (xYZ)“
  • And after that on „Register Server (xYZ)“

Restart the Windows Explorer and you should be done (not necessarily needed).

Das Ergebnis sieht in etwa so aus:

CustomPropertiesTab_Pic

Nun seid ihr fertig und könnt eure CustomProperties beliebig hinzufügen, löschen und anzeigen lassen.

Ein Beispielprojekt findet ihr hier: CustomPropertyTab

[C#] Auslesen einer Excel Datei #1 – Interop-Assembly

Um Daten aus einer Excel-Datei in das Programm zu laden, gibt es mehrere Wege:

  • Zugriff auf die Excel-Datei über die Interop-Schnittstelle
  • Zugriff auf die Excel-Datei über einen Datenbank-Provider (hier: OLEDB)

Beginnen wir mit dem ersten genannten Weg, dem Zugriff über die Interop-Assembly.
Um einen Zugriff zu erhalten, müssen wir zuerst die Assembly einbinden, dies tun wir, indem wir einen Verweis auf die DLL hinzufügen.
Dazu klicken wir mit der rechten Maustaste auf das Item „Verweise“ im gewünschten Projekt und betätigen das Feld „Verweis hinzufügen…“.
Verweis_hinzufügen

Anschließend öffnet sich Dialog, indem wir einige DLLs finden.
Wir benötigen die Microsoft.Office.Interop.Excel-DLL, welche im Reiter .NET zu finden ist.

Interop_Excel_Verweis
Anschließend binden wir den Namespace der DLL in das Projekt (die gewünschte Klasse) ein.

 using Microsoft.Office.Interop.Excel; 

Nun zum eigentlichen Auslesen.
Zuerst müssen wir die verschiedenen Variablen anlegen, die Excel benötigt:

  • Die Excel-Applikation
  • Das Workbook
  • Das Worksheet
ApplicationClass app = new ApplicationClass(); //Die Excel-Applikation
Workbook book = null; //Das Workbook
Worksheet sheet = null; //Das Worksheet

Nun weisen wir die Werte zu:

 book = app.Workbooks.Open(path, Missing.Value, Missing.Value,
                                         Missing.Value, Missing.Value, Missing.Value, Missing.Value,
                                         Missing.Value, Missing.Value, Missing.Value, Missing.Value,
                                         Missing.Value, Missing.Value, Missing.Value, Missing.Value);

Dies lässt Excel das Workbook öffnen.
Falls dies im Hintergrund geschehen soll (Excel soll nicht sichtbar laufen), müssen folgende Optionen gesetzt sein:

 app.Visible = false;
app.ScreenUpdating = false;
app.DisplayAlerts = false; 

Nun da wir das komplette Excel-File geöffnet haben, wollen wir die Dateien der verschiedenen Worksheets (zu Deutsch: Tabellenblätter) auslesen.
Dazu weisen wir dem Objekt vom Typ Worksheet das Worksheet aus dem Excel-File zu:

 sheet = (Worksheet)book.Worksheets[1]; 

Es ist zu beachten, dass hier das erste Worksheet auch den Index 1 hat. (Kein zero-based-indexing!)
Jetzt lesen wir das Worksheet aus. Dazu muss man angeben, ab welcher Zelle und bis zu welcher Zelle man auslesen will, man muss also einen Bereich (eine Range) angeben.
Für dies existiert die Klasse Range.
Nun weisen wir der Range den gesamten Bereich zu, in dem Werte stehen.
Dazu erstellen wir ein char-Array bzw. einen string (ein String ist ein char-Array):

 string alphabet= "ABCDEFGHIJKLMNOPQRSTUVQXYZ"; 

Nun lesen wir aus, wie viele Spalten es gibt:

 int colCount = sheet.UsedRange.Columns.Count; 

Den Buchstaben der letzten Spalte bekommen wir nun ganz einfach durch Nutzen des Index (colCount):

 char lastColChar = alphabet[iColumnCount]; 

Um die letzte genutzte Spalte zu finden nutzen wir:

int rowCount = sheet.UsedRange.Rows.Count; 

Die Range definieren wir dann wie folgt:

 Range range = sheet.get_Range("A1", lastColChar.toString() + rowCount.toString()); 

Der erste Parameter definiert die obere, rechte Zelle, der zweite die untere, linke.
Nun haben wir den Bereich definiert.
Das Auslesen ist nun sehr simpel:
Da wir alle benötigten Daten haben, können wir ein Array erstellen und das Array schnell füllen:

 object[,] myExcelFileValues = (object[,])range.Value2; 

Nun haben wir alle Zellen im Speicher und können Excel beenden (!!!), dies ist wichtig, da die Datei sonst nicht freigegeben wird.
Dies geschieht nach dem First-In-Last-Out-Prinzip.
Zuerst löschen wir also das Range-Objekt:

 range = null; 

Nun löschen wir das Worksheet und rufen den GarbageCollector auf:

Marshal.FinalReleaseComObject(sheet);
app.DisplayAlerts = false;
sheet = null; 
GC.Collect();
GC.WaitForPendingFinalizers(); 

Anschließend lassen wir das Workbook schließen und löschen das Workbook-Objekt:

  book.Close(false, Missing.Value, Missing.Value); 
 Marshal.FinalReleaseComObject(book);
 book = null;

Daraufhin schließen wir Excel/die Applikation und löschen diese aus dem Speicher:

 app.Quit();
Marshal.FinalReleaseComObject(app);
app = null; 

Nun ist das Programm beendet.

[C#/.NET] – Applikation mit Administrator-Rechten ausführen

Wie starte ich meine C#-Applikation Administrator-Rechten?
Eine Möglichkeit (und das ist sicher eine der einfachsten) ist es eine Manifest-Datei hinzuzufügen, in der die Berechtigungen und andere Dinge definiert werden.
Hier ein Zitat aus dem MSDN:

[…] An assembly manifest contains all the metadata needed to specify the assembly’s version requirements and security identity […]

Erstellen wir nun die Manifest-Datei.
Dazu gehen wir auf unser Projekt mit einem Rechtsklick, dann auf „Hinzufügen“, „Komponente“.

Add_Manifest_projectManifest_project

Nun wählen wir das Element „Anwendungsmanifestdatei“ aus. Die Bezeichnung/den Namen lassen wir auf „app.manifest“.
Sollte die Datei nun erstellt worden sein, enthält sie einige vordefinierte Zeilen.
Suchen wir nach der Zeile:

<requestedExecutionLevel level="asInvoker" uiAccess="false" />

Das level ändern wir nun in requireAdministrator:

<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

Das sollte nun ungefähr so aussehen: Admin_Application

Und voíla, ihr habt Adminrechte (Natürlich erst nachdem ihr die UAC-Abfrage bestätigt).

Kleine Bemerkung: Eure Programmierumgebung (bei mir Visual Studio) muss auch mit Adminrechten gestartet werden. Nur so kann der Debugger mitlaufen.

[C#/.NET] – Liste in mehrere Listen splitten/gruppieren

Mein Problem war es zu Beginn eines früheren Projektes eine List<T> (in meinem Fall List<Reporter>) in mehrere Unterlisten zu sortieren.
Meine Klasse sah grob so aus:

     class Reporter
    {
        public string name;
        public string birthYear;

        public Reporter(string birthYear, string name)
        {
            this.name = name;
            this.birthYear = birthYear;
        }
    }

Meine Liste bestand aus mehreren Reportern und sah so aus:

Birthyear Name

  • 1991 Jon
  • 1992 Dominic
  • 1993 Jack
  • 1994 Hillary
  • 1991 Jackson
  • 1994 Jaqueline

Nun wollte ich die Liste in mehrere Listen splitten und zwar je nach Geburtsjahr:

Birthyear Name


1991 Jon

1991 Jackson


1993 Jack


1992 Dominic


1994 Hillary

1994 Jaqueline


Das Ergebnis erreichte ich relativ einfach mit einem Einzeiler:
Zuerst gruppierte ich die Liste mit einer Lambda-Expression nach dem Geburtsjahr:

 var groups = reporterList.GroupBy(x => x.birthYear); 

Danach wählte ich jede Gruppe aus (Lambda) und konvertierte jedes Element in eine Liste:

 var groups = groups.Select(grp => grp.ToList()); 

Und schlussendlich fügte ich alle Gruppen in eine Liste zusammen:

 var groups = groups.ToList(); 

Ein Einzeiler, der all das macht, ist einfach eine Aneinanderreihung dieser Befehle:

 var groups = reporterList.GroupBy(x => x.birthYear).Select(grp => grp.ToList()).ToList(); 

Und voíla hat man eine Liste aller Gruppen.

© 2020 Abou Chleih. Alle Rechte vorbehalten.

Thema von Anders Norén.