Laden...

Forenbeiträge von Taipi88 Ingesamt 1.029 Beiträge

07.07.2017 - 18:15 Uhr

Hi,

du hast doch jetzt selbst schon aufgeschrieben wie du dran kommst 😕

e.Data.<DeinPropertyDassDuImplementierenMusst>

Oder was meinst du?

LG

07.07.2017 - 12:06 Uhr

Hi,

habe noch einige Anmerkungen:

  1. Die Klasse "DataAddedEventArgs" bitte so lassen wie ich sie hatte - das Ding war generisch programmiert und kann auch so mit einem Dataset belegt werden. Google einfach mal "C# Generics" (das geht auch in VS 2012 schon)

  2. Du willst mit Sicherkeit kein komplettes DataSet übertragen - sondern maximal eine DataRow die man einfach hinzufügen kann (würde im Form 2 sogar eine Datenklasse - und nicht eine DataRow verwenden - die DataRow kannst du ja im Event von Form 1 erstellen und hinzufügen)

So implementiert würde sich dir auch erschließen was im AddButton.Click-Ereignis passieren soll - hier sollst du nämlich:
a) Die Daten aus den Textboxen in die Datenklasse packen
b) Das Ereignis mit der Datenklasse auslösen

LG

07.07.2017 - 09:06 Uhr

Hi,

anstatt es zu löschen hättest du es lieber posten sollen - so bekommst du nur wieder ein Beispiel wie das funktioniert 😉

Grundsätzlich:
Bitte schau dir DataBinding an - was du dort machst wird nichts als Durcheinander.

Dein Beispiel (jeweils ohne Designer-Code):

  1. Form1

public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();

			var form2 = new Form2();

			// an das ereignis von form 2 dranhängen
			form2.DataAdded += (sender, args) =>
			{
				// wenns ausgelöst wird - irgendwas mit den daten machen
				MessageBox.Show(args.Data.Value1);
			};

			// open Form2 on button-click
			openForm2button.Click += (sender, args) => { form2.Show(); };
		}
	}

  1. Form2:

public partial class Form2 : Form
	{
		public event EventHandler<DataAddedEventArgs<MyDataClass>> DataAdded;
		
		public Form2()
		{
			InitializeComponent();
			addButton.Click += (sender, args) =>
			{
				// daten zusammenstellen
				var data = new MyDataClass
				{
					Value1 = textBox1.Text,
					Value2 = textBox2.Text
				};

				// ereignis auslösen
				OnDataAdded(data);
			};
		}

		// mit dieser methode wird das event ausgelöst
		protected void OnDataAdded(MyDataClass data)
		{
			DataAdded?.Invoke(this, new DataAddedEventArgs<MyDataClass>(data));
		}
	}

  1. Klassen für Event und Daten

// die klasse, die die daten hält
	public class MyDataClass
	{
		public string Value1 { get; set; }
		public string Value2 { get; set; }
	}

	// Klasse, welche über das event "geschickt" wird
	public class DataAddedEventArgs<T> : EventArgs
	{
		public DataAddedEventArgs(T data)
		{
			Data = data;
		}

		public T Data { get; }
	}

LG

06.07.2017 - 15:05 Uhr

Hi,

was mit der von mir verlinkten Software allerdings gehen sollte wäre den Bildschirmschoner auszuschalten - was dir widerum ermöglichen würde einen Hilfe-Text anzuzeigen.

LG

27.06.2017 - 15:19 Uhr

@Gerry:
Nein - dein AssemblyLoader soll von MarshalByRefObject erben - der eigentliche Typ muss das nicht.

Könnte dann z.B. so aussehen:


class Program
	{
		static void Main(string[] args)
		{
			for (var i = 0; i < 10; i++)
			{
				var domain = AppDomain.CreateDomain("my-temp-domain", new Evidence(), AppDomain.CurrentDomain.BaseDirectory,
					AppDomain.CurrentDomain.RelativeSearchPath, false);

				var loader = (SimpleAssemblyLoader) domain.CreateInstanceAndUnwrap(typeof(SimpleAssemblyLoader).Assembly.FullName,
					typeof(SimpleAssemblyLoader).FullName);
				var assembly = loader.Load(path: @"C:\dev\BitBucket\Trash\Trash\ConsoleApp3\bin\Debug\ClassLibrary2.dll");
				var type = assembly.GetType(name: "ClassLibrary2.Test");
				var instance = Activator.CreateInstance(type);
				var methodInfo = type.GetMethod("TestMethod");
				var result = methodInfo.Invoke(instance, null);

				AppDomain.Unload(domain);
			}
		}
	}

	public class SimpleAssemblyLoader : MarshalByRefObject
	{
		public Assembly Load(string path)
		{
			ValidatePath(path);

			return Assembly.LoadFile(path);
		}

		private void ValidatePath(string path)
		{
			if (path == null) throw new ArgumentNullException(nameof(path));
			if (!System.IO.File.Exists(path))
				throw new ArgumentException($"path \"{path}\" does not exist");
		}
	}


namespace ClassLibrary2
{
    public class Test
    {
	    public string TestMethod()
	    {
		    return $"{GetType().FullName}";
	    }
    }
}

27.06.2017 - 12:02 Uhr

Hi,

nun - eine Assembly die geladen wurde kann man meines Wissens nicht mehr entladen - die einzige Variante ist die AppDomain komplett zu entladen.

Hier kannst du nachschauen wie das geht: https://stackoverflow.com/questions/4887847/hot-unload-reload-of-a-dll-used-by-an-application

LG

Edit: Meint - für diese Assembly eine eigene AppDomain erstellen - und diese dann eben ggf. entladen. (sofern das hinsichtlich der Performance ok ist)

27.06.2017 - 11:43 Uhr

Hi,

mal naiv gedacht - wie wäre, wenn du im MouseMove:
a) einen Timer startest bzw. zurücksetzt und neu startest
b) die Koordinaten in einer Variablen zwischenspeicherst

Wenn der Timer dann abgelaufen ist - dann wird halt eben erst der Tooltip angezeigt.

LG

27.06.2017 - 06:59 Uhr

Hi,

da man ja nicht alles selbst machen muss - willst du eventuell mal folgende Komponente testen?: A Zoomable and Scrollable PictureBox

Erfüllt ja scheinbar all deine Anforderungen.

Was das Zeichnen angeht - wenn das Ganze nur 1-2 Sekunden dauert und auch nicht übermäßig riesig im Arbeitsspeicher wird - würde ich es an deiner Stelle so lassen. Nur weil das Bitmap so groß ist heißt das ja nicht, dass die PictureBox auch alles auf den Bildschirm malt - ähnlich wie die von mir verlinkte Komponente.

Halte 1-2 Sekunden beim Start für absolut vertretbar, solange sicher gestellt ist, dass das Bild nicht unendlich größer werden kann. Zumal danach ja quasi alles flutschen sollte.

LG

26.06.2017 - 06:49 Uhr

Hi,

ich bin nicht sicher, was ein WPF-Tab so alles kann - letztendlich werden da ja sicherlich auch Labels und Textboxen sein - grundsätzlich bevor du weiter machst solltest du dir für WPF mal
MVVM und DataBinding anschauen - dann sollte das ganz leicht von der Hand gehen.

LG

19.06.2017 - 22:03 Uhr

Hi Abt,

da haben wir aneinander vorbei geredet. Ich verwende durchaus appsettings.json und auch Umgebungsvariablen die ich über die von dir genannten Sections anspreche.

Im speziellen hab ich dafür eine Klasse die mit Hilfe einer Section die Klasse DapperServiceOptions erstellt und befüllt, welche als Properties:
a) Einen ConnectionString
b) Die IConnectionFactory
bereitstellen soll. Den ConnectionString füllen ist einfach (macht ja das Konfigurationssystem) - wie ich die ConnectionFactory per appsettings.json setzen kann ohne Reflection wie beschrieben zu verwenden ist mir nicht klar.
Hast du unter diesen Gesichtspunkten einen Tipp?

Finde das Konfigurationssystem super und weiß die Vorteile durchaus zu schätzen...

LG

19.06.2017 - 21:07 Uhr

Hi gfoidl,

danke erst mal für deine Hilfe.

Nun - zur Entwurfszeit ist es eigentlich nicht gewünscht - letztendlich soll das dazu dienen eine Anwendung zu haben, bei der man letztendlich per Konfiguration bestimmt mit welcher Datenbank man (auf Basis von Dapper) arbeiten möchte.

Das Thema ist, dass ich in einer JSON-Konfigurationsdatei letztendlich den Namen der Assembly und den Namen des Typs, den ich erstellen möchte eintrage - und dann davon eine Instanz erzeuge - und zwar im Endausbau möglichst so, dass das Projekt gar keine direkte Referenz mehr auf die Library hat.

Der Tipp mit "DependencyContext.Default.GetDefaultAssemblyNames()" war insofern gut, dass ich dort zumindest mal einen Hinweis fand, dass das Programm mal gesagt bekommen hat, dass es eine solche Abhängigkeit gab (in Form eines AssemblyName) - scheitert letztendlich beim Laden der Assembly, da der Compiler natürlich auch keine Kopie der "nicht benötigten" Assembly beigelegt hat. (Gründlich isser ja^^)

Der Typ wird in der Tat mit Assembly.GetType(<name>) erstellt, wofür man nun leider eine geladene Assembly benötigt.

@Abt
Ich verstehe nicht ganz was du hier als Nachteil siehst - im Endeffekt geht es mir darum, dass hier ein Objekt vom Typ IConnectionFactory (MssqlConnectionFactory, OracleConnectionFactory, etc.) per Option für Dapper her soll. Den Austausch der Datenbanktechnologie möchte ich letztendlich per Config-File - und nicht im Code vornehmen. Wie würdest du dieses Ziel anders angehen? Meine direkte Alternative wäre eine Art Factory die allerdings mit MagicStrings arbeiten würde und alle Anbieter kennen müsste, was ich hier für unterlegen halten würde. (Das EntityFramework arbeitet hier ja mit den Providern eigentlich komplett äquivalent wenn ich das richtig sehe...)

Was die Namespace-Aufteilung angeht - kommt sicher auf die Sichtweise an. Der Gedanke ist, dass Frameworks wie Dapper und EF Datenbanken "unter sich vereinen". Sicher - ich hätte das Dapper weglassen können - eventuell probiere ich allerdings auch noch ein anderes Framework aus - dann bin ich froh drum.
(.Data ist übrigens Schnittstellendefinition für RepositoryPattern und UnitOfWork-Pattern, Data.Dapper eine Implementierung, die keinen Wert auf Mssql und ähnliches legt bzw. sich auf Schnittstellen verlässt, die wiederum in Data.Dapper.Mssql und weiteren implementiert werden)

Mein Plan sieht jetzt so aus:
a) AssemblyLoader schreiben, der anhand von "Assembly.GetEntryAssembly().GetReferencedAssemblies()" prüft, ob eine bestimmte Assembly in den Referenzen vorhanden ist
b) Falls dem so ist - wird diese per Assembly.Load geladen, vorgehalten und zurückgegeben
c) Falls nicht, wird der AssemblyLoader (anhand weiterer Config-Einträge) bzw. einer Lookup-Liste von AssemblyNames und Dateinamen die benötigte Assembly per "AssemblyLoadContext.Default.LoadFromAssemblyPath(<pfad>) laden, diese vorhalten und zurückgeben
d) Anschließend wird per Assembly.GetType der Typ erstellt
e) Letztendlich die Instanz per Activator.CreateInstance erstellt

AssemblyLoader würde ich in diesem Fall für einen tollen Kandidaten für das Singleton-Pattern halten.

Wie seht ihr das?

LG

19.06.2017 - 16:20 Uhr

Hi gfoidl,

sry - da war ich unvollständig. Auch die Hauptassembly hat einen direkten Verweis in VS auf diese "Dapper"-Assembly.

Das Problem ist vielmehr, dass das Hauptprojekt nur über Reflection auf die Assembly zugreift, womit die Referenz eben wegoptimiert wird. (Was ich ja normal gut finde - nur eben für diese Assembly nicht^^)

Ich habe mir jetzt geholfen, indem ich die Klasse, die ich dynamisch instanziieren möchte noch einmal abgeleitet habe und damit auch einen direkten Zugriff auf die Assembly mache, womit die Referenz nicht länger wegoptimiert wird.

Die Frage ist nur die, ob man dem Compiler sagen kann, dass man eine bestimmte Referenz gerne behalten möchte...

LG

Edit:

Für den Background mal die "eigentliche" Projektstruktur:

  1. Firmenname.AuthHost (AspnetCore Projekt)
  2. Firmenname.Data (Assembly mit wichtigen Interfaces)
  3. Firmenname.Data.Dapper (Assembly mit Standardimplementierungen auf DapperBasis)
  4. Firmenname.Data.Dapper.Mssql (Erweiterung zu Data.Dapper, die nur eine Klasse enthält die ich per Reflection anspreche - aber eben nicht in Data.Dapper gehört wegen direktem Verweis auf Mssql)

Und eben Eintrag Nummer 4 ist direkt referenziert - wird aber denn vom Compiler wegoptimiert...

LG

19.06.2017 - 15:01 Uhr

Hi,

ich hab das Problem, dass ich für eine aktuelle ASP.NET Anwendung im Konfigurationsbereich Reflection einsetzen möchte.

Das ganze würde auch eigentlich funktionieren - wenn NetCore nicht verschiedene Referenzen wegoptimieren würde.

Beispiel:

Hauptassembly: AuthHost
verweist auf Dapper.Mssql

Dapper.Mssql verweist auf Dapper

Beide Verweise werden auch als Referenzen im Visual Studio angezeigt - rufe ich jedoch:


var referencedAssemblies = Assembly.GetEntryAssembly().GetRefenrencedAssemblies();

auf, taucht die Refenrenz Dapper in der Variable "referencedAssemblies" nicht auf, bzw. nur dann auf, wenn ich im Code explizit einen Typ aus der Assembly Dapper verwende, was ich allerdings nicht möchte, da ich ja im Bereich der Startkonfiguration mit Reflection arbeiten möchte.

Mein Anliegen?
Ist es möglich dem Compiler zu sagen, dass er diesen Verweis doch bitte "stehen" lassen soll? Wenn ja: Wie geht das?

LG

12.06.2017 - 16:26 Uhr

Hi,

so leid mir das tut - aber der Betreiber wünscht nicht, dass Robots auf diese Seite angesetzt werden, welchen du offenkundig gerade schreibst. (Beim ersten Post leider die Url übersehen)

Ich möchte somit hier nicht helfen - und würde es anderen ebenfalls nicht empfehlen.

LG

12.06.2017 - 15:58 Uhr

Hi,

kurzum - ich würde behaupten, dass dein Content wie der Header es auch sagt gzip-komprimiert ist.

Sicher - du könntest jetzt hingehen und schauen, wie man das dekomprimierst.

Da das .NET-Framework für WebRequest's eine nützliche Klasse bietet, die dich davon befreit "das Rad" neu zu erfinden - scshau dir doch mal bitte folgenden Link an:

How can I download HTML source in C#

LG 😉

12.06.2017 - 13:51 Uhr

Hi,

naja - um ehrlich zu sein verliere ich in deinen Ausführungen den Überblick - ein minimaler Codeschnipsel würde dir sicher selbst direkt schon weiterhelfen.

Letztendlich scheinst du dir eine Ereigniskette gebaut zu haben, die abläuft bevor deine Klasse komplett initialisiert wurde.

Und wie alles was zur Initialisierung gehört - solltest du auch entsprechende Variablen ggf. schon im Konstruktor bzw. einer Methode, die vom Konstruktor aufgerufen wird.

Die Startreihenfolge einer Windows-Form wird dir hier denke ich nicht wirklich weiterhelfen, da es dennoch nützlich ist:
Ereignisreihenfolge in Windows Forms

LG

03.05.2017 - 09:17 Uhr

Hi,

naja - wenn all deine Zellen von CommonCell erben und gleichzeitig auch das (mir unbekannte) Interface implementieren müssen, wäre es am einfachsten, wenn deine CommonCell auch das Interface "beerbt". (In einer abstrakten Klasse muss es ja nicht implementiert werden)

Dann könntest du die foreach-Schleife so lassen. Sofern das in deinem Aufbau so möglich ist, wäre das auch die beste Lösung.

So zum Beispiel:


public interface ICell
	{
		void Do();
	}

	public abstract class CommonCell : ICell
	{
		public abstract void Do();
	}

	public class MyCell1 : CommonCell {
		public override void Do()
		{
			throw new NotImplementedException();
		}
	}

	public class MyCell2 : CommonCell {
		public override void Do()
		{
			throw new NotImplementedException();
		}
	}

Wenn das nicht geht - dann wirst du die einzelnen Zellen "casten" müssen, dafür gibt es gleich mehrere Varianten:

Grundaufbau:


public interface ICell
	{
		void Do();
	}

	public abstract class CommonCell
	{
	}

	public class MyCell1 : CommonCell, ICell {
		public void Do()
		{
			// ignore
		}
	}

	public class MyCell2 : CommonCell, ICell {
		public void Do()
		{
			// ignore
		}
	}

Durchführung:


static void LoopWitCast()
		{
			// GetSampleData returns IEnumerable<CommonCell>
			// V1: Cast all of them
			foreach (var c in GetSampleData().Cast<ICell>())
			{
				c.Do();
			}

			// GetSampleData returns IEnumerable<CommonCell>
			// V2: Using as
			foreach (var c in GetSampleData())
			{
				var cell = c as ICell;
				cell?.Do();
			}

			// GetSampleData returns IEnumerable<CommonCell>
			// V3: Using direct cast
			foreach (var c in GetSampleData())
			{
				var cell = (ICell) c;
				cell.Do();
			}
		}

LG

28.04.2017 - 06:57 Uhr

Hi,

und falls es dir nur um den Startbutton geht - ASP.NET Core ist nicht auf den IIS angewiesen.
Alternativ kann man an Stelle von ASP.NET Core wenn's um ne WebApi geht auch durchaus auf Nancy setzen.

Hosten kannst du dann beide via:

  • Windows Service
  • Konsolenanwendung
  • IIS
  • und viele andere Optionen

Allerdings solang's um ne WebApi geht - und das ist sicher die austauschbarste Variante - würde ich auf einen der vorgenannten in Verbindung mit JSON setzen.

LG

27.04.2017 - 14:52 Uhr

Hi,

naja - ich würde lieber einen Webserver aufsetzen - als dass ich ein nicht gerade triviales PeerToPeer-Netz auf eigener Basis aufstelle, worauf deine Gedanken gerade hinauslaufen.

Nur so als Wink 😉

LG

26.04.2017 - 13:03 Uhr

Hi,

zum Thema Sinn des parameterlosen Konstruktors:
Der Designer braucht ihn und wird ihn verwenden. Andernfalls hast du eben keine Design-Ansicht.

Was die Einschränkungen und deine Probleme angeht:
Im Prinzip ist das genau dein Problem. Das public wie du's gemacht hast ist schon richtig - dummerweise hilft es aber nicht immer. (Und selbst wenn - musst du halt immer erst neu kompilieren, bevor er's rafft)

Mal als alternative Vorgehensweise:
Ich würde eine eigene Formableitung erstellen (ohne Hilfe des Designers - also einfach in einer normalen .cs-Datei in einer Klasse von System.Windows.Form erben und dort wichtige Methoden rein machen.

Wenn du Controls mit Vorkonfiguration benötigst - kannst du spezielle UserControls verwenden und entsprechend einstellen, so dass du weniger Arbeit hast.

Was die Behandlung von Ereignissen angeht:
Grundsätzlich ist der von dir gezeigte Weg eine Standardvariante zum Behandeln von Ereignissen. Mögliche alternative "Schreibweisen" gibt es in der Tat - aber das ist jetzt nichts spezielles.
Alternativ - wenn die Basismethode überschreibbar ist (virtual/abstract) kannst du mit "override" auch Methoden überschreiben wie üblich. Aber auch komplett c#-konform.
(und somit teils auch Methoden, die eben jene Ereignisse auslösen)

LG

25.04.2017 - 16:01 Uhr

Hi,

naja - wenn deine Form "nackt" angezeigt wir - würde ich fast vermuten, dass deine Stammmaske zwei Konstruktoren hat und du beim erben den aufrufst, der nicht "InitializeComponent" aufruft. (Eine vom Forms-Designer generierte Methode)

Unabhängig davon wird das alleine dir auch nichts helfen, da die vom Designer erstellten Controls mit "private" markiert sind im Standard. (Wirst du dann für jedes Control anpassen müssen, damit du in der erbenden Form irgendwas daran schrauben kannst)

Zu Windows Forms:
Wird derzeit immer stärker von WPF ersetzt. Wenn du eh gerade erst anfängst solltest du da vll mal drüber schauen. Ist zwar erstmal schwieriger, spart am Ende aber Arbeit und man findet am Ende im eigenen Code auch noch was.

Zum Thema Vererbung:
Ich kenne FoxPro/VFP jetzt nicht - aber mal bei reiner Vererbung ist Windows Forms da eigentlich sehr transparent, was ich auch gut finde. Designer-spezifischer Code ist durchaus auch in Windows Forms möglich.

LG

Edit:
Dein Verständnisproblem kann ich nicht nachvollziehen in puncto Konstruktoren. Was verstehst du nicht? Die Kernaussage des Threads ist nämlich im Prinzip:

"Eine Form muss eine parameterlosen Konstruktor haben, damit der Designer funktioniert."

Ergo für den Designer nicht nutzbar:


public class MyForm : Form
{
public MyForm(string value) { this.InitializeComponents();}
}

Besser für den Designer:


public class MyForm : Form
{
public MyForm() { this.InitializeComponents();}
public MyForm(string value) : this() {}
}

24.04.2017 - 10:26 Uhr

Hi,

naja - das Prinzip ist recht einfach - du hast 3 verschiedene Show-Methoden geschrieben.

Jede einzelne davon hat keinen Rückgabewert (void) - beim Aufruf möchtest du nun allerdings ein DialogResult, dass du eben nicht implementiert hast. Und dafür fehlt auch noch einiges an Arbeit deinerseits - denn du erstellst du irgendwelche Buttons, welche sicher eine Relevanz für den erwarteten Rückgabewert haben.

Zudem weicht deine MessageBox stark vom Funktionsumfang der standardmäßig vorhandenen ab... Ganz ehrlich - was möchtest du denn eigentlich haben / machen?
Ich vermute fast, dass es schon eine MessageBox gibt, die deinen Funktionsumfang abdeckt.

LG

Edit:
Faktisch müsste der Methodenkopf dann folgendermaßen aussehen:


internal static DialogResult Show(string messageText, string messageTitle, enumMessageIcon messageIcon, enumMessageButton messageButton)
        {
            ...
        }

13.04.2017 - 13:40 Uhr

Hi,

naja - der Unterschied ist im Prinzip trivial - aber wichtig. Das Thema ist:

a) Bei

double variable = double.Parse(....

verlangt die von dir geschriebene Zuweisung, dass du einen double-Wert zurückbekommst. Wenn die double.Parse-Methode das aber schlicht nicht kann - MUSS eine Exception geworfen werden, die per se nicht nötig wäre.

b) Bei

if (Double.TryParse(textBox6.Text, out Feiertage))

lässt du der TryParse-Methode eben die Möglichkeit dir ohne Exception mitzuteilen, dass das, was die Methode parsen sollte kein gültiger Wert war.

Der Unterschied?
Wenn dein Programm unter Nutzung von Variante bei einer ungültigen Eingabe nicht komplett abschmieren soll - dann ist ein try{...} catch() {} - erforderlich.
Und selbst dann werden einzig durch das Werfen der Exception Ressourcen verschwendet, da für diese i.d.R. Stacktrace, etc. geholt werden müssen.

Unter Nutzung von Variante b) fällt das eben alles weg.

LG

13.04.2017 - 09:16 Uhr

Hi,

wie auf der Projektseite erwähnt läuft Zyan auch unter Mono - setzte es selbst auf nem RaspberryPi 2 ein.

LG

10.04.2017 - 13:18 Uhr

Hi,

naja - die Frage ist jetzt nicht sonderlich detailliert - aber mir kommt da direkt Google Forms in den Sinn. Kurze Umfrage gemacht - Auswertung ist online verfügbar allerdings auch per API abrufbar.

https://www.google.de/intl/de/forms/about/

Zwar sicher nicht selbst hostbar - aber echt simpel in der Handhabung.

LG

05.04.2017 - 15:07 Uhr

Hi,

die Frage gab's hier so ähnlich schon x-fach.

Schau mal unter Taschenrechner: String mit Zahlen und Operatoren aufteilen & verarbeiten die Links durch.

LG

01.04.2017 - 15:53 Uhr

Hi,

ich fürchte da wirst du dann selbst die Registry durchsuchen müssen. Vll hilft dir folgender Thread - da steht zumindest drin, wo die Klasse SerialPort Ihre Infos her nimmt - das wirst du dann mit den Ergebnissen von Libusb abgleichen müssen - falls das so möglich ist.

Der Thread: How do I get serial Port device id?

LG

31.03.2017 - 22:04 Uhr

Hi,

was meinst du denn mit dem Portnamen?

Ist dein USB-Gerät, welches später als COM-Port auftritt?

Falls dem so ist - würde ich über SerialPort.GetPortNames gehen.

Zudem gab es auch über ähnliche Wege sogar mitzubekommen, wenn ein neuer SerialPort dazugekommen ist etc.

LG

31.03.2017 - 21:45 Uhr

Hi,

als Nachtrag - ich musste den Quellcode leider noch anpassen, damit es im Zusammenhang mit netsh funktioniert - der vorgenannte Quellcode generiert zwar ein laut Windows gültiges Zertifikat - netsh nimmt es jedoch nicht.

(Hab mich gerade stundenlang damit rumgeärgert wieso netsh mit Fehlercode 1312 die Zusammenarbeit verweigert, obwohl ich so ungefähr jeden Tipp von Google beherzigt hatte...)

Von der selben Quelle - habe ich dann noch mal angepasst:
SslHelper:


using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;

namespace FluiTec.SelfHost.HostInstaller
{
	/// <summary>	A ssl helper. </summary>
	public static class SslHelper
	{
		private const string SignatureAlgorithm = "SHA256WithRSA";

		/// <summary>	Generates a self signed certificate. </summary>
		/// <exception cref="PemException">	Thrown when a Pem error condition occurs. </exception>
		/// <param name="subjectName">  	Name of the subject. </param>
		/// <param name="issuerName">   	Name of the issuer. </param>
		/// <param name="issuerPrivKey">	The issuer priv key. </param>
		/// <param name="validTill">		The valid till Date/Time. </param>
		/// <param name="keyStrength">  	(Optional) The key strength. </param>
		/// <returns>	The self signed certificate. </returns>
		public static X509Certificate2 GenerateSelfSignedCertificate(string subjectName, string issuerName,
			AsymmetricKeyParameter issuerPrivKey, DateTime validTill, int keyStrength = 2048)
		{
			// Generating Random Numbers
			var randomGenerator = new CryptoApiRandomGenerator();
			var random = new SecureRandom(randomGenerator);

			// The Certificate Generator
			var certificateGenerator = new X509V3CertificateGenerator();

			// Serial Number
			var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);
			certificateGenerator.SetSerialNumber(serialNumber);

			// Issuer and Subject Name
			var subjectDn = new X509Name(subjectName);
			var issuerDn = new X509Name(issuerName);
			certificateGenerator.SetIssuerDN(issuerDn);
			certificateGenerator.SetSubjectDN(subjectDn);

			// Valid For
			var notBefore = DateTime.UtcNow.Date;
			var notAfter = validTill;

			certificateGenerator.SetNotBefore(notBefore);
			certificateGenerator.SetNotAfter(notAfter);

			// Subject Public Key
			var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
			var keyPairGenerator = new RsaKeyPairGenerator();
			keyPairGenerator.Init(keyGenerationParameters);
			var subjectKeyPair = keyPairGenerator.GenerateKeyPair();
			certificateGenerator.SetPublicKey(subjectKeyPair.Public);

			// selfsign certificate
			var signatureFactory = new Asn1SignatureFactory(SignatureAlgorithm, issuerPrivKey);
			var certificate = certificateGenerator.Generate(signatureFactory);

			// correcponding private key
			var info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);

			// merge into X509Certificate2
			var x509 = new X509Certificate2(certificate.GetEncoded());

			var seq = (Asn1Sequence) info.ParsePrivateKey();
			if (seq.Count != 9)
				throw new PemException("malformed sequence in RSA private key");

			var rsa = RsaPrivateKeyStructure.GetInstance(seq);
			var rsaparams = new RsaPrivateCrtKeyParameters(
				rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2,
				rsa.Coefficient);

			x509.PrivateKey = ToDotNetKey(rsaparams);

			return x509;
		}

		/// <summary>	Converts a privateKey to a dot net key. </summary>
		/// <param name="privateKey">	The private key. </param>
		/// <returns>	PrivateKey as an AsymmetricAlgorithm. </returns>
		public static AsymmetricAlgorithm ToDotNetKey(RsaPrivateCrtKeyParameters privateKey)
		{
			var cspParams = new CspParameters
			{
				KeyContainerName = Guid.NewGuid().ToString(),
				KeyNumber = (int) KeyNumber.Exchange,
				Flags = CspProviderFlags.UseMachineKeyStore
			};

			var rsaProvider = new RSACryptoServiceProvider(cspParams);
			var parameters = new RSAParameters
			{
				Modulus = privateKey.Modulus.ToByteArrayUnsigned(),
				P = privateKey.P.ToByteArrayUnsigned(),
				Q = privateKey.Q.ToByteArrayUnsigned(),
				DP = privateKey.DP.ToByteArrayUnsigned(),
				DQ = privateKey.DQ.ToByteArrayUnsigned(),
				InverseQ = privateKey.QInv.ToByteArrayUnsigned(),
				D = privateKey.Exponent.ToByteArrayUnsigned(),
				Exponent = privateKey.PublicExponent.ToByteArrayUnsigned()
			};

			rsaProvider.ImportParameters(parameters);
			return rsaProvider;
		}

		/// <summary>	Generates a ca certificate. </summary>
		/// <param name="subjectName"> 	Name of the subject. </param>
		/// <param name="caPrivateKey">	[in,out] The ca private key. </param>
		/// <param name="validTill">   	The valid till Date/Time. </param>
		/// <param name="keyStrength"> 	(Optional) The key strength. </param>
		/// <returns>	The ca certificate. </returns>
		public static X509Certificate2 GenerateCaCertificate(string subjectName, out AsymmetricKeyParameter caPrivateKey,
			DateTime validTill, int keyStrength = 2048)
		{
			// Generating Random Numbers
			var randomGenerator = new CryptoApiRandomGenerator();
			var random = new SecureRandom(randomGenerator);

			// The Certificate Generator
			var certificateGenerator = new X509V3CertificateGenerator();

			// Serial Number
			var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);
			certificateGenerator.SetSerialNumber(serialNumber);

			// Issuer and Subject Name
			var subjectDn = new X509Name(subjectName);
			var issuerDn = subjectDn;
			certificateGenerator.SetIssuerDN(issuerDn);
			certificateGenerator.SetSubjectDN(subjectDn);

			// Valid For
			var notBefore = DateTime.UtcNow.Date;
			var notAfter = validTill;

			certificateGenerator.SetNotBefore(notBefore);
			certificateGenerator.SetNotAfter(notAfter);

			// Subject Public Key
			var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
			var keyPairGenerator = new RsaKeyPairGenerator();
			keyPairGenerator.Init(keyGenerationParameters);
			var subjectKeyPair = keyPairGenerator.GenerateKeyPair();
			certificateGenerator.SetPublicKey(subjectKeyPair.Public);

			// Generating the Certificate
			var issuerKeyPair = subjectKeyPair;

			// Signature Algorithm
			ISignatureFactory signatureFactory = new Asn1SignatureFactory(SignatureAlgorithm, issuerKeyPair.Private);

			// selfsign certificate
			var certificate = certificateGenerator.Generate(signatureFactory);
			var x509 = new X509Certificate2(certificate.GetEncoded());

			caPrivateKey = issuerKeyPair.Private;

			return x509;
		}

		/// <summary>	Adds a cert to store. </summary>
		/// <param name="cert">	The cert. </param>
		/// <param name="st">  	The st. </param>
		/// <param name="sl">  	The sl. </param>
		public static void AddCertToStore(X509Certificate2 cert, StoreName st, StoreLocation sl)
		{
			var store = new X509Store(st, sl);
			store.Open(OpenFlags.ReadWrite);
			store.Add(cert);

			store.Close();
		}
	}
}

Anwendung, wenn man:
a) eine CA erzeugen will
b) ein Zertifikat auf Basis der CA erzeugen will
c) diese für "netsh" zugänglich dem Zertifikatsspeicher hinzufügen möchte


// create ca
var caCert = SslHelper.GenerateCaCertificate($"CN={CertificateSubject}-CA", out AsymmetricKeyParameter caPrivateKey, DateTime.Now.AddYears(YearsValid));

// add ca-cert to store
SslHelper.AddCertToStore(caCert, StoreName.Root, StoreLocation.LocalMachine);

// create selfsigned cert
var cert = SslHelper.GenerateSelfSignedCertificate($"CN={CertificateSubject}", $"CN={CertificateSubject}-CA", caPrivateKey, DateTime.Now.AddYears(YearsValid));

// add cert to store
var p12 = cert.Export(X509ContentType.Pfx);
SslHelper.AddCertToStore(new X509Certificate2(p12, (string)null, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet), StoreName.My, StoreLocation.LocalMachine);

// get thumbprint (used by netsh, etc.)
certHash = cert.Thumbprint?.ToLower();

31.03.2017 - 13:42 Uhr

Hi,

ich hab im Prinzip eine recht simple Frage - für ein Programm von mir wird im Rahmen des Installationsprozesses auf diversen Zielcomputern eine Art Mini-Webserver eingerichtet.
(Nancy-SelfHost via netsh.exe in Kombination mit UPNP - also das Programm registriert sich automatisch eine URL und schaltet via UPNP einen Port frei)

Jetzt möchte ich das Ganze natürlich nicht auf irgendwelchen Client-Maschinen ungesichert laufen lassen - und möchte hierzu auch direkt automatisch SSL einrichten und nutze dafür derzeit BouncyCastle um:
a) eine lokale CA zu erstellen (Wird als vertrauenswürde Stammzertifizierungsstelle gespeichert)
b) ein von dieser CA signiertes Zertifikat zu erstellen (Wird unter "Eigene Zertifikate" gespeichert)

Dieses Zertifikat binde ich dann wiederum via netsh.exe an die URL-Reservierung bzw. den entsprechenden Port.

Dieser Client wird im Endaufbau dann von einem von mir gehosteten Server (dieser dann mit ordentlichem Zertifikat) angesprochen. (Mit "eigener" Zertifikatsvalidierung, da das hier genannte Zertifikat ja selbst signiert ist)

Meine Frage ist:
Nach Tutorials setze ich zur Erstellung dieses Zertifikats:

  • 2048 Bit RSA Keys
  • SHA256
    ein und baue daraus dann ein x509-Zertifikat.

Das Signaturverfahren in BouncyCastle heißt somit "SHA256withRSA".
Ist das so sicher genug oder sollte ich hier andere Verfahren anwenden? Wenn ja - welche?
Oder gibt es gar neben der Sicherheit Einwände gegen meine Vorgehensweise?

Mal als Beispielcode der Part, der zum Erstellen des eigentlichen Zertifikats genutzt wird:


// <summary>	Generates a self signed certificate. </summary>
		/// <exception cref="PemException">	Thrown when a Pem error condition occurs. </exception>
		/// <param name="subjectName">  	Name of the subject. </param>
		/// <param name="issuerName">   	Name of the issuer. </param>
		/// <param name="issuerPrivKey">	The issuer priv key. </param>
		/// <param name="keyStrength">  	(Optional) The key strength. </param>
		/// <returns>	The self signed certificate. </returns>
		public static X509Certificate2 GenerateSelfSignedCertificate(string subjectName, string issuerName,
			AsymmetricKeyParameter issuerPrivKey, int keyStrength = 2048)
		{
			// Generating Random Numbers
			var randomGenerator = new CryptoApiRandomGenerator();
			var random = new SecureRandom(randomGenerator);

			// The Certificate Generator
			var certificateGenerator = new X509V3CertificateGenerator();

			// Serial Number
			var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);
			certificateGenerator.SetSerialNumber(serialNumber);

			// Issuer and Subject Name
			var subjectDn = new X509Name(subjectName);
			var issuerDn = new X509Name(issuerName);

			certificateGenerator.SetIssuerDN(issuerDn);
			certificateGenerator.SetSubjectDN(subjectDn);

			// Valid For
			var notBefore = DateTime.UtcNow.Date;
			var notAfter = notBefore.AddYears(2);

			certificateGenerator.SetNotBefore(notBefore);
			certificateGenerator.SetNotAfter(notAfter);

			// Subject Public Key
			var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
			var keyPairGenerator = new RsaKeyPairGenerator();
			keyPairGenerator.Init(keyGenerationParameters);
			var subjectKeyPair = keyPairGenerator.GenerateKeyPair();

			certificateGenerator.SetPublicKey(subjectKeyPair.Public);

			// Generating the Certificate
			var issuerKeyPair = subjectKeyPair;

			// signature factory
			ISignatureFactory signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, issuerPrivKey);

			// selfsign certificate
			var certificate = certificateGenerator.Generate(signatureFactory);

			// correcponding private key
			var info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);


			// merge into X509Certificate2
			var x509 = new X509Certificate2(certificate.GetEncoded());

			var seq = (Asn1Sequence) info.ParsePrivateKey();
			if (seq.Count != 9)
				throw new PemException("malformed sequence in RSA private key");

			var rsa = RsaPrivateKeyStructure.GetInstance(seq);
			var rsaparams = new RsaPrivateCrtKeyParameters(
				rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2,
				rsa.Coefficient);

			x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
			return x509;
		}

Vielen Dank im Voraus.

Liebe Grüße

31.03.2017 - 10:24 Uhr

Hi,

da hatte ich vor nicht all zu langer Zeit mal was gebastelt, was mich bisher noch nicht enttäuscht hat.

Ist bei mir innem Bootstrapper gekapselt - der Splash ist auf Basis von folgender Anleitung erstellt allerdings ein bisl angepasst.

Ursprüngliche Anleitung:
http://dontpaniclabs.com/blog/post/2013/11/14/dynamic-splash-screens-in-wpf/

Start des SplashScreens:


/// <summary>   Started den SplashScreen in einem neuen Thread. </summary>
		protected virtual void RunSplashScreen()
		{
			SplashScreenViewModel = GetSplashScreenViewModel();

			// separater thread mit STA, damit der SplashScreen die Anwendung nicht beeinflusst und umgekehrt
			var splashThread = new Thread(ShowSplashScreen);
			splashThread.SetApartmentState(ApartmentState.STA);
			splashThread.IsBackground = true;
			splashThread.Name = "Splash Screen";
			splashThread.Start();
		}

/// <summary>   Zeigt einen Splashscreen an. </summary>
		/// <remarks>
		///     Started den Thread, der den SplashScreen anzeigt
		/// </remarks>
		public override void ShowSplashScreen()
		{
			_splashScreen = new SplashScreen(SplashScreenViewModel);
			_splashScreen.Show();
			Dispatcher.Run();
		}

So sieht der SplashScreen bei mir aus:


public partial class SplashScreen
	{
		/// <summary>   Standardkonstruktor. </summary>
		public SplashScreen() : this(new SplashScreenViewModel())
		{
		}

		/// <summary>   Konstruktor. </summary>
		/// <param name="viewModel">    Das ViewModel. </param>
		public SplashScreen(ISplashScreenViewModel viewModel)
		{
			InitializeComponent();
			DataContext = viewModel;
		}

		/// <summary>   Schliesst den SplashScreen. </summary>
		public void Shutdown()
		{
			Dispatcher.InvokeShutdown();
		}
	}

Nach der Anwendungsinitialisierung kannst du dann im Endeffekt:


...
// Shell abrufen, als Hauptfenster zuweisen und anzeigen
			var shell = ServiceLocator.Current.GetInstance<Shell>();
			Application.Current.MainWindow = shell;

			// splash schliessen
			CloseSplashScreen();

			// shell anzeigen
			shell.Show();
			
			// shell in den Fordergrund holen
			shell.Activate();
			shell.Focus();
...

/// <summary>   Schliesst den Splashscreen. </summary>
		public override void CloseSplashScreen()
		{
			_splashScreen.Shutdown();
		}

Bei mir ist es halt so, dass ich meine Shell (also Hauptfenster der Anwendung) nicht per XAML öffnete - sondern quasi aus der App.xaml.cs heraus über einen Bootstrapper, der vorgenanntes ausführt. Dann muss man auch am Hauptthread nichts rumfummeln.

Wenn du dann das Hauptfenster schließt beendet sich die Anwendung wenn sonst nix gespielt wurde wie gewohnt von allein.

LG

Edit:
Die Art in der ich's mache hat halt noch den Vorteil, dass man beim Initialisieren im Hauptthread bleiben kann und sich da kein Bein abbricht. Dem Splash kann man dann über das ViewModel ggf. noch Nachrichten zum Status geben und gut ist...

15.03.2017 - 10:48 Uhr

Hi,

was läuft denn genau nicht bzw. nicht perfekt?

Grundsätzlich ist es in meinen Augen nicht die perfekte Idee erst bei Programmende in die Datei zu schreiben - wenn dein Programm nämlich abstürzt - sind die vorgehaltenen Daten nämlich schlicht und ergreifend weg.

Was dein Problem angeht sieht man jetzt leider nicht, wie du deine Schreibfunktion aufrufst - liegt allerdings je nach Exception die du nicht verrätst in der Tat an gleichzeitigen Dateizugriffen.

Kannst dich auf folgendem Thread ja mal umschauen:
Writing to file in a thread safe manner

LG

13.03.2017 - 12:33 Uhr

Hi,

naja - deine Variante des Abrufs dieser Menüs ist wohl auch noch die Alte.

Ich bin nicht sicher, was du schon hast - aber sofern du z.B. ein Addin (auf VSTO-Basis) hast - dann hilft dir dort die vorgenerierte Klasse namens "Globals" weiter - da steht z.B. Folgendes drin:


...
internal static ThisRibbonCollection Ribbons {
            get {
                if ((_ThisRibbonCollection == null)) {
                    _ThisRibbonCollection = new ThisRibbonCollection(_factory.GetRibbonFactory());
                }
                return _ThisRibbonCollection;
            }
        }
...

Bin mir relativ sicher, dass du darüber an die richtigen Infos kommen wirst.

In einer deiner Methoden würde dann nämlich Folgendes gehen:


var ribbons = Globals.Ribbons;
            foreach (var ribbon in ribbons)
            {
                
            }

Kanns leider nicht testen, da ich zu meinem einzigen VSTO-Projekt nicht mehr die passende Office-Version installiert hab - aber so sollte es gehen.

LG

13.03.2017 - 11:37 Uhr

Hi,

ich verstehe leider dein Anliegen nicht.

Kannst du das genauer erklären?

LG

09.03.2017 - 13:11 Uhr

Hi,

ohne jemals damit gearbeitet zu haben finde ich es auffällig, dass du 2 Mal BeginReceive aufrufst. Das wäre jedenfalls mein Ansatzpunkt.

LG

09.03.2017 - 09:31 Uhr

Hallo Emrichm2,

bitte benutze die Code-Tags, wie bereits schon mal erbeten.

Wenn du nicht verstehst, was dort passiert - dann muss man dich leider bitten erst einmal ein C#-Buch zu lesen - denn deine Aufgabe können wir dir nicht abnehmen - und die Anweisungen die du hier postest sind alle recht simpel und zudem noch kommentiert.

Welchen Sinn die Anweisungen haben - das musst du herausfinden.

LG

09.03.2017 - 07:59 Uhr

Hi,

naja - kommt drauf an - wenn du Einzelentwickler bist bzw. anderweitig "Rechte" auf eine Community-Lizenz von Syncfusion hast - das DateTimeEdit von denen funktioniert da sehr gut und ist auch deutlich flexibler. Bin jedenfalls sehr zufrieden damit.

Wenn das keine Option ist - gibt es einige Tutorials um sich ein eigenes zu bauen - kommst aber sicher nicht so leicht an vorgenanntes Beispiel ran...

LG

09.03.2017 - 06:37 Uhr

Hi,

welchen DateTimePicker hast du denn genommen? Den vom Extended WPF Toolkit? (Im Standard gibts nämlich keinen...)

Der im Extended WPF Toolkit scheint laut den Issues dort aktuell genau dein Problem zu haben - ergo aktuell nicht nutzbar...

LG

08.03.2017 - 12:48 Uhr

Hi,

prinzipiell bitte C#-Code auch in die Tags packen.

Das sieht nach Code von einem Control aus.

Die ersten beiden Zeilen sind Attribute, die dem Property bestimmte Eigenschaften geben, die wahrscheinlich im Designer verwendet werden.

Das was danach kommt ist ein Property, welches eine Variable/Feld names "blurArea" kapselt.
Hintergrund: Variablen und Felder sind normalerweise private und somit von außen weder sichtbar noch zugreifbar (das ist sinnvoll).

Details: Eigenschaften (C#-Programmierhandbuch)

LG

PS: Das Property geht auch heutzutage über ein AutoProperty kürzer, wenn dort sonst nichts passiert, dann kannst du einfach:


public int BlurArea { get; set; }

Das Feld blurArea brauchst du dann nicht mehr.

PPS: Was mir gerade auffällt - du arbeitest nicht zufällig mit einem ReflectionTool und nimmst fremden Code auseinander? 😕

07.03.2017 - 07:50 Uhr

Hi,

ich glaube du verrennst dich in deinen Schleifen 😕 Um das ganze bei reinen bools zu machen würde ich in etwa so vorgehen:


public class BoolReverser
{
	private readonly bool[] values;

	public BoolReverser(int count)
	{
		values = new bool[count];
		for(var i = 0; i < values.Length; i++)
			ReverseValues(i);
	}

	void ReverseValues(int indexStart)
	{
		var increment = indexStart + 1;
		for (var i = indexStart; i < values.Length; i+=increment)
			values[i] = !values[i];
	}
}

LG

03.03.2017 - 10:29 Uhr

Hi,

wenn ich mich nicht täusche wird eine Zählervariable "n" gecaptured, weshalb du diesen nicht nachvollziehbaren Fehler hast.

Das ganze nennt sich "Closure" - im Endeffekt führt das bei dir dazu, dass "n" zwar normal hochgezählt wird - die Tasks jedoch jedoch nicht den erwarteten Wert bekommen.

Mein Tipp:
Definiere mal im Loop eine Kopie von n, damit hier nichts mehr gecaptured wird.

LG

Edit: Tipp bezieht sich auf den von Palin genannten Code-Auszug.

03.03.2017 - 08:05 Uhr

Was meinst du mit in die Ressource packen? Das macht doch Visual Studio automatisch wenn du das als Icon für dein Projekt auswählst 😕

Ich baue meine Icons meist mit IcoFx (fand ich bislang sehr bequem) - wähl's im VS aus und fertig.

LG

Edit: Scheint auf Bezahlvariante gewechselt zu haben - die alte Freeware-Version gibts aber z.B. noch da: http://www.chip.de/downloads/IcoFX-letzte-Freeware-Version_28266149.html

02.03.2017 - 07:21 Uhr

Hi,

das DataGridView erlaubt via "AllowUserToAddRows" das Einfügen von Zeilen - diese Zeile ist per Default allerdings ganz unten.

Wenn du mittenrein einen neuen Eintrag machen möchtest - wirst du um etwas manuelle Arbeit nicht herum kommen.

Im Prinzip brauchst du ja nur ein ContextMenu, welches mittenrein eine neue Zeile macht...

LG

26.02.2017 - 22:02 Uhr

Hallo Abt,

ich glaub der Link von dir passt nicht - soweit war ich ja noch gar nicht - ich wollte ja erst mal soweit kommen, dass überhaupt ein Token erstellt wird...

Habe zwischenzeitlich noch eine bessere Lösung gefunden - Für alle mit dem selben Anliegen (in Hinsicht auf Alexa):

Ein eigener OAuth-Provider ist gar nicht nötig, man registriert den Skill (z.B.) bei Amazon-Login - lässt den Skill dort seinen Token abholen - der Skill schickt dann brav bei jedem Request seinen Token mit - und man selbst kann mit dem Token dann intern z.B. die Mail-Adresse abfragen um Accounts im Hintergrund zu verbinden.
Wird auf folgender Seite beschrieben:
https://developer.amazon.com/blogs/post/Tx3CX1ETRZZ2NPC/Alexa-Account-Linking-5-Steps-to-Seamlessly-Link-Your-Alexa-Skill-with-Login-wit

Im Endeffekt war es ohnehin keine gescheite Idee einen eigenen OAuth-Server aufzustellen, wenn's auch viel einfacher geht.

LG

PS:

Was ASP.NET Core 2.0 angeht - wann genau kommt das denn?

Bin von .NET Core bislang noch nicht wirklich überzeugt - was ich bislang gesehen habe waren viele Breaking Changes dabei, die schon allerhand Turorials und Beispielcode wertlos gemacht haben... Eigentlich ein Zeichen, dass man ein solches Framework noch ein bisschen wachsen lassen sollte.

LG

26.02.2017 - 17:01 Uhr

Hi,

vorab: Ich bin dabei einen eigenen Alexa-Skill schreiben - funktioniert auch super. Da das Ding später auch Andere nutzen sollen - benötige ich eine Methode auf dem Server den entsprechenden User ausfindig zu machen.

Über Amazon/Alexa ist das offenkundig über OAuth 2.0 vorgesehen, womit ich mich nun schon sehr lange rumschlage.

Grundsätzlich: Ich arbeite mit MVC5 unter .NET 4.6.1, gehostet wird das Ding auf einem IIS.

Meine nicht funktionierende Anwendung läuft folgendermaßen:
a) Hab über den AccountController eine neue Seite - extra für Alexa-Benutzer angelegt, bei der die sich anmelden und gleichzeitig einige Alexa-Parameter behalten werden. Funktioniert: User meldet sich (ggf) an, es erfolgt eine Abfrage, ob Alexa vertraut werden kann, es erfolgt ein Redirect mitsamt einem Code, den Alexa auch akzeptiert --> alles klar

Im Anschluss an vorgenannte Redirect, versucht Alexa sich mit dem von mir generierten Code einen Access- und einen Refresh-Token zu besorgen:

Erster Versuch:
via app.UseOAuthAuthorizationServer und etwas Config war nun mein erster Versuch - leider funktioniert hier gar nichts, weil diese MiddleWare scheinbar davon ausgeht, dass alle Parameter als QueryParameter verfügbar sind. Dummerweise schickt Alexa die als FormParameter.

Zweiter Versuch:
Durch viel Kleinarbeit und Kopiererei von Microsoft.Owin... hab ich nun einen SelfOAuthAuthorizationServer geschrieben, der die Parameter aus dem FormBody holt,
client_id validiert, redirect_uri validiert, code validiert (klappt alles soweit) - und schlussendlich soll eine Standardantwort erstellt werden.

Nur, dass die Standardantwort ein Redirect auf "redirect_uri" ist - ich aber theoretisch wenn ich den OAuth-Ablauf korrekt verstanden habe - eigentlich mit einer Reponse antworten müsste, die einen Access- und einen Refresh-Token bereitstellt.

Meine Fragen:
Ist das so unpraktisch? Mache ich was komplett falsch?
Falls ja: Gibt es irgendwo ein vollständiges Tutorial? Ich finde leider überall nur Brocken.
Falls nein: Jemand eine Idee, wie ich als Antwort ein gültiges paar Token ausgeben könnte?

Vielen Dank

Liebe Grüße

21.02.2017 - 07:04 Uhr

Hi,

naja - die Fehlermeldung klingt recht eindeutig im Zusammenhang mit der MSDN.
Die maximale Verschachtelungstiefe ist per Default wohl bei 32 - und du würdest damit drüber kommen, weshalb das Ding abgewürgt wird.

Du kannst jetzt zwar sicher versuchen @@NESTLEVEL anzuheben - vermuten würde ich allerdings doch eher, dass hier eine Endlosschleife gebaut wurde. Würde somit mal schauen was sich hier so oft aufruft...

Nach all den beteiligten Procedures und Triggern frag ich nicht mal - denn sobald du alle Beteiligten gefunden hast löst sich das Problem wahrscheinlich fast von allein 😉

LG

20.02.2017 - 09:33 Uhr

Hi,

wofür willst du denn bitte casten?!

Du könntest zwar so casten - aber VS sagt dir direkt schon, dass der Cast redundant ist.
(Hab Framework-Element durch "Base" ersetzt um mir den Verweis zu sparen)


var x = new X();
var y = x as ClassicMenuModuleItem<Module, Base>;

LG