Das kann verschiedene Gründe haben wie beispielsweise:
- Umgehen von CORS während Entwicklungsprozessen
- Monorepo Codebasis
- Damit bei einem Deployment die Angular-App direkt vom (bspw. IIS) geserved wird, ohne dass man sich um externes Hosten kümmern muss
Da wir bei uns aber getrennt entwickeln (eigene Repositories für je Angular und WebApi) sind meine Aussagen natürlich mit Vorsicht zu geniessen. :)
Wir lassen beispielsweise unsere (teilwese SSR) Apps unter Docker entweder auf Nginx oder Node laufen.
Bezüglich dem Bundling / Environment.
Die einzigen Settings die unsere Angularapps jeweils benötigen sind aktuell
a) REST-API Url
b) weitere externe host-configurations, wie bspw. Sentry.
Diese werden aber nicht vom Host (NGINX / Node) vorgegeben, sondern stehen (Achtung Abt ;)) hardgecoded in den jeweiligen environment.xxx.ts files. Der Angular Build Prozess entscheidet dann jeweils welches Environment File er effektiv in die App reinsetzt.
Es gibt kein 'Ini DAL' oder ein 'SQL DAL'. Es gibt genau ein Data Access Layer, welches zwei verschiedene Repositories (oder was auch immer) enthält.
Diese implementieren beide das (beispielsweise) IConfigRepository, welches mit einer ConfigEntity arbeitet.
Sprich;
Im DAL mappen die einzelnen Repositories ihre Daten in die Config Entity.
Im Business Layer wird dann die ConfigEntity in entsprechende Business Model gemappt.
Es gibt sonst auch die Möglichkeit Javascript / Typescript Code direkt in Google Chrome zu debuggen.
F12 (developer console) -> Sources.
Danach entweder mittels CTRL+P ein File öffnen, oder im Filetree (links) unter Webpack das gewünschte File suchen. Dort kannst du auch Breakpoints etc setzen.
Ich persönlich debugge Frontend-Code immer über die Chrome Dev Tools.
Ich habe scheinbar gerade ne echte Blockade vor dem Kopf was Dependency Injection angeht.
Und zwar stelle ich mir die Frage wie ich am besten bei einem Child-Objekt verschiedene Services injiziere, ohne dass diese im Parent Objekt verwendet werden.
Beispielcode:
public class Person
{
private IDummyInterfaceOne _interfaceA;
private IList<Haus> _haeuser;
public Person(IDummyInterfaceOne interfaceA)
{
this._interfaceA = interfaceA;
this._haeuser = new List<Haus>();
for (int i = 0; i < 10; i++)
{
this._haeuser.Add(new Haus()); // Von wo kommt das IDummyInterfaceTwo?
}
}
}
public class Haus
{
private IDummyInterfaceTwo _interfaceB;
public Haus(IDummyInterfaceTwo interfaceB)
{
this._interfaceB = interfaceB;
}
}
Person ist das Objekt welches schlussendlich mehrere Häuser instanzieren soll.
Die beiden Services 'IDummyInterfaceOne' und 'IDummyInterfaceTwo' sind im DI-Container vorhanden.
Per se fallen mir jetzt zwei Möglichkeiten ein, bin mir aber nicht wirklich sicher ob diese auch der richtige Weg sind.
1) IDummyInterFaceTwo im Person Konstruktor deklarieren, und dann einfach weiter runtergeben
-> Wird aber bei mehreren Services / Interfaces dann auch unsauber, und vorallem verlangt dann mein Person-Objekt Services die es eigentlich (von sich aus) ja auch gar nicht benötigt (sondern nur an das Haus Objekt weitergibt).
2) Ich rufe den (statischen Container) auf und hole von dort jeweils den Service.
Gibts etwas was ich da nicht ganz verstanden oder bedacht habe?
Jein.
iA ist kein Teil eines Objekts.
Eine statische Variable ist eine sogenannte 'Klassenvariable'.
Variabeln eines Objektes, resp. einer Instanz einer Klasse nennt man dann 'Instanzvariable'.
Beispiel.
class Foo
{
public Int32 MyInteger { get; set; }
public static Int32 MyStaticInteger = 0;
}
class Program
{
static void main(string[] args)
{
Foo myFoo = new Foo();
myFoo.MyInteger = 2; // Instanzvariable MyInteger wird für das Objekt 'myFoo' gesetzt.
Foo mySecondFoo = new Foo();
mySecondFoo.MyInteger = 3; // Instanzvariable MyInteger wird für das Objekt 'mySecondFoo' gesetzt.
Foo.MyStaticInteger = 4; // Klassenvariable MyStaticInteger ist nicht Teil einer Foo-Instanz, sondern eine statische Variable.
}
}
Keine Ahnung wie positiv die Repräsentation damit im Marketing ist. ;)
Wir sind alles bald-Absolventen und und interessieren uns für die Thematik da so etwas in unserem Bachelor Studium nicht mehr so genau (oder gar nicht? :)) gelehrt wird. Keine Angst das hat nichts mit Firmenstrategie oder reiner Publicity zu tun. ;)
Siehe Anhang für die Microservice Idee.
Die Aufteilung hier mag zwar trivial sein, soll ja aber auch nur als Beispiel- & Lernprojekt dienen.
Danke für den Input bzgl. normales Login via Forms - ich schaus mir nochmals genauer an!
Mag sein dass ich ein wenig eingerostet bin und mir dadurch das Ganze komplizierter vorstelle als es überhaupt ist.
Aber ja schlussendlich sollen es mehrere Services geben, auf welche durch ein Gateway geroutet wird.
Clients wird es SPA und Mobile App geben.
Danke für deine Antwort.
Wir wollen schlussendlich eine OAuth Login-Möglichkeit anbiete, sprich:
- Entweder der Benutzer registriert sich bei uns mit Email & Passwort und konfiguriert dann sein Profil (weitere Daten wie beispielsweise.. Beruf, Anschrift, was weiss ich) oder
- er nutzt einen IDP wie Facebook oder Google, authentifiziert sich dort und konfiguriert dann sein Profil weiter bei uns (wieder; Beruf, Anschrift etc).
Wichtig ist hier, dass wir wie erwähnt eine Microservice Architektur verwenden und keinen Monolith.
Alle Services können zwar die IDP Authentifizierung nachverfolgen, wie aber die Custom-Authentifizierung (die nicht über einen externen IDP, sondern über unser eigenes System erledigt wurde) verifiziert wird ist mir noch unschlüssig.
Kannst du uns da noch weiter helfen?
Oder ist - wie erwähnt - die beste Lösung, dass unser Auth-Service selber auch ein IDP also quasi ein IdentityServer ist?
Um uns für ein grösseres Projekt vorzubereiten entwickeln wir zur Zeit eine kleinere Web-Applikation welche die Microservice Architektur unterstützt.
Damit die einzelnen REST-Services geschützt sind, möchten wir eine Authorisierung einbauen die Service-Übergreifend ist und müssen da scheinbar noch auf den richtigen Weg geschupst werden.
Was uns da spontan in den Sinn kommt ist eine OpenID Implementation.
Dazu folgende Fragen:
- Ist es korrekt, dass wir damit unseren eigenen Identity Server benötigen (beispielsweise https://identityserver.github.io).
- Wir möchten die User und/oder Clients auf Policies überprüfen (keine Role-Based Authentication). Können wir diese auch auf dem IDP selber oder müssen wir diese auf allen Services definieren?
- Business Logik Überprüfungen (beispielsweise ob ein Benutzer eine Gruppe editieren und/oder löschen kann) wird dann nicht mehr direkt mit dem OAuth Protokoll geregelt, sondern über 'eigene' interne Strukturen. Ist dies korrekt so oder haben wir da einen Denkfehler?
- Gibt es wichtige Punkte die wir noch beachten müssen?
dies ist natürlich die andere Möglichkeit, ich werde mal einen Blick darauf werfen.
Danke euch!
€:
Zitat
Du kannst versuchen für jedes Format einen eigenen Converter zu bauen und dann mit dem Attribut [JsonConverter(typeof(IsoDateTimeConverter))]
an jeder Property zu handieren.
Meinst du damit die Attribute in der Mitarbeiter Klasse? Könnte schwer werden, da die Klassen automatisch mittels dem EF generiert werden.
Oder kann ich die ebenfalls in einer Partial Class so verändern?
Ich google das mal, müsste ja Basic-Knowledge sein (Forenpunkt 1.x.x ;))
Alles klar, gegoogelt und schlauer geworden. Sogenannte MetaData Klassen sind das Stichwort - ich probiere die Sache in den nächsten Tagen aus - danke!
Ich übergebe mittels Javascript eine JSON Zeichenfolge an meinem MVC Controller.
Dort soll mittels dem JSONSerializer die Zeichenfolge in ein ModelObject zurück konvertiert werden.
Leider scheint die Klasse aus dd.MM.yyyy ein MM.dd.yyyy zu machen.
Jegliche Ansätze die Datumsformatierung irgendwie zu ändern sind bisher gescheitert.
Mein bisheriger Code sieht folgendermassen aus:
// employee ist der JSON String
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "dd/MM/yyyy" } );
Mitarbeiter JSONemployee = JsonConvert.DeserializeObject<Mitarbeiter>(employee, settings);
Mit diesem Code erhalte ich jedoch eine FormatException.
Ohne die JsonSerializerSettings werden Tag & Monat vertauscht.
Danke für die schnellen Antworten.
Das mit dem Deaktivieren des Javascripts ist natürlich so eine Sache.
Damit werden wir uns sicherlich auch noch befassen.
Der Hinweis auf Knockout.JS ist super, das schauen wir uns ebenfalls noch an.
Zu den Areas, das Ganze sieht sehr interessant aus.
So wie ich das verstanden habe, ist es eine gute 'Methode' jegliche Module in eine eigene Area zu verpacken.
Angenommen ich erstelle eine Area Verwaltung.
Dort drin müsste man Mitarbeiter, Gruppen sowie News verwalten können.
Wäre es eine gute Lösung im View Ordner in der Area dann für jede 'Verwaltungsmöglichkeit' einen Unterordner zu erstellen?
Wir sind dabei ein grösseres Projekt mittels dem MVC Prinzip zu entwickeln.
Es stellt sich die Frage inwiefern man mittels dem MVC den View Ordner organisieren kann.
Grundsätzlich ist es ja so dass alle Views in dem View Ordner sind.
Ist es jedoch quasi möglich dass man innerhalb des Orderns noch weitere Unterordner erstellen kann und der Controller trotzdem noch begreift wie was abläuft?
Beispielsweise die Ordner Mitarbeiter und Gruppen:
Ich bin auf sogenannte 'Areas' gestossen (Using areas in ASP.NET MVC to organize a project).
Funktioniert ein wenig anders als mein oben genannter Ansatz, aber sieht schon einmal gut aus.
Wäre dies der richtige Ansatz dafür?
Nebenbei soll die Webapplikation mit purem Ajax funktionieren.
Sprich die Seite soll niemals neugeladen werden.
Wäre es also möglich aus der einen Seite (welche mit Controller X) verbunden ist, ein View reinzuladen welches auf Controller Y basiert?
Ein bisschen schwer zu erklären, sorry.
Aber ich hoffe ihr versteht was ich zu Fragen probiere.
Chrome scheint bei meinem AutoCompleteExtender Control die CSS Klassen ('CompletionListCssClass', 'CompletionListItemCssClass', 'CompletionListHighlightedItemCssClass' nicht anzunehmen.
Beim IE und Firefox funktioniert das Ganze einwandfrei.
Weiss da jemand rat?
Gruss,
Regenwurm
EDIT:
Erledigt!
Chrome hatte wohl Probleme die Klassen zu finden da vor dem Klassennamen noch ein #XXXX war.
In der System.Web.Ui.WebControl Klasse gibt es ja das Attribut 'TabIndex', womit fetgelegt wird an welcher Stelle das Control 'durch getabt' wird.
Besteht die Möglichkeit dass ich dieses Attribut einem System.Web.Ui.UserControl geben kann?
Hintergrund ist folgender dass ich ein Benutzercontrol habe, welches nicht durchgetabt (respektive erst ganz am schluss) werden soll.
Das Control von System.Web.Ui.WebControl erben zu lassen steht zur Zeit nicht zur Verfügung.
Ich muss automatisch ein Kalender erstellen.
Jetzt sollen alle einzelnen Events mit der Eigenschaft Free markiert werden.
Jedoch finde ich kein passendes Attribut im RFC2445.
Das VFREEBUSY Attribut scheint mir das naheliegenste zu sein, doch irgendwie werde ich nicht genau schlau aus dem (man muss ja da irgendwie nochmals einen Zeitraum angeben).
Dass der IE sicher nicht der optimale Browser ist bin ich mir bewusst.
Leider habe ich hier Vorgaben welche ich nicht einfach umgehen kann.
Es scheint so als ob die Übergabe der POST Variabeln nur im Debug Modus funktioniert (keine Ahnung warum).
Ausserdem wird nach erfolgreicher Verarbeitung 'einfach so' der Eventhandler meiner 'Löschen' Spalte aufgerufen & das neu erstellte Item dadurch wieder aus der Datenbank entfernt.
Einen Fehler habe ich bei einem kurzen Überblick leider nicht gefunden.
Aufgrund dessen dass es sich hier um eine Abschlussarbeit handelt und ich einen begrenzten Zeitplan habe, muss ich die Massnahme ergreiffen und eine separate Seite für die Bearbeitung der einzelnen Spalten erstellen.
Mir fehlt einfach die Zeit um mich hier weiter mit dem Problem zu beschäftigen.
Aber ich bleibe dran um dies für mögliche - zukünftige - Projekt zu realisieren.
Die POST Variabeln sind im Page_Load Event alle null.
Ich arbeite hier leider mit Internet Explorer und deswegen ist für mich Firebug keine Hilfestellung.
Wenn ich das Javascript debugge sehe ich folgenden HTML Code in meiner erstellten Form:
Sorry bin noch nicht ganz wach. :)
Hier ist meine (momentane) Implementation:
Javascript:
<script type="text/javascript">
// MODA: Funtkion von Stackoverflow um mittels Javascript einen POST Request zu senden.
// [URL]http://stackoverflow.com/questions/133925/javascript-post-request-like-a-form-submit[/URL]
function post_to_url(path, params, method) {
method = method || "post"; // Set method to post by default, if not specified.
var form = document.createElement("form");
form.setAttribute("id", "frmRCH");
form.setAttribute("name", "frmRCH");
form.setAttribute("method", method);
form.setAttribute("action", path);
for (var key in params) {
if (params.hasOwnProperty(key)) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("id", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
form.submit();
}
function InsertData(CheckID) {
var Nummer = document.getElementById("TbNummer").value;
var Rechnungsnummer = document.getElementById("TbRechnungsnummer").value;
var Bezugsdatum = document.getElementById("TbBezugsdatum").value;
var Rechnungsdatum = document.getElementById("TbRechnungsdatum").value;
var Typ = document.getElementById("DDTyp").value;
post_to_url(document.URL, { // Formdaten via POST versenden
'nummer': Nummer, // Railcheck Nummer
'rechnungsnummer': Rechnungsnummer, // Rechnungsnummer
'bezugsdatum': Bezugsdatum, // Datum des Railcheck Bezuges
'rechnungsdatum': Rechnungsdatum, // Datum der Rechnung (bei welcher der Railcheck eingesetzt wurde)
'typ': Typ, // Typ des Railchecks (Codevalue Angabe -> Siehe Codeverwaltung bei WebApps2)
'checkid' : CheckID // ID des Checks (0 -> neu!)
}, "POST"
);
}
</script>
Im Page_Load ist folgender Code Abschnitt zu finden, um die Daten zu verarbeiten:
if (!String.IsNullOrEmpty(Request.Form["checkid"]))
{
Int32 RailID = Int32.Parse(Request.Form["checkid"]);
String RailRechnungsnummer = Request.Form["rechnungsnummer"];
DateTime RailBezugsdatum = new DateTime();
if (String.IsNullOrEmpty(Request.Form["bezugsdatum"]) || !DateTime.TryParse(Request.Form["bezugsdatum"], out RailBezugsdatum))
{
SfFeedback.SqlFailure = "Das Bezugsdatum ist ungültig!";
Server.Transfer(Request.Url.AbsolutePath);
}
DateTime? RailRechnungsdatum = null;
if (String.IsNullOrEmpty(Request.Form["rechnungsdatum"]))
RailRechnungsdatum = null;
else
RailRechnungsdatum = DateTime.Parse(Request.Form["rechnungsdatum"]);
string RailTyp = Request.Form["typ"];
string RailNummer = Request.Form["nummer"];
Railchecks input = cmpRail.LoadSingleData(RailID);
if (input == null)
input = new Railchecks() { ID = 0 };
input.Nummer = RailNummer;
input.Rechnungsnummer = RailRechnungsnummer;
input.Rechnungsdatum = RailRechnungsdatum;
input.Bezugsdatum = RailBezugsdatum;
input.Typ_CD = RailTyp;
if (cmpRail.SaveData(input))
{
SfFeedback.SqlSuccess = "Railcheck erfolgreich hinzugefügt / bearbeitet";
}
else
{
SfFeedback.SqlFailure = "Während des Bearbeitens des Railchecks ist ein Fehler aufgetreten!";
}
Server.Transfer(Request.Url.AbsolutePath, false);
}
Damit ich in einer Auflistung eine 'In-Place' Edit Funktion ohne Ajax realisieren kann, muss ich via Javascript einen POST (oder einen GET) Request absenden, und diesen mittels ASPX verarbeiten.
Bisher habe ich meine Datenbank Modelle (für das Entity Framework) immer bereits im Microsoft SQL Management Studio erstellt.
Diest ist aktuell nicht mehr möglich weil alle Tabellen die ich benütze eine FK Referenz auf ein View brauchen. -> Im Management Studio kann ich bei den Datenbank Diagrammen kein View hinzufügen.
Nun muss ich also die Assoziationen direkt im Model Designer erstellen -> und daran scheitere ich.
Um eine Assoziation zu erstelle mache ich einen Rechtsklick auf die erste Tabelle und wähle 'Add -> Association'.
Bei der linken Spalte wähle ich eine meiner Tabelle aus (die einen FK besitzt).
Bei der rechten Spalte wähle ich das View aus (auf welches referenziert werden soll).
Das Navigation Property bei der rechten Spalte brauche ich nicht (da ich ja nur von meiner Tabelle aus referenzieren möchte).
Ebenfalls soll kein Foreign Key Property erstellt werden.
Meist muss ich die assoziation noch bearbeiten, da er öfters 2 falsche Spaltenreferenziert.
Das Ganze funktioniert super wenn ich eine Tabelle benütze, welche keinen 'ID Primary Key hat' (Also quasi einen Identifier).
Sobald die Tabelle aber einen Identifier UND einen Foreign Key hat, sagt er mir dass ich beide Spalten referenzieren muss.
Inwiefern kann ich die ID-Spalte so markieren, dass ich sie nicht mit referenzieren muss?