Laden...

ASP MVC 3: Invalid Operation Exception beim Einsatz von Data Annotations für Modelvalidierung

Erstellt von st@tic vor 12 Jahren Letzter Beitrag vor 11 Jahren 14.066 Views
S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 12 Jahren
ASP MVC 3: Invalid Operation Exception beim Einsatz von Data Annotations für Modelvalidierung

Hallo,

ich arbeite mich gerade in ASP MVC 3 ein und versuche mich an dem Tutorial MVC Musicstore und bin mittlerweile beim Part 6 angekommen. In Teil 6 geht es um die Validierung mittels der Data Annotations

Es funktioniert auch teilweise. Nur sobald ich zum Beispiel Required einsetze, erhalte ich eine InvalidOperationException

Fehlermeldung:
{"Der Vorgang erfordert eine Verbindung mit der Masterdatenbank ('master'). Es kann keine Verbindung mit der Masterdatenbank ('master') hergestellt werden, da die ursprüngliche Datenbankverbindung geöffnet wurde und die Anmeldeinformationen aus der Verbindungszeichenfolge entfernt wurden. Stellen Sie eine nicht geöffnete Verbindung bereit."}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Web.Mvc;

namespace MvcMusicStore.Models
{
    [Bind(Exclude = "AlbumId")]
    public class Album
    {
        [ScaffoldColumn(false)]
        public int AlbumId { get; set; }
        [DisplayName("Genre")]
        public int GenreId { get; set; }
        [DisplayName("Artist")]
        public int ArtistId { get; set; }
        //[Required(ErrorMessage = "An Album Title is required")]
        //[StringLength(160)]
        public string Title { get; set; }
        //[Required(ErrorMessage = "Price is required")]
        //[Range(0.01, 100.00, ErrorMessage="Price must be between 0.01 and 100.00")]
        public decimal Price { get; set; }
        [DisplayName("Album Art URL")]
        //[StringLength(1024)]
        public string AlbumArtUrl { get; set; }
        public /*virtual*/ Genre Genre { get; set; }
        public /*virtual*/ Artist Artist { get; set; }
    }
}

sobald Required, Stringlenght oder Range wieder einkommentiert werden, bekomme ich die Fehlermeldung. Kommentiere ich es aus, alles wieder in Butter.

16.806 Beiträge seit 2008
vor 12 Jahren

Zeig mal, wie Du eine Datenbankverbindung erstellst. Da ist was evtl. krumm.

Ich persönlich rate aber mittlerweile von Data Annotations ab, da ich schlechte Erfahrungen gemacht hab. Ich verwende überall nur noch IValidateableObject, da es deutlich flexibler und korrekter arbeitet.

1.002 Beiträge seit 2007
vor 12 Jahren

Hallo Abt,

implementierst du das IValidateableObject-Interface in deinen Entity-Klassen oder in View-spezifischen ViewModels?
Wenn in den ViewModels, wie vermeidest du Redundanzen?

[...] da es deutlich flexibler und korrekter arbeitet.

Inwiefern arbeitet IValidateableObject korrekter?

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 12 Jahren

mit dem xmlpart aus der webconfig.


<connectionStrings>
    <add name="MusicStoreEntities"
         connectionString="data source=.;Initial Catalog=MvcMusicStore;Password=user;User ID=pwd;Connect Timeout=150"
         providerName="System.Data.SqlClient"/>
  </connectionStrings>

was mich nur wundert ist, in dem andern tutorial fliegt er mir nicht auseinander.
die unbehandelte execption wird übrigens im StoremanagerController in der Index-Methode geworfen


public ViewResult Index()
{
            var albums = db.Albums.Include(a => a.Genre).Include(a => a.Artist);
            return View(albums.ToList());
}

das mit dem IValidateableObject finde ich noch interessant. Gibt es da irgendwas zum Einstieg? Wenn ich mir dadurch solch einen Ärger erspare, dann würde ich mich daran versuchen.

16.806 Beiträge seit 2008
vor 12 Jahren

Hi,

ich erweitert meine Entities via partial und implementiere dann IValidateableObject.

Anschließend hab ich drei Methoden:
zum einen die Standard IsValid() Methode, die IValidateableObject erfordert und zum anderen ein Validate()



        public bool IsValid( out IEnumerable<ValidationResult> resultList )
        {
            var errorCollection = new List<ValidationResult>( );

            if ( String.IsNullOrEmpty( this.Maker ) )
            {
                errorCollection.Add( new ValidationResult( "'Maker' is required.", new[ ] { "Maker" } ) );
            }

            resultList = errorCollection;

            return ( errorCollection.Count == 0 );
        }

        public IEnumerable<ValidationResult> Validate( )
        {
            IEnumerable<ValidationResult> list;

            this.IsValid( out list );

            return list;
        }

        public IEnumerable<ValidationResult> Validate( ValidationContext validationContext )
        {
            return Validate( );
        }

Damit decke ich dann alle Fälle ab; kann zb über einen eigenen Context validieren, kann validieren, ohne mit der DB agieren zu müssen und auch die sichere Validierung vor einem Insert ist abgedeckt.

Zudem kann ich nicht nur eine einfache Prüfung vollziehen, sondern auch eine logische Abhängigkeit zweier Properties sehr einfach umsetzen.
[gelöst] ASP MVC + EntityFramework: Connection (closed/ opened) ==> Context Sharing

16.806 Beiträge seit 2008
vor 12 Jahren

st@tic eigentlich schaut das okay aus. Vielleicht passt das Datenbankmodell nicht zu Deiner Klasse; aber das ist nur raten.

Hinweis: Allgemeine Vorgehensweise bei userbezogenen DB-Verbindung in einer Webapplikation
Vielleicht läufts Du irgendwann auch auf den Fehler.

Zudem empfehl ich Dir die Verwendung von Repositories zur einheitlichen Auslagerung von Datenbank-Methoden.
Lese dazu: Brauche ich ein Repository?

1.002 Beiträge seit 2007
vor 12 Jahren

Hallo Abt,

vielen Dank für deine Antwort.

Wie handhabst du denn clientseitige JavaScript-Validierung?

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 12 Jahren

Vielen Dank Abt für deine Mühe.

Diese partial Klasse muss ich dann für alle Entities schreiben richtig? Und ist das wirklich alles? Ich verstehe zur Zeit nicht wie diese Art der Validierung arbeitet. Brauche ich da weiterhin die DataAnnotations oder wie weiß, dann die Klasse wie was validiert werden soll?

Auch hab ich noch Schwierigkeiten, dass ganz mit Factory und Repository zu verstehen und um zu setzen. Wollte mich erstmal mit ein paar Grundzügen vertraut machen, daher ist es deprimierend, wenn dann die Tutorials nicht wirklich so funktionieren.

weil merkwürdigerweise funktioniert es in einem anderen beispiel wunderbar


public class Movie
    {
        public int ID { get; set; }
        [Required(ErrorMessage = "Title is required")]
        public string Title { get; set; }
        [Required(ErrorMessage = "Date is required")]
        [DisplayFormat(DataFormatString="{0:d}")]
        public DateTime ReleaseDate { get; set; }
        [Required(ErrorMessage = "Genre is required")]
        public string Genre { get; set; }
        [Required(ErrorMessage = "Price required")]
        [Range(1,100, ErrorMessage="Price must be between $1 and $100")]
        [DisplayFormat(DataFormatString="{0:c}")]
        public decimal Price { get; set; }
        [StringLength(5)]
        public string Rating { get; set; }
    }

beide beispiele stammen von asp.net. beispiel oben ist die MVC Movie App

das mit der Cliend-Sidevalidation würde mich aber auch Intressieren 😃

16.806 Beiträge seit 2008
vor 12 Jahren

Wie handhabst du denn clientseitige JavaScript-Validierung?

Verwende nur HTML5 Validierungen, die zB ein IE10, Firefox oder Chrome ebenfalls unterstützen.
Der Anwender kann eine HTML5 Validierung nicht umgehen, eine Javascript-Validierung hingegen schon, indem er einfach Javascript deaktiviert.
Zudem funktioniert eine JS-Validierung auf manchen mobilen Geräten aus irgendeinem Grund nicht wirklich sauber - wieso weiß ich nicht.

Am Server muss ich also so oder so validieren.

Ich seh die Client-seitige Validierung in MVC sowieso auf einem sterbenden Ast. Kann mir nicht vorstellen, dass in einer MVC Version 5 das in der Form noch existiert.

Ich verstehe zur Zeit nicht wie diese Art der Validierung arbeitet.

Sobald beim Commit das Entity versucht wird einzutragen wird durch die Implementierung von IValidateableObject das Validate() ausgeführt - daher wird auch der ValidationContext als Parameter benötigt, den das EF aber bereits automatisch liefert.

Theoretisch musst Du also im Controller gar kein IsValid ausführen; ich habs beispielhaft in meinem Snippet, weil ich ein Save() erst ausführe, wenn das IsValid auch wirklich valid ist - dann kann ich die einzelnen Fehler besser in meine View integrieren, sodass der Anwender auch direkt am entsprechenden Feld weiß, was er tun muss.

Brauche ich da weiterhin die DataAnnotations oder wie weiß, dann die Klasse wie was validiert werden soll?

Nein, brauchst Du nicht mehr.

Du musst halt wie in meinem Beispiel oben die Elemente manuell validieren, nach Deinen Vorgaben. Bei mir wars eben ein String.IsNullOrEmpty()-Beispiel. Aber man ja validieren, was man will und braucht.

Auch hab ich noch Schwierigkeiten, dass ganz mit Factory und Repository zu verstehen und um zu setzen. Wollte mich erstmal mit ein paar Grundzügen vertraut machen, daher ist es deprimierend, wenn dann die Tutorials nicht wirklich so funktionieren.

Ein Repository ist nichts anderes als eine Ansammlung von Methoden, um mit der Datenbank zu agieren - aber an einer zentralen Stelle.
Angenommen Du suchst in 15 Stellen in Deinem Code nach einem String in der Datenbank, und Du willst jetzt, dass die Groß- und Kleinschreibung ignoriert wird, dann musst Du 15 Stellen im Code ändern.
Bei einem Repository wäre es nur eine Stelle. Zudem ist der Code einfach übersichtlicher und es findet eine modulare Trennung von Code statt.

Die ConnectionFactory ist ebenfalls ein Hilfsmittel zur Fehlervermeidung.
Das ist im Gegensatz zu einem Repository nur ein optionaler, wirklich optionaler Punkt. Die meisten werden in solch eine Problematik erst kommen, wenn mal ein IIS-Update stattfindet und die Connection-Strings überschrieben werden.

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 12 Jahren

Und wie prüfst du z.b. sachen ab ob Integer, String oder String mit einer maixmalen Länge von x etc?
Wird HTML5 eigentlich schon vom IE unterstützt? Da ich hauptsächlich für interne Zwecke Projekte realisere und der IE bedauerlicherweise Standard ist, bringt mir FF Chrome und Co wenig 😦

16.806 Beiträge seit 2008
vor 12 Jahren

Das kannst Du in der Form so gar nicht validieren; das ist aber ein Problem des HTML Standards. Der 4er ist einfach sehr weit verbreitet und der 5er ist noch nicht soweit, dass man ihn als allgemein Gültig bezeichnen könnte.

Alle meine Seiten basieren mitlerweile auf der HTML5-Boilerplate.
Wenn HTML5 nicht vom Browser unterstützt wird, dann wird ein html5.js geladen, das die Funktionen nachahmt.

Ich hab also ein Input-Feld mit dem type="integer"; dann ist auch nur eine Eingabe als Integer möglich.

Generell hab ich aber SubmitModels, die dem jeweiligen Typ entsprechen.
Wenn ich also ein Integer erwarte, und der User tippt ein String ein, dann wird in der MVC-Theorie das Feld gar nicht gefüllt - es bleibt also leer bzw beim Standard-Wert, auf das die Validierung gejagt wird.

Bei manchem Projekten mach ichs aber auch so, dass ich immer Strings annehme, und dann versuche zu parsen. Klappt das nicht, ist der Wert ungültig (in meinen Augen ist das auch der bessere Weg).
Das muss aber bei der Wertübernahme von SubmitModel zu Entity passieren.
Das entspricht auch der Theorie, dass die View sich um die korrekten Eingabetypen kümmern muss, und die Entity um die Gültigkeit des Werts an sich.

Sprich, die View bzw. der Controller prüft, ob die Typ-Eingaben korrekt sind; ob ein Int dort ankam, wo er auch erwartet wurde.
Eine Entity prüft, ob der Integer dann auch wirklich in dem Wertebereich liegt, in dem er liegen soll.

Ein Range bzw. eine Länge eines Wertes kann ich aber direkt im IsValid() abfragen und behandeln.


Ist vielleicht ein wenig umständlcher als mit DA; aber es ist viel leichter zu warten und individuelle Anpassungen durchzuführen; dahingehend empfinde ichs auch leichter zu integrieren und dem Benutzer viel intuitiver anzeigen zu können, was denn wirklich falsch ist.

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 12 Jahren

Ich glaub ich brauch ein Buch. Es klingt alles logisch und verständlich. Aber umsetzen werd ich es zumindet jetzt nicht können. Ich hab noch nicht wirklich den Fuß in die Tür gekriegt. Zu deiner Lösung hat sich wahrscheinlich noch keiner die Mühe gemacht es ausführlich und für Anfänger verständlich nieder zu schreiben oder?

16.806 Beiträge seit 2008
vor 12 Jahren

Ich wollte schon lang mal ne FAQ dazu schreiben, aber ehrlich gesagt fehlte mir da bislang die Zeit.

Was genau versteht Du denn nicht?
Alles, was Du brauchst, hab ich eigentlich genannt bzw sogar in nem Snippet gezeigt.

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 12 Jahren

was mich noch interessiert ist wie ich es am besten mit einer Factory löse. Vielleicht liegt es auch einfach nur an der Web.config, dass es da in der Tat auseinander fliegt. Auch wenn mir der Begriff bekannt ist, tu ich mir unglaublich schwer das umzusetzen.

ich will mich erstmal so nah wie möglich an den Tutorials bewegen, damit ich ein wenig das Grundverständnis bekomme.

16.806 Beiträge seit 2008
vor 12 Jahren

Also gut... dann tipp ich mal frei aus dem Kopf - garantiere mal nicht, dass es kompiliert; womöglich nehm ich es als Basis für einen FAQ Eintrag...

(Die Tutorials finde ich übrigens nicht mehr zeitgemäß, weder NerdDinner noch der MusicStore. Gerade Repositories werden hier völlig vergessen!.
Auch das direkte Übergeben von Entities an die View bzw als Empfang am Controller finde ich mittlerweile mehr als unangemessen - viel zuviele Fallstricke.
MVC hat hier zwar eine schöne Basis und viele Helfer (zB UpdateModel), aber zu Ende gedacht wurde hier leider nicht.)

Ich halte nicht viel vom Speichern der Einstellungen in der Web.Config; in der Desktop-Umgebung mag das Sinn machen - aber nicht in der Web.
Der Grund: der IIS vererbt seine Einstellungen nach unten - somit können schnell Einstellungen überschrieben sein und es kracht.

Daher empfehle ich einen eigenen SettingsProvider zu schreiben, der zB mit einer eigenen XML-Struktur gemäß der Anwendung arbeitet.

Für eine ordentliche Projektstruktur empfiehlt sich folgende Basis:

  • MVC Hauptprojekt
  • Entity Projekt
  • Entity Extension Projekt
  • Repository Projekt

Im Entity Projekt ist nichts anderes definiert als eben die Entities.
In meinem Falle arbeite ich immer mit einem EDMX-Designer-File und lasse mir die Entities anschließend mit einem DbContext Entity Generator erstellen.
Erweitern (zB IsValid()) kann ich die Entities anschließend in ausgelagerten Dateien via partial. Diese müssen auch in diesem Projekt abliegen!

Wenn es um Erweiterungen geht, die keine logische Abhängigkeit haben, und nur Hilfsfunktionen sind, gehören diese in ein extra Extension Projekt. Erweitern geht dann hier via static class Extensions.

Das Repository Projekt behandelt die komplette Interaktion mit der Datenbank.
Hier werden Get, GetMany, GetAll, Add, Delete, Save Methoden angegeben. Jedes Entity hat hierbei ein eigenes Repository, sodass spezifsche Methoden ebenfalls hinzugefügt werden können (zB GetUserByEMail macht nur bei einem User sinn, nicht bei einer anderen Entity, das gar keine E-Mail hat).

Die Hauptanwendung kümmert sich um den Aufbau der Datenverbindung; könnte man auch auslagern - aber ich finde, da die Anwendung weiß, welche DB-Einstellungen sie verwenden muss, gehört das auch da rein.

Im gesamten sieht das dann etwa so aus:


// Datenbankspezifisches Handling 
public static class DatabaseConnectionFactory
{
	private static MyDatabaseContext SingleConnection
	{
		get
		{
			var singleConnction = new MyDatabaseContext( CreateConnectionString( ) );
			return singleConnction;
		}
	}

	// Erstellen eines ConnectionStrings für das Entity Framework.
	public static string CreateConnectionString( )
	{
		 var sqlBuilder = new SqlConnectionStringBuilder( );
		{
			sqlBuilder.DataSource = "123.123.123.123";
			sqlBuilder.InitialCatalog = "MyDatabaseName";
			sqlBuilder.IntegratedSecurity = true;
			sqlBuilder.MultipleActiveResultSets = true;
		 }
	 
		var entityBuilder = new EntityConnectionStringBuilder( );
		{
			entityBuilder.Provider = "System.Data.SqlClient" // "System.Data.SqlClient";
			entityBuilder.ProviderConnectionString = sqlBuilder.ToString( );
			entityBuilder.Metadata = "res://*/";
		}
	 
		return entityBuilder.ToString( );
	}
}

// Basis Controller, von dem alle anderen Controller erben.
public class MyCustomBaseController : Controller
{
	private MyDatabaseContext _dbContext;
	
	// DbContext für diesen Request
	// Implementiert als "Lazy Loading", sodass ein Context nur (einmalig) erstellt wird, wenn er auch wirklich gebraucht wird
	
	public MyDatabaseContext DbContext
	{
		if( this._dbContext == null )
		{
			this._dbContext = DatabaseConnectionFactory.SingleConnection;
		}
		
		return _dbContext;
	}
}

// Controller, der Views anzeigen soll
public class IndexController : MyCustomBaseController
{
	// Einzeigen einer Hauptseite, in dem Fall /Users/Index bzw einfach nur /Users
	public ActionResult Index( )
	{
		// Erstellen eines ViewModel Objektes
		var viewModel = MyCustomIndexViewModel( )
		
		// Erstellen eines Repositories - in diesem Fall für die Benutzer-Tabelle
		using( var myUsersRepository = new UserRepository( base.DbContext ) )
		{
			// Laden und materialisieren aller Benutzer aus der Datenbank - geordnet nach Name (absteigend)
			
			viewModel.Users = myUsersRepository.GetAll( ).OrderBy( userEntry => UserEntry.Name ).ToList( )
			
			// ToList macht man eigentlich nicht, hier machts aber sinn, da man eh alle Daten braucht
		}
		
		return View( "Index", viewModel );
	}
}
S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 12 Jahren

ui, soviel Arbeit. Danke! Bin wirklich kein großer freund vom Vorkauen, aber wie du so schön sagtest: Die Tutorials sind nicht mehr zeitgemäß und wenn die dann auch nicht mal mehr funktionieren wird es richtig doof.

Dein Code ist auf den ersten Blick auch für mich verständlich. Die verschiedenen Klassen kommen dann sicherlich aber in verschiedene Klassendateien oder? Aber ich denke mal mit den ganzen hilfreichen Informationen kann ich was anfangen. Gibt es eigentlich ein etwas aktuelleres empfehlenswertes Buch was UpdateModel, Repositories etc behandeln. Um ein bisschen Printlektüre werde ich nicht drum rum kommen.

16.806 Beiträge seit 2008
vor 12 Jahren

Bis die Printlektüre draußen ist, ist das Web fünf Schritte weiter. Im Web laufen die Uhren ein wenig schneller als auf dem Desktop.
Völliger Käse in meinen Augen also - aber jeder hat da andere Geschmäcker.

PS: ja, gemäß Microsoft Empfehlungen ist jede Klasse eine Datei.

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 12 Jahren

oh man. Tutorials veraltet, keine anständige Lektüre und Dokumentation von MS ist auch dürftig. Ich seh da irgendwie schwarz es zu lernen. Ich kann ja auch schlecht jedes mal fragen und andere meine Arbeit erledigen lassen.

16.806 Beiträge seit 2008
vor 12 Jahren

Fahrradfahren lernt man auch nicht aus dem Buch; sondern man fährt.. und fährt.. fällt hin.. merkt, dass es weh tut..und fährt weiter bis es klappt 😉

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 12 Jahren

Blöd is nur, dass ich noch nicht mal weiß, wie rum ich mich auf den Sattel zu setzen habe.

1.002 Beiträge seit 2007
vor 12 Jahren

Hallo st@tic,

Abt hat Recht damit, dass die Geschwindigkeit der Weiterentwicklung von Web-Technolgien sehr hoch ist. Mit dieser Frequenz können Bücher schlicht aufgrund der Tatsache, dass sie ein Printmedium sind, nicht mithalten. Ich würde dir trotzdem empfehlen, dir ein Buch zuzulegen und dir die Grundlagen anzueignen. So habe ich zum Beispiel die Professional ASP.NET MVC gelesen (damals noch für ASP.NET MVC 2) und war mit dem Buch sehr zufrieden.

Um dich auf dem aktuellen Stand zu halten und über die neuesten Themen Bescheid zu wissen, musst du natürlich digitale Quellen heranziehen, also Dokumentationen, Blogeinträge, usw. Ich halte es jedoch für sinnvoll, sich vorerst systematisch die Grundlagen anzueignen, und dafür ist ein zusammenhängendes Buch von renommierten Autoren meiner Meinung nach am besten geeignet.

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 12 Jahren

gibt es eigentlich gute online quellen? microsoft nimmt es ja leider nicht so genau mit der öffentlichen dokumentation.

16.806 Beiträge seit 2008
vor 12 Jahren

Diese Behauptung ist völliger Käse.

Mir ist keine Programmiersprache bekannt, die in Breite und Tiefe so gut dokumentiert ist, wie C# bzw .NET. Da könnten sich andere eine Scheibe von abschneiden.
Zudem hat Microsoft den Quellcode von ASP MVC veröffentlicht, sodass hier auch eine völlige Transparenz herrscht.

Er hat nicht den besten Schreibstil aber ScottGu hat nen sehr umfachreichen Blog http://weblogs.asp.net/scottgu/

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 12 Jahren

ja bei c# hast du recht, aber beim mvc vermisse ich persönlich einiges oder bin ich zu blöd es zu finden.

Edit. Bin übrigens mal dazu übergegangen die MSSQL Datenbank nicht zu verwenden sondern wie im Tutorial das ganze zu machen. Da taucht der Fehler nicht auf. Nicht desto trotz seh ich das jetzt erstmal als Notlösung an, damit ich mir zumindest ein wenig mehr Grundverständnis aneignen kann.

1.002 Beiträge seit 2007
vor 12 Jahren

Hallo st@tic,

hast du mal Google bemüht und nach "ASP.NET MVC" gesucht? Das erste Suchresultat schickt dich auf www.asp.net/mvc, eine Seite von Microsoft, die sehr ausführliche Online-Tutorials zu den wichtigsten Themenbereichen von ASP.NET MVC enthält.

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 12 Jahren

die acker ich gerade durch.

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 11 Jahren

ich hab mich noch ein wenig mit dem IValidatableObject beschäftigt und es tun sich noch ein paar Fragen auf.

Zuerst die Validierung. Hier ist ein Beispiel wie eine eigene Validierung implementiert wurde
http://en.hugon.ws/articles/mvc-3/the-iv...ject-interface/
ist das die saubere Lösung oder eine "funktioniert geht aber schöner"?

Mit den erwähnten Entities sind die Modelklassen gemeint und diese sollten dann mittels partial erweitert werden, richtig? Man kann die partial-Klassendatei zwar nennen wie man will, aber wie nennt ihr sie so, dass man erkennt, welche Dateien zusammen gehören?

Das Interface muss bei jeder Klasse implementiert werden und die Validierung für jedes Model/Entity neu geschrieben werden? Oder gibt es auch hier sauberere Lösungen?

Wie sieht die Prüfung bei verschalteten Klassen aus? Z.B. im Musicstore das Model Album beinhaltet eine Liste vom Typ Genre. Bekommt jede Klasse das Interface und die Validierung findet dann in jedem Model statt oder wird die Prüfung nur in der "Mutterklasse" vorgenommen?

Ich bedanke mich schon mal für eure Antworten. Ich lerne langsam, aber fleißig 😃

16.806 Beiträge seit 2008
vor 11 Jahren

Also an und für sich ist die Implementierung richtig - und auch die Vorgehensweise:
Die Validierung wird ausgeführt, sobald die Entity im Controller ist und schiebt die Fehler dann in den ModelState, der dann direkt abgefragt werden kann. das gleiche würde dann noch mal passieren, wenn man versucht die Entity in die Datenbank zu schieben.

ABER: ich finds in der realen Welt nicht praktikabel.

Man sollte einfach nicht direkt eine Entity an einem Controller empfangen; ich war früher zugegebenermaßen auch anderer Meinung - aber die ein oder andren Probleme haben mich davon abgebracht.

Kleines Beispiel:
Du hats eine Entity "Mitarbeiter".
Diese hat in der Validierung die überprüfung, ob die Relation "Chef" gesetzt ist - es ist schließlich eine Pflichtangabe.

Nun kann aber diese Relation gar nicht direkt durch die View an den Controller gegeben werden; wird einfach nicht unterstützt - wie auch.
Sprich, der ModelState ist in diesem Fall IMMER Invalid.

Daher nutze ich überall nur noch ViewModels bzw SumitModels.
In diesem Fall hätte das SubmitModel neben den Eingaben des Mitarbeiters noch zusätzlich die ID des Chefs.

Anschließend werden alle Werte vom SubmitModel in die Entity des Mitarbeiters übertragen und die Entity des Chefs gesucht und den Mitarbeiter zugewiesen.
ANSCHLIESSEND manuell eine Valid-Überprüfung ausführen - deren Resultat ist dann auch glaubhaft.

Das Nutzen des ModelStates ist für mich nur für enthaltene Properties sinnvoll; und das ist in der Realität nur kaum vorhanden.

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 11 Jahren

Ok danke,
also noch mal auf Anfang und View- und SubmitModels anschauen 😃

die validierung wird dann in den submitmodels durchgeführt oder?

16.806 Beiträge seit 2008
vor 11 Jahren

Ne, ViewModels und SubmitModels sind doof - die kennen keine Methoden.
Ich weiß auch nicht, ob ich der einzige bin, der so etwas verwendet - die meisten nutzen einfach nur ViewModels. Gesehen hab ich so etwas, wie ichs nutze, jedenfalls noch nicht.

Ich habs weiter oben schon erklärt:

Ein ViewModel repräsentiert die VIEW.
Ist also eine Auswahlbox, zB mit Ländern, in der View enthalten, dann hat das ViewModel eine Liste von Ländern


public class MySpecificViewModel
{
   public IEnumerable< String > Laender { get; set; }
}

Das SubmitModel hingegen repräsentiert die Form, die von der View generiert und vom User abgesendet wurde und später am Controller landet.
In diesem Beispiel landet also nicht eine Liste von Ländern, sondern nur das jeweilige Land am Controller - und zwar das, das vom Anwender ausgewählt wurde.


public class MySpecificSubmitModel
{
   public String Land { get; set; }
}

public ActionResult Submit(MySpecificSubmitModel submitModel)
{
   var selectedLand = submitModel.Land;
}

Die Werte werden anschließend vom SubmitModel in ein neues Entity übertragen, und das Entity dann validiert.
Die Fehler werden dann über das ViewModel wieder auf der View angezeigt.

SubmitModels verlassen in meinen Gedanken auch den Controller nicht mehr - sondern sind nur dazu da, die Daten aus der Form aufzunehmen.
Nur ViewModels werden view View() den Controller verlassen und an die View übergeben!

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 11 Jahren

jetzt bin ich verwirrt, also doch keine submitmodels nutzen oder wie?
validierung in den entities selbst (sind das jetzt eigentlich die models?) wo dann immer noch die vorherige frage mit den verschalteten wäre.

so doof kann ich doch eigentlich nicht sein, ich zweifel langsam wirklich an meinen spärlichen fähigkeiten.

16.806 Beiträge seit 2008
vor 11 Jahren

Ich auch...

Du hast im Endeffekt 4 Klassen.

* Du hast eine Klasse der Entity - die kannst Du auch nicht verändern, sofern sie vom Entity Framework / vom Designer generiert wird.
Diese heißt zum Beispiel Mitarbeiter in der Mitarbeiter.cs

* Du hast eine Klasse zum erweitern der Entity, wie in Deinem Beispiel oben.
Hier wird auch IValidatableObject implementiert.
Eben Mitarbeiter in der PartialMitarbeiter.cs

Das sind beides Klassen, die besser in ein eigenes Projekt gehören. Eben auf Datenbankebene, da sie eben auch eine Tabelle in der Datenbank repräsentieren.

Dann hast Du noch 2 Klassen, die in die MVC Applikation gehören.
SubmitModel und ViewModel.

Im unteren beispiel siehst Du auf der linken Seite, wie meinew View- bzw. SubmitModels angesiedelt sind.
Auf der rechten Seite sind meine Entities - wobei unter vom *.tt-File die vom Designer generierten Entity-Files liegen, und im Ordner Metadata die Erweiterungen (partial).

Aktuell wenig Zeit den Artikel zu schreiben - leider. Aber kommt.

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 11 Jahren

ok,

noch ne kleine bescheuerte Frage. Wie kommt das Submit und Viewmodel so unter die Bearbeiten.cshtml?

und noch was. ich versuche gerade selbst was zusammen zu bauen. einfach was super simples. u.a. will ich auch ne ConnectionFactory nutzen.

private static MyDatabaseContext SingleConnection
    {
        get
        {
            var singleConnction = new MyDatabaseContext( CreateConnectionString( ) );
            return singleConnction;
        }
    }

wo kommt MyDatabaseContext her?

16.806 Beiträge seit 2008
vor 11 Jahren

Das Group Items kommt vom Visual Studio Addin "VSCommands"; damit kann man solche Elemente gruppieren.

Der Context heißt so, wie der Datenbankcontext Deiner Entities. Weiß nicht, wie der bei Dir heißt.
Aber tendenziell so, wie der Connectionstring bei Dir heißt - wäre MusicStoreEntities.

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 11 Jahren

achso.
da ich wie gesagt gerade versuche etwas nacktes selbst zu baue hab ich natürlich noch nichts der gleichen. ich probier jetzt noch ein paar kleinigkeiten selbst aus, welche mir gerade beim schreiben eingefallen sind und bei weiteren fragen, muss ich dann wahrscheinlich wieder deine geduld strapazieren.

Edit: ok eine Frage hab ich jetzt noch. Es ist zwar nicht sonderlich intelligent, immer durch die Themenpunkte zu springen, aber ich hocke jetzt an der ConnectionFactory

hab mir jetzt einfach mal eine simple klasse zusammen gebaut.


namespace ValidateTest.Models
{
    public class ValidateTestEntities : DbContext
    {
        public DbSet<HomeModel> HomeModels { get; set; }
    }
}


private static ValidateTestEntities SingleConnection
        {
            get
            {
                var singleConnection = new ValidateTestEntities(CreateConnectionString());
                return singleConnection;
            }
        }

jetzt kommt der Fehler "enthält keinen Konstruktor der 1-Argumente akzeptiert. Logisch weiß ich jetzt, was es bedeutet. Ich muss jetzt einen Konstruktor mit einem Argument anlegen, aber in was muss ich dann den ConnectionString speichern.

16.806 Beiträge seit 2008
vor 11 Jahren

Also ich werd Dir jetzt nicht mehr auf Dinge antworten, die Du selbst binnen 20 Sekunden via Google finden kannst - auch nicht via PN.

Using DbContext in EF 4.1 Part 2: Connections and Models

Aus der Reihe Using DbContext in EF 4.1 Part 1: Introduction and Model

S
st@tic Themenstarter:in
281 Beiträge seit 2004
vor 11 Jahren

das reicht mir hoffentlich schon aus. ich hab ein wenig die orientierung verloren. deswegen scheitere ich schon an den simpelsten problemen. morgen hab ich vielleicht wieder mehr den kopf dafür frei.

edit: ach ich gebs glaub ich wirklich auf. der mensch hat ja schneller den aufrechten gang gelernt, als ich das mvc verstehe. hab den artikel gelesen aber den entsprechenden part nicht gefunden (oder nicht verstanden). ich werd mal erst den kopf frei machen gehen und dann probier ich es morgen nochmal.

edit2: habs scheinbar doch gefunden. hoffe ich zumindest mal.

danke für die geduld.