kann nachvollziehen, dass es keinen Spaß macht x-beliebige Schüler zu zwingen ein MS-Konto anzulegen bzw. auch nur durch die Erstellung eines solchen zu schubsen.
On Top:
So wie ich mich an die Schule erinnere haben die Schüler auch keine Benutzerkonten auf den Rechnern - ergo - stehen die Chancen hoch, dass die Schule unwissentlich an der Verletzung von Lizenzvereinbarungen teilnimmt - schlicht weil ein Schüler eingeloggt blieb - ein anderer aber das Konto verwendet - sofern man nun Visual Studio in welcher Form auch immer nutzt.
(Würde mir als Schüler auch nicht passen, dass ich meine Benutzerdaten auf einem Gerät/Konto hinterlasse, über dass ich im Prinzip keinerlei Kontrolle habe)
Grundlegend:
SharpDevelop ist der Vorgänger von MonoDevelop - hier könnte man ggf. noch evaluieren - grundlegend liegt der Fokus hier aber auf VS Code, dass ebenfalls kein Benutzerkonto benötigt.
WebServices auf Basis von ASP.NET Core kann man damit komfortabel schreiben.
Die Microsoft-Beispiele nutzen zwar in der Tat meist Visual Studio - allerdings lässt sich das Endergebnis genauso gut mit VS Code gestalten. Sicher - hier ist in Teilen die cli beteiligt für entsprechende Vorlagen - auf der anderen Seite: "dotnet new webapi" einzugeben sollte im Informatikunterricht ja kein Problem darstellen.
Was VS im Standard vll noch anders macht: Die haben im Standard eine IIS-Express-Integration - allerdings finde ich das seit ASP.NET Core vollkommen unnötig - zum Entwickeln ist "dotnet run" bzw. "dotnet watch" viel angenehmer - mir persönlich gefällt das separate CLI-Fenster mit den Logausgaben.
naja - ein Shell-Aufruf startet im Endeffekt eine Art Kommandozeile für ein anderes Programm.
Wenn das Python-Programm einen entsprechenden CLI-Aufruf schafft - dann schafft das auch ein Shell-Aufruf.
Wenn das Ganze sich allerdings nur über die GUI anstoßen lässt - wird das mit der Shell nichts.
Um allerdings ehrlich zu sein: Das klingt nicht nach einer Aufgabe aus dem Studium - sondern eher nach einem Nebenjob mit lausiger Aufgabenstellung... Falls nicht würde ich eher erwarten, dass man dich auffordert alles in C# zu implementieren. Dann allerdings CAD in's Spiel zu bringen...
Naja - grundlegend hast du mindestens 2 Möglichkeiten soweit ich mit einer schnellen Suche fnde:
a) Einfach per Shell ausführen (halte ich nicht unbedingt für verkehrt)
b) IronPython verwende - aber normal kommt da denke ich kein import (zumindest im C# vor)
PS: Wenn man dich zwingt ein externes Script auszuführen - würde ich persönlich wenn ich keine Rückmeldung für mein Programm brauche - immer per Shell bzw. Cmd ausführen. Ist schlicht sehr simpel auf diese Art.
Alternativ musst du ja nicht mal das Konfig-System benutzen. Es genügt doch eine zentral gepflegte XML-Datei, welche per Deserialisierung ausgelesen wird - oder?
platt formuliert: Du brauchst einen WebServer, der (was auch immer du genau gemacht hast) ausführen kann - zusätzlich zur Datenbank, welche du ja offensichtlich verwendest...
Grundlegend brauchst du somit einen Server (Linux oder Windows) auf dem du Datenbank und Anwendung installieren und einrichten kannst, im Normalfall eine fixe IP sowie eine Domain.
Wie und was genau du brauchst hängt grundlegend davon ab was du so drauf hast, wie viel Geld du ausgeben kannst/möchtest - und was du eben so alles in deinem Programm verwendet hast. (Gibt hier schlicht zig Möglichkeiten zum Ziel)
Persönlich:
Für einige meiner Anwendungen betreibe ich einen gemieteten Windows-WebServer von HostEurope - dieser Server führt IIS sowie eine Instanz eines MSSQL-Servers aus. IIS wiederum ist letztendlich der Proxy-Server für verschiedene ASP.NET Core - Anwendungen, welche ggf. wieder mit der Datenbank kommunizieren.
Andere meiner Anwendungen (auch ASP.NET Core) laufen hinter NGINX (Webserver als Proxy) direkt auf einem Ubuntu-Server, noch andere Anwendungen sind hinter Traefik (Webserver als Proxy) in verschiedenen Docker-Containern.
Github oder ein FTP-Server genügen jedenfalls für sowas nicht nicht.
Wobei es in Github durchaus möglich ist via CI/CD eine Anbindung zu Azure zum Hosting in der Cloud aufzubauen. Persönlich würde ich dir allerdings vorerst davon abraten - einfach damit du siehst, wie's eigentlich funktioniert...
grundlegend: nein - die IDE ist keine Konsole und bietet soweit mir bekannt ist auch nicht die Möglichkeit eine solche inline anzuzeigen - das heißt das Fenster wird sich auf diese Art immer öffnen.
Grundlegend sind im nachfolgenden Link einige Optionen aufgezeigt: Having the output of a console application in Visual Studio instead of the console
Kurzum:
Wenn du keine Konsolenausgabe möchtest - wäre es am besten eine Windows-(Forms)-Anwendung zu erstellen und dort eben Debug.Write(Line) zu benutzen - dann öffnet sich auch kein Fenster.
Was Logging angeht:
VS selbst hat nichts mit dem Logging in deinem Programm zu tun. Hierzu gibt es allerdings diverse Frameworks - ich denke die bekanntesten sind Log4Net und Serilog. (siehe hierzu jeweils github und nuget)
Was git angeht - git ist weder an Java noch .NET (noch eine bestimmte IDE gebunden) - verwendbar ist es demnach definitiv. VS bietet hierzu teils auch integrierte Funktionen. Ich selbst arbeite meist allerdings lieber mit SourceTree.
ohne deinen Code zu kennen kann man dir nicht wirklich helfen.
Unabhängig davon:
Wenn man die Seite liest bekommt man mit dem folgenden Link eine lauffähige Anwendung, welche das deinerseits geschilderte Problem nicht hat. siehe: https://github.com/ourcodeworld/csharp-scanner-wia
Der dort verwendete Code sieht prinzipiell recht übersichtlich aus wenn du mich fragst.
Kann somit nur empfehlen, dass du das mit deinem Code vergleichst...
Das Semikolon sorgt dafür, dass folgendes ausgeführt wird, wenn "True": Nichts.
Und darauf folgt, dass jede (numerische) Eingabe die Schleife beendet.
Urgh - hast Recht - hatte das Semikolon bei meinem ersten Test direkt gestrichen, weil's nicht hingehört und beim zweiten Test direkt eine höhere Zahl eingegeben. (Hab so nen Fehler noch nie gesehen)
grundlegend hilft es (wenn du Hilfe haben möchtest), wenn du beschreibst welches Problem du überhaupt hast.
Direkt offensichtlich:
Da ist ein Semikolon, welches dort nicht hingehört bei: "if (Bid > maxBid);" (Das hindert das Programm allerdings nicht - es ist nur unnötig)
Bei Ausführung des Codes lässt sich meinerseits feststellen, dass dieser sich verhält wie zu erwarten - nämlich:
Solange die Eingabe < erste Eingabe ist hängt man in der while-Schleife. Gibt man was größeres ein - ist das Programm zu Ende. (Es schreibt sogar "Sold:<Number>" - das Programm ist dann nur so schnell zu, dass du es nicht mehr siehst...)
Sofern das dein Problem ist bin ich sicher, dass du eine Methode aus dem System.Console-Bereich findest, die es dem Nutzer ermöglicht zu sehen was passiert.
Achso - das kannst du dir doch von ASP.NET Core abspicken.
In deiner späteren Anwendung (abseits der Library) wirst du ja sicher etwas ähnliches haben wie die Startup-Klasse - nur dass du es dort wahrscheinlich übersichtlich/einfach halten willst. (Zumindest für Standard-Konfigurationen)
Hab das auch für einige (zugegeben ASP.NET Core basierte) libs gemacht. Schreibst dir einfach einer Helper-Klasse, die solche Services und deren Abhängigkeiten in Standardkonfiguration in der DI einträgt. So sind die einzelnen Komponenten nach wie vor unabhängig und die Verwendung wird trotzdem nicht unübersichtlich, solange der Standard genügt.
Als simple Beispielklasse dafür:
namespace Microsoft.Extensions.DependencyInjection
{
public static class YourNameHereConfigurationExtension
{
public static IServiceCollection ConfigureYourNameName(this IServiceCollectionb services)
{
// your di-registrations here....
}
}
}
Durch eine solche Klasse hast du keine Nachteile - und sogar Microsoft hat's vorgemacht.
(ConfigureMVC, ConfigureLogging, etc.)
Abseits dieser Helfer-Klasse allerdings - ist jegliche Verwendung von DI (oder sogar ServiceLocator) ein Fehler, der dir später bitter aufstoßen wird.
LG
Edit:
Ich hab eine solche Helfer-Klasse z.B. für die Registrierung des DataServices. Da bekommt die Helferklasse die Möglichkeit an bestimtme Konfigurationselemente ranzukommen - und je nach dem was konfiguriert wurde - werden dann eben spezifische DB-Implementierungen (Mssql, Mysql, etc.) in die ServiceCollection eingefügt.
es gibt wirklich keinen Grund, weshalb deine Klassen in diesem Format überhaupt das Prinzip DI kennen sollten.
Beispiel:
Deine Controller in ASP.NET Core - die wissen nichts von DI - die haben im Normalfall schlicht einige Parameter im Konstruktor. Einfach um bei der Anwendung die Freiheit zu erhalten ob und wenn ja welches DI-Framework zum Einsatz kommt.
Wenn die Klasse überhaupt was vom DI-Framework weiß - oder sogar via DI die eigenen Abhängigkeiten auflöst - hast du effektiv Murks gemacht. DI machst du ja eben für lose Kopplung / leichte Austauschbarkeit - und nicht um die Kopplung noch zu verkomplizieren...
Um auf dein Beispiel zurückzukommen:
Wenn BLL1 die BLL2 braucht - dann bekommt sie diese eben per Konstruktor. In der eigentlichen Anwendung (dort in der Startup z.B.) kann man das dann gerne als Singleton via DI umsetzen - aber diese Funktionalität so vorzuschreiben ist in der Regel keine so tolle Idee, da du dann die Verwendung von DI vorschreibst und damit eine Kopplung (zur Microsoft DI) vorschreibst, welche sich überhaupt nicht austauschen lässt.
Mir ging es damit nicht um bestimmte Normen - sondern vielmehr um die typisierte Vorgehensweise. Excel will genauso wenig alles string behandeln wie C#...
ob das dein Problem behebt oder nicht ist mir nicht bekannt.
Soweit mir bekannt - arbeitet Excel mit DateTime genauso mit DateTime wie C#, nur dass das Startdatum zum Zählen ein anderes ist. Kurzum: Das ist eine speziell interpretierte Zahl - und kein string.
wolltest du nicht weg von Excel? Dann scheidet Excel doch auch als Formelmanager aus - sonst kannst du es doch gleich so lassen...
Ich finde es zwar gut solche Formeln nicht hart im Code zu verankern - aber dann würde ich mir an deiner Stelle lieber einen Formelparser suchen und dann eine Art ManagerInterface dafür zu kreieren, das eben auch Doku enthalten kann.
Ich persönlich finde das Projekt "Flee" da ganz interessant - könntest du dir ja mal anschauen: https://github.com/mparlak/Flee
du brauchst doch gar kein static wenn du's ordentlich machst.
Gib den Pages entweder einen Verweis auf die Seitenverwaltung oder auf einen Service zur Seitenverwaltung.
Ich persönlich würde eine IPageNavigationService-Schnittstelle definieren, diese mit der Klasse PageNavigationService implementieren und dies entweder per DependencyInjection oder eben bei Erzeugung der Pages mitgeben, damit es einfach verwendet werden kann.
Wobei die einfachste Möglichkeit (siehe @BerndFfm wenn du nur wenige und unkomplizierte Argumente brauchst) hier definitiv den Vorzug genießen sollte. Muss ja keiner das Rad neu erfinden...
die Fragestellung verwirrt ehrlich gesagt - zumindest wenn diese von einem Programmierer kommt.
Unabhängig von WPF - ihr habt eine startfähige Programmdatei, welche problemlos auch so programmiert werden könnte, dass diese auch Kommandozeilenargumente beherrscht - und bei entsprechenden Parameter eben keine UI zeigt - sondern irgendwo einen Report speichert.
Dabei helfen wird dir WPF wenig bis gar nichts - denn du willst ja nichts darstellen - und für die Reports selbst wird wohl eine wie auch immer geartete andere Lösung zum Einsatz kommen.
Grundlegend:
Ich würde sowas ggf. über die Windows Aufgabenplanung starten lassen und das bestehende Programm eben so erweitern, dass die .exe auch auf entsprechende Kommandozeilenbefehle reagiert.
Was immer du da mit dem Passwort treibst - hör bitte auf damit und nimm ein ordentliches System oder Vorbild für Authentifizierung.
Wer ein Passwort im Klartext im Jahr 2020 speichert dem gehört eigentlich die Schulbank.
Es gibt genug fertige Systeme - und selbst wenn du nicht gewillt bist ein fertiges zu nehmen - dann solltest du dir zumindest die Zeit nehmen nachzuforschen wie man das richtig macht.
innerhalb des AddAuthorization-Aufrufs kommt man nicht an einen IServiceProvider und somit auch nicht an die Instanz des Lizenzservices bzw. dessen Optionen.
(Theoretisch kann man vorab manuell einen erzeugen - das ist aber unsauber und sollte vermieden werden)
Grundlegend sehe ich hier zwei Möglichkeiten:
a) Du baust eine "Option" und liest diese beim o.g. Aufruf auf und verwendest diese Option sowohl im Lizenzservice als auch im Requirement
b) Du hast sicher ohnehin schon eine eigene Implementierung eines AuthorizationHandlers - der bekommt sicher eh schon per DependecyInjection das notwendige Datum, womit das Requirement es hier schlicht nicht nötig hat
den Identity-Kram von Microsoft kann man zwar mit einer eigenen Datenzugriffstechnologie nutzen - es kann hier auch etwas umfangreicher werden.
Grundlegend:
Du musst einen eigenen IdentityStore schreiben, der (bei mir) folgende Schnittstellen implementiert:
IUserPasswordStore<IdentityUserEntity>, IUserClaimStore<IdentityUserEntity>, IRoleStore<IdentityRoleEntity>, IUserSecurityStampStore<IdentityUserEntity>, UserRoleStore<IdentityUserEntity>, IUserLoginStore<IdentityUserEntity>, IUserEmailStore<IdentityUserEntity>, IUserPhoneNumberStore<IdentityUserEntity>, IUserTwoFactorStore<IdentityUserEntity>, IUserLockoutStore<IdentityUserEntity>
Wie man das alles implementiert und anpasst - hängt prinzipiell von dir ab - aber die von Abt verlinkten Stellen waren bei mir vollkommen ausreichend um es auf meine Bedürfnisse mit eigenen Datenschnittstellen anzupassen.
Kann dir zwar ein Beispielprojekt verlinken - aber um ehrlich zu sein wird dich das nicht entscheidend weiter bringen, da es im Prinzip alles Boiler-Plate-Code ist um die bereits genannten Schnittstellen mit der eigenen Schnittstelle zu implementieren...
Wenn du einen Dispatcher in der selben Methode wie eine MySqlConnection verwendest - machst du es im Prinzip schon falsch. (siehe bereits verlinkten Artikel 3-Schichten-Architektur)
Kurz: Ein Dispatcher gehört zur UI - eine Connection zur Datenbank. Beide in der selben Methode zu verwenden zeigt nur, dass du eben nicht getrennt hast wie es sich gehört.
Warum man das so klar sagen kann?
Den Dispatcher verwendet man um eine asynchrone Datenänderung mit dem "UI-Thread" von WPF abzufangen, sodass du UI darüber eben im "richtigen" Thread informiert wird. Wenn du jetzt einen Dispatcher (und auch noch eine Liste, welche der UI bekannt ist - aus der Datenschicht aktualisieren lässt - dann kann das nur falsch sein)
Kann jetzt natürlich sein, dass der Dispatcher komplett unnötig verwendet wurde - aber dann solltest du aufhören einfach Code zu kopieren...
@Abt - ich leider auch nicht - ich hatte nur gehofft jemand hätte mal versucht auf dem Standard-MS-Image sich simpel mit einem Port zu verbinden.
@david.m
Hatte es bislang nicht erwähnt - aber mit einer der ersten Tests meinerseits war das simple Öffnen eines Ports, was problemlos durchging. (Auch ohne "-t"^^)
Zusätzlich hatte ich den UnitTest auch mal mit Port 50.000 ausgeführt.
Trotzdem Danke :)
LG
PS:
Ich denke das weitere Verfolgen dieses Anliegens wird hier keinen so großen Zweck haben. Wenn keiner SMTP auf diese Art testet ist das wohl einfach nicht die Art, wie man das Problem angeht. (Wollte ja nur gründlich sein) Hab meine eigentlichen Klassen und UnitTests (diesmal wirklich) nun so umgeschrieben, dass alles was nicht gerade wirklich getestet wird per Moq gemockt wird. (Obwohl ich noch "etwas" an der Verifizierung eines IMailTransport.Send knabbere - das wird aber schon noch)
Ok - dass damit keine Tests ausgeführt werden war mir nicht bewusst. Schade.
Nunja - dass der Fehler im Test liegt - ich führe diese ganzen Tests ja auch lokal aus - vollkommen ohne jedes Problem - und alle erfolgreich. (Dort führe ich das ganze per VS/ReShaper aus) Demnach sollte der Fehler doch eher in der Umgebung zu suchen sein. Korrekt? (Ist auch nicht so, als ob ich die Tests nur auf dem Server ausführe...)
Habe mal die Änderungen am CI vorgenommen und ein Timeout für den Client gesetzt.
Vom Grundprinzip hast du Recht - es ist ein Timeout, dass beim Connecten auftritt.
Aber wieso tritt das lokal nicht auf - aber auf diesem Docker-System?
Fehler
X DoMailTest [185ms]
Error Message:
Test method FluiTec.AppFx.Networking.Mail.Tests.MailTest.DoMailTest threw exception:
System.IO.IOException: Connection timed out ---> System.Net.Sockets.SocketException: Connection timed out
Stack Trace:
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at MailKit.Net.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 count)
--- End of inner exception stack trace ---
at MailKit.Net.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at MailKit.Net.Smtp.SmtpStream.ReadAheadAsync(Boolean doAsync, CancellationToken cancellationToken)
at MailKit.Net.Smtp.SmtpStream.ReadResponseAsync(Boolean doAsync, CancellationToken cancellationToken)
at MailKit.Net.Smtp.SmtpStream.ReadResponse(CancellationToken cancellationToken)
at MailKit.Net.Smtp.SmtpClient.DataAsync(FormatOptions options, MimeMessage message, Int64 size, Boolean doAsync, CancellationToken cancellationToken, ITransferProgress progress)
at MailKit.Net.Smtp.SmtpClient.SendAsync(FormatOptions options, MimeMessage message, MailboxAddress sender, IList`1 recipients, Boolean doAsync, CancellationToken cancellationToken, ITransferProgress progress)
at MailKit.Net.Smtp.SmtpClient.Send(FormatOptions options, MimeMessage message, CancellationToken cancellationToken, ITransferProgress progress)
at MailKit.MailTransport.Send(MimeMessage message, CancellationToken cancellationToken, ITransferProgress progress)
at FluiTec.AppFx.Networking.Mail.Tests.MailTest.DoMailTest() in /builds/fluitec/fluitec.appfx.networking/src/tests/FluiTec.AppFx.Networking.Mail.Tests/MailTest.cs:line 23
Am öffnen des Ports scheint es ja nicht zu hapern - warum also beim verbinden?
Was den Integrationstest angeht - ja das ist kein feiner UnitTest - grundlegend hatte ich aber hier die Optionen einen SmtpClient zu mocken (der in meinem Teil der API bislang gar nicht öffentlich zur Verfügung steht) und dort zu validieren - oder eben einen simplen SmtpService anzubieten, der eine Validierung erlaubt.
In anderen Worten: Du empfiehlst somit eher dem Client zu mocken?
LG und Vielen Dank
PS: Nunja - ein funktionierendes Verhalten gegenüber dem nDumbsterCore hat mir durchaus einen Mehrweg gebracht. Hab schnell gesehen, dass ich einige Paramter bei der Weitergabe getauscht hatte. Sicher - das ist kein echter SMTP-Server und soll es auch niemals werden, da ich gar keine Mails verschicken möchte in simplen Tests. Auf der anderen Seite verhält sich auch nicht jeder SMTP-Server wie der andere, womit ein solcher Test besser als nichts - aber auch sicher weniger gut als das Produktivsystem ist...
Grundlegend geht es um Folgendes:
Ich schreibe UnitTests die auch SMTP testen sollen - deshalb verwende ich quasi eine Minimalimplementierung eines SMTP-Servers (nDumbsterCore). Lokal - funkioniert das hervorragend - im Gitlab-Runner gibt's ein Timeout nach dem Entdecken der Tests ohne mir die Möglichkeit zu geben auch nur den geringsten Output zu erhalten.
Ursprünglich dachte ich, dass entweder das öffnen oder das verbinden zu einem so geöffneten Port Ärger mit sich bringt. Wie es scheint - ist das nicht der Fall. Denn das hinzufügen von "-t" zu dotnet test - genügt um den Test laufen zu lassen. Sogar parallelisiert.
Für mich steht fest: Das darf kein solches Problem beheben.
Die Fragen die sich mir nun stellen:
a) Warum behebt dieses Flag das Problem?
b) Stell ich mich selbst doof an?
c) Falls b) nicht zutrifft - wo kann ich ein entsprechendes Issue melden?
Gitlab oder eher Microsoft? (und wo genau?)
Für den Fall, dass jemand die Muße hat mein Problem nachzustellen:
a) Eine kurze C#-Klasse, welche genügt um im Gitlab-Runner ein Timeout auszulösen
Datei: MailTest.cs
using MailKit.Net.Smtp;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MimeKit;
using MimeKit.Text;
using nDumbsterCore.smtp;
namespace FluiTec.AppFx.Networking.Mail.Tests
{
[TestClass]
public class MailTest
{
[TestMethod]
public void DoMailTest()
{
var server = SimpleSmtpServer.Start(25);
using (var client = new SmtpClient())
{
client.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true; // accepts all certs
client.Connect("127.0.0.1", 25, false);
client.AuthenticationMechanisms.Remove("XOAUTH2");
client.Send(new MimeMessage
{
From = { new MailboxAddress("Test", "test@example.com") },
To = { new MailboxAddress("Test", "test@example.com") },
Subject = "Subject",
Body = new TextPart(TextFormat.Plain)
});
}
server.Stop();
}
}
}
b) Eine CI-Yaml-Datei um das Problem zu demonstrieren
Datei: .gitlab-ci.yml
If-Else würde funktionieren, du kannst aber auch auch objektorientierter arbeiten und quasi ein Ruleset dafür bauen mit welchem du nicht so viele Verzweigungen brauchst.
Im einfachsten Fall könnte es dann so aussehen:
public static double GetDiscount(int amount)
{
if (amount ≥ 5)
return .2;
if (amount == 4)
return .15;
if (amount == 3)
return .1;
return 0;
}