Dieser Artikel wurde maschinell übersetzt.

Datenpunkte

Umgang mit Entity Framework-Validierungen in WCF Data Services

Julie Lerman

Julie LermanIch schreibe diese Spalte auf den Fersen von der Microsoft BUILD-Konferenz.Der Kern aller von der Aufregung bei BUILD war natürlich, die neue Metro UI für Windows 8, die über die neue Windows Common Language Runtime (WinRT) sitzt.Wenn Sie eine Daten-Geek sind, Sie möglicherweise bereits geschaut haben um zu sehen, welche Möglichkeiten gibt es für die Bereitstellung von Daten zu "Metro-Stil" apps.In dieser Anfang Vorschau können Sie Daten aus Dateispeicher oder aus dem Web bereitstellen.Wenn Sie mit relationalen Daten interagieren möchten, sind Web-basierte Optionen XML oder JSON über HTTP, Steckdosen und Dienstleistungen.Auf der Vorderseite Dienstleistungen bieten U-Bahn-Stil apps-Client-Bibliotheken für die Nutzung von imparte, was bedeutet, dass Sie arbeiten heute mit imparte durch Microsoft keine Erfahrung.NET Framework, Silverlight oder andere Client-Bibliotheken einen großen Vorteil geben Ihnen wenn Sie bereit sind, imparte in Metro-Stil Anwendungen verbrauchen.

In diesem Sinne werde ich diese Spalte auf die Zusammenarbeit mit imparte widmen.Das Entity Framework (EF)-Release, das erste Code und die DbContext enthält eingeführt, eine neue API für Validierung.Ich werde Ihnen zeigen, wie zur Nutzung der integrierten Server-seitige Validierung beim EF Code ersten Modell als imparte durch WCF Data Services ausgesetzt ist.

Validierung API Grundlagen

Sie können bereits mit dem Konfigurieren der Attribute wie erforderlich oder MaxLength-Klasseneigenschaften mit Anmerkungen für Daten oder die Fluent-API vertraut sein.Diese Attribute können automatisch durch die neue API für Validierung überprüft werden."Entity Framework 4.1 Validation", einen Artikel im MSDN Data Developer Center (msdn.microsoft.com/data/gg193959), zeigt dies, wie und wie Sie Regeln mit der IValidatableObject-Schnittstelle und die ValidateEntity-Methode.Während Sie bereits Anmerkungen für Daten und IValidatable überprüfen werden möglicherweise­Objekt auf der Client-Seite ihrer Regeln auch auf der Serverseite zusammen mit ValidateEntity Logik, die Sie hinzugefügt haben geprüft werden können.Alternativ können Sie auch eine Validierung bei Bedarf in Ihrem Servercode auslösen.

Hier zum Beispiel ist eine einfache Person-Klasse, die zwei Anmerkungen für Daten verwendet (die erste angegeben, dass die LastName-Eigenschaft erforderlich ist, und die andere eine maximale Länge für das Feld der IdentityCard):

public class Person
{
  public int PersonId { get; set; }
  public string FirstName { get; set; }
  [Required]
  public string LastName { get; set; }
  [MaxLength(10)]
  public string IdentityCardNumber { get; set; }
}

Standardmäßig wird EF Validierung durchführen, wenn SaveChanges aufgerufen wird. Wenn eine der folgenden Regeln fehlschlägt, löst EF ein Sys­Tem.Da­ta.Ent­Ity.DbEntityValidationException — die hat eine interessanten Struktur. Jeder Validierungsfehler in eine DbValidationError beschrieben wird, und DbValidationErrors sind nach Objektinstanz in Gruppen von EntityValidationErrors gruppiert.

Z. B. Abbildung 1 zeigt eine DbEntityValidationException, die ausgelöst werden würde, wenn EF Probleme bei der Überprüfung mit zwei verschiedenen Person Instanzen erkannt. Das erste EntityValidationErrors-Objekt enthält eine Reihe von DbValidationErrors für eine einzelne Person-Instanz gab zwei Fehler: keine LastName und die IdentityCard hatte zu viele Zeichen. Die zweite Person-Instanz kein einziges Problem gehabt; Deshalb gibt es nur ein DbValidationError in das zweite EntityValidationErrors-Objekt.

DbEntityValidationException Contains Grouped Sets of Errors
Abbildung 1 DbEntityValidationException enthält gruppierten Störungen

In der MSDN Data Developer Center-Artikel erwähnt, ich zeigte die Ausnahme wird an ein Modell-Ansicht -­Controller (MVC) Anwendung, die wusste, wie zu entdecken und zu den spezifischen Fehler anzeigen.

In einer verteilten Anwendung könnte jedoch die Fehler nicht machen es zurück zu der Client-Seite verwendet und so leicht gemeldet werden. Während die obersten Ebene Ausnahme zurückgegeben werden kann, kann die Client-Anwendung wie in einer DbEntityValidationException zu die Fehlern finden zu bohren keine Ahnung haben. Mit vielen apps haben Sie nicht sogar Zugriff auf die System.Data.Entity-Namespace und daher keine Kenntnis von der DbEntityValidationException.

Problematischer ist wie WCF Data Services Ausnahmen standardmäßig überträgt. Auf der Clientseite erhalten Sie nur eine Meldung "Fehler während der Verarbeitung dieser Anforderung." Aber die kritische Phrase hier ist "by Default." Sie können anpassen, Ihre WCF Data Services zum Analysieren von DbEntityValidationExceptions und nützliche Fehlerinformationen an den Client zurückgegeben. Dies ist, was ich für den Rest dieses Artikels konzentrieren werde.

WCF Service Datenergebnisse ausblenden Validierungsfehler standardmäßig

Mein Modell befindet sich in einer Datenschicht DbContext ich PersonModelContext genannt habe:

public class PersonModelContext : DbContext
  {
    public DbSet<Person> People { get; set; }
  }

Ich habe einen einfachen Datendienst, der den Person-Typ aus diesem Kontext für Lesen und Schreiben von Macht verfügbar:

public class DataService : DataService<PersonModelContext>
{
  public static void InitializeService(DataServiceConfiguration config)
  {
    config.SetEntitySetAccessRule("People", EntitySetRights.All);
    config.DataServiceBehavior.MaxProtocolVersion =
      DataServiceProtocolVersion.V3;
  }
}

Weil ich Code ersten verwende, würde ich habe zu tun, einige Optimierungen zu WCF Data Services zu arbeiten. Anstelle des Zwickens, habe ich die Microsoft ersetzt.NET Framework 4 System.Data.Services und System.Data.ClientServices mit den Microsoft.Data.Services und Microsoft.Data.ClientServices Bibliotheken ab März 2011 WCF Daten Services CTP (finden Sie unter bit.ly/mTI69m), hat die Optimierungen erbaut. Das ist, warum die DataServiceProtocolVersion V3 festgelegt ist.

Schließlich bin ich den Dienst mit einer einfachen Konsole-Anwendung verwenden, die die folgende Methode verwendet, um eine Person einzufügen:

private static void InsertPersonNoLastName()
{
  var person = new Person
  {
    FirstName = "Julie",
    IdentityCardNumber="123456789",
  };
  var context = new PersonModelContext
   (new Uri("http://localhost:43447/DataService.svc"));
 context.AddToPeople(person);
 context.SaveChanges();
}

Beachten Sie, dass ich es versäumt haben, die LastName-Eigenschaft festgelegt. Da LastName konfiguriert wird erforderlich sein, die EF löst ein sich­Tion an den Datendienst, aber die Konsolenanwendung erhalten nur eine DataServiceRequestException mit der Meldung beschriebenen früheren ("trat ein Fehler während der Verarbeitung dieser Anforderung."). Wenn Sie einen in die innere Ausnahme Drilldown, werden Sie feststellen, dass es die gleiche Nachricht und keine zusätzlichen Details enthält.

WCF Data Services muss eine Einstellung lassen Sie zurück Ausnahmemeldungen mit mehr Details per der InitializeService-Methode Folgendes hinzufügen:

#if DEBUG
  config.UseVerboseErrors = true;
#endif

Jetzt die innere Nachricht (enthalten in der XML-Antwort vom Dienst) Ihnen sagt: "Validierung fehlgeschlagen für eine oder mehrere Entitäten. Siehe 'EntityValidationErrors'-Eigenschaft für weitere Details." Aber leider, die EntityValidationErrors nicht wieder mit der Ausnahme übergeben bekommen. Damit wissen Sie, dass die Validierung API ein oder mehrere Probleme gefunden, aber Sie nicht, etwas mehr über den Fehler ermitteln können. Beachten Sie, dass ich UseVerboseErrors in eine Compiler-Direktive eingebunden. UseVerboseErrors sollte nur für das Debuggen verwendet werden – Sie wollen es nicht im Produktionscode.

Überschreiben der HandleException-Methode

WCF Data Services stellt eine virtuelle (Overrideable) Methode namens HandleException. Auf diese Weise können Sie alle Ausnahmen, die im Dienst geschieht erfassen, analysieren und erstellen Sie Ihre eigenen DataServiceException an den Aufrufer zurückgegeben. Es ist in dieser Methode, dass Sie heraus alle Validierungsfehler und können aussagekräftigere Informationen an die aufrufende Anwendung zurück. Die Signatur der Methode ist:

protected override void HandleException(HandleExceptionArgs args)

HandleExceptionArgs-Typ hat eine Reihe von Eigenschaften: Ausnahme, ResponseContentType, EsponseStatusCode, Antwort­geschrieben, UseVerboseErrors

Von Interesse für mich ist die Exception-Eigenschaft. Dies ist wo Sie erfassen und identifizieren Ausnahmen ausgelöst, von der Validierung-API-DbEntityValidationException. Sie können auch alle anderen Arten von Fehlern hier behandeln, aber ich werde auf Suchen und analysieren die Validierungsausnahmen konzentrieren. Ich habe den System.Data.Entity.Validation-Namespace in meiner mit Anweisungen am Anfang der Klasse, so dass ich zu stark nicht geben Sie die Ausnahme.

Ich beginne mit der Annahme, dass nur eine einzelne Entität überprüft wird, und deshalb bin ich nur für die erste Entität Abfragen­ValidationErrors in der Ausnahme enthaltenen, siehe Abbildung 2. Wenn Sie den Dienst für mehrere Objekte überprüfen möchten, achten Sie darauf, den SaveChangesOptions.Batch-Parameter verwenden, wenn Sie SaveChanges aufrufen. Sonst, nur ein Objekt gespeichert und zu einem Zeitpunkt überprüft wird und wenn Sie einen Fehler, werden keine Objekte mehr gespeichert werden oder überprüft.

Abbildung 2 erstellen eine nützlichere Ausnahmemeldung

protected override void HandleException(HandleExceptionArgs args)
{
  if (args.Exception.GetType()==
    typeof(DbEntityValidationException))
  {
    var ex=args.Exception as DbEntityValidationException;
    var errors = ex.EntityValidationErrors.First().ValidationErrors.ToList();
    var errorMessage=new StringBuilder();
    foreach (System.Data.Entity.Validation.DbValidationError e in errors)
    {
      errorMessage.AppendLine(e.ErrorMessage);
    }
    args.Exception = new DataServiceException(500, errorMessage.ToString());
  }
}

Was passiert in dieser Methode ist, dass ich zuerst überprüfen, ob die Ausnahme ist der Typ von der Validierung-API ausgelöst. Wenn es ist, ziehe ich die Ausnahme in der Variable "ex" Als nächstes Abfragen ich für eine Liste aller in der ersten Reihe von EntityValidationErrors in der Ausnahme enthaltenen DbValidationErrors. Dann habe ich eine neue Fehlermeldung-Zeichenfolge mithilfe der ErrorMessage-Eigenschaft jedes EntityValidationError aufzubauen und diese Zeichenfolge zurück an die aufrufende Anwendung in einem neuen übergeben­ServiceException. EntityValidationError hat andere Eigenschaften, aber es baut sich ein mit dem Namen der Eigenschaft und die Bestätigung Tücke in die ErrorMessage Restlicher Wortlaut der Fehlermeldung. Mit Code ersten können Sie eine benutzerdefinierte Fehlermeldung angeben, aber ich bin glücklich mit den Standardeinstellungen für die Zwecke dieser Demo. In diesem Beispiel wird die Meldung "das LastName-Feld erforderlich ist." Beachten Sie, dass der Konstruktor für DataServiceException verfügt über eine Reihe von Überladungen. Ich bin es einfach zu halten indem nur die "internal Server Error" 500 Code und eine Zeichenfolge mit der Nachricht, die ich weiterleiten möchten.

Analyse der neuen Ausnahme auf dem Client

Nun, auf der Clientseite, noch eine Ausnahme erhalten Sie, die sagt, "während der Verarbeitung dieser Anforderung ist ein Fehler aufgetreten", aber dieses Mal die innere Ausnahme die Meldung enthält "das LastName-Feld ist erforderlich."

Aber es ist keine einfache Zeichenfolge. Die Nachricht von einem DataServiceRequestException ist in eine HTTP-Antwort formatiert, da die Anforderung über HTTP hergestellt wird:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<error xmlns=
  "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <code></code>
  <message xml:lang="en-US">The LastName field is required.&#xD;
  </message>
</error>

Eine der Überladungen für die DataServiceException ich im Dienst konstruierte können Sie benutzerdefinierte Fehlercodes einfügen. Wenn ich hatte, die verwendet wird, würde der benutzerdefinierte Code in der <code> auftauchen Element des Fehlers. Wenn Sie den Dienst aus einer Webanwendung aufrufen, möglicherweise Sie die HTTP-Antwort direkt in der Benutzeroberfläche angezeigt. Andernfalls sollten Sie wahrscheinlich es analysiert, so dass Sie die Ausnahme mit was auch immer Sie für den Umgang mit Fehlern in Ihrer Anwendung verwendeten Muster behandeln können.

Ich bin mit LINQ to XML, um die Nachricht zu extrahieren und dann kann ich es in meiner Konsolenanwendung anzeigen. Ich fordere SaveChanges in einen Try/Catch-Block, analysieren und Anzeigen der Fehlermeldung (siehe Abbildung 3). Abbildung 4 zeigt die Ergebnisse der clientseitigen Ausnahme.

Abbildung 3 Analyse und zeigt die vom Dienst zurückgegebenen Fehlermeldung

try
{
  context.SaveChanges();
}
catch (Exception ex)
{
  var sr = new StringReader(ex.InnerException.Message);
  XElement root = XElement.Load(sr);
  IEnumerable<XElement> message =
    from el in root.Elements()
    where el.Name.LocalName == "message"
    select el;
  foreach (XElement el in message)
    Console.WriteLine(el.Value);
  Console.ReadKey();
}

Parsed Error Message Displayed in the Client
Abbildung 4 analysiert im Client angezeigt Fehlermeldung

Jetzt werde ich einen anderen-Schraubenschlüssel in die InsertPerson-Methode auslösen. Zusätzlich zu vernachlässigen die LastName-Eigenschaft, werde ich zu viele Zeichen in die Identität­Card-Eigenschaft. Denken Sie daran, dass diese Eigenschaft so konfiguriert wurde, dass eine MaxLength von 10 haben:

var person = new Person
{
  FirstName = "Julie",
  IdentityCardNumber="123456789ABCDE"
};

Jetzt die HandleException-Methode zwei DataValidation finden­Störungen für die Person-Instanz, die der Dienst hat versucht zu aktualisieren. Der StringBuilder einer zwei-Line-Nachricht — eine Beschreibung des Problems und die LastName-Eigenschaft einen anderen zu erklären, das Problem mit der IdentityCard-Eigenschaft.

In der Konsolenanwendung wird dies als eine einzelne Nachricht in der Ausnahme angesehen werden:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<error xmlns=
  "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <code></code>
  <message xml:lang="en-US">The field IdentityCardNumber must be a string or array type with a maximum length of '10'.&#xD;
    The LastName field is required.&#xD;
  </message>
</error>

Die LINQ to XML-Parser wird dann weiterleiten die Meldung an die Konsole, wie in gezeigt Abbildung 5.

Console App Displaying Multiple Errors for a Single Entity
Abbildung 5 Console App mehrere Fehler für eine einzelne Entität anzeigen

Profitieren Sie von Validierung, selbst wenn getrennt

Sie haben nun gesehen, wie, mit einem einfachen Satz von Anforderungen mithilfe von Code erste Datenanmerkungen angewendet, Sie können erfassen und analysieren EF Validierungsausnahmen, an einen Client zurücksenden, und, auf der Clientseite, analysieren die Ausnahme über HTTP zurückgegeben. Egal ob Sie arbeiten mit Regeln für die Gültigkeitsprüfung über Eigenschaft Konfigurationen oder komplexere Regeln, die Sie angeben können, mit IValidationObject oder durch Überschreiben der ValidateEntity-Methode angewendet, die EF immer zurück DbEntity­ValidationExceptions. Sie wissen, wie durch jene analysieren und die Logik, um Platz für mehrere Objekte Fehlermeldungen enthält weitere Details zu erhöhen, und behandeln sie auf dem Server oder auf dem Client nach Bedarf von der Anwendung erweitern können.

Da WCF Data Services imparte zurückgibt, können Sie diese Dienste nutzen und nutzen die Validierung heute und Praxis, so dass Sie bereit zu tun, das gleiche mit U-Bahn-Stil Zukunftstechnologien sein können.

Julie Lerman ist ein Microsoft MVP.NET Mentor und Berater lebt in den Hügeln von Vermont. Finden Sie ihre Präsentation auf Datenzugriff und anderen Microsoft.NET-Themen auf Benutzergruppen und Konferenzen auf der ganzen Welt. She Blogs auf thedatafarm.com/blog und ist der Autor des Buches hoch gelobten "Programming Entity Framework" (O' Reilly Media, 2010). Folgen sie auf Twitter bei twitter.com/julielerman.

Dank der folgenden technischen Experten für die Überprüfung dieses Artikels: Mike Flasko