2010-11-24 38 views
2

J'ai un code C# qui effectue un POST sur un service Web OData, ce qui entraîne l'insertion d'un enregistrement dans une base de données. S'il existe une exception, telle qu'une violation de clé primaire, je souhaite capturer et consigner le message d'erreur. Cependant, le message est contenu dans XML. Voici mon gestionnaire d'exception:Comment analyser internalexception à partir de la réponse WebException

catch (WebException ex) 
{ 
    if (ex.Status == WebExceptionStatus.ProtocolError) 
    { 
     string responseText = string.Empty; 

     using (Stream responseStream = ((HttpWebResponse)ex.Response).GetResponseStream()) 
     { 
      using (StreamReader streamReader = new StreamReader(responseStream)) 
      { 
       responseText = streamReader.ReadToEnd(); 
      } 
     } 
     Debug.WriteLine(responseText); 
     return responseText; 
    } 
    else 
    { 
     Debug.WriteLine(ex.Message.ToString()); 
     return ex.Message.ToString(); 
    } 
} 

Voici ce que je reçois dans responseText:

<?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">An error occurred while processing this request.</message> 
    <innererror> 
    <message>An error occurred while updating the entries. See the inner exception for details.</message> 
    <type>System.Data.UpdateException</type> 
    <stacktrace> at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)&#xD; 
    at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)&#xD; 
    at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)&#xD; 
    at System.Data.Services.Providers.ObjectContextServiceProvider.SaveChanges()&#xD; 
    at System.Data.Services.DataService 1.HandleNonBatchRequest(RequestDescription description)&#xD; 
    at System.Data.Services.DataService 1.HandleRequest()</stacktrace> 
    <internalexception> 
     <message>Violation of PRIMARY KEY constraint 'PK_Customer_CustomerId'. Cannot insert duplicate key in object 'VertexBilling.Customer'.&#xD; 
The statement has been terminated.</message> 
     <type>System.Data.SqlClient.SqlException</type> 
     <stacktrace> at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)&#xD; 
    at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)&#xD; 
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()&#xD; 
    at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)&#xD; 
    at System.Data.SqlClient.SqlDataReader.ConsumeMetaData()&#xD; 
    at System.Data.SqlClient.SqlDataReader.get_MetaData()&#xD; 
    at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)&#xD; 
    at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)&#xD; 
    at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)&#xD; 
    at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)&#xD; 
    at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)&#xD; 
    at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)&#xD; 
    at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)&#xD; 
    at System.Data.Mapping.Update.Internal.DynamicUpdateCommand.Execute(UpdateTranslator translator, EntityConnection connection, Dictionary 2 identifierValues, List 1 generatedValues)&#xD; 
    at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)</stacktrace> 
    </internalexception> 
    </innererror> 
</error> 

je dois faire passer le message de la internalexception de la innererror. Quelle est la meilleure façon de faire cela?

+0

BTW, ex.Message est déjà une chaîne. Vous n'avez pas besoin d'utiliser '.ToString()' –

Répondre

0

Le plus facile est probablement d'utiliser une expression régulière comme suit pour extraire la chaîne entre "<message>" et "</message>":

<message>(.+)</message> 

Ce n'est pas extrêmement robuste, et ce n'est pas dans l'esprit de XML, mais cela devrait fonctionner à moins que le XML varie beaucoup. Et si vous n'utilisez pas déjà les outils XML dans votre application, vous ne souhaitez pas nécessairement les afficher uniquement pour extraire cette chaîne.

+0

Le problème est qu'il y a un dans dans le que je veux, et un dans le que je n'ai pas. –

+0

@Mark: bon point. C'est pourquoi vous ne devriez pas utiliser regexps pour traiter XML, à moins que ce soit un cas * très * simple. :-) Essayez la réponse de l'autre gars, sauf changer le "//" initial en "/" pour une meilleure efficacité. – LarsH

1

Vous devez utiliser boîte à outils XML, vous l'avez déjà à votre disposition dans .net et il élimine les problèmes d'ambiguïté lors du traitement de XML sous forme de texte (son cauchemar en attente de se produire, dans le fichier XML ci-dessus, vous avez deux noeuds de message)

  1. chaîne de charge à XmlDocument
  2. utilisation // erreur/innerError/internalexception/message XPath pour extraire le nœud nécessaire

vous pouvez également construire un petit morceau de code qui extrait/désérialiser le innerException en un Exceptio n instance et peut le réutiliser pour d'autres appels.

Si vous ne savez pas comment faire cela, hurleurs, je vais faire quelque chose.

+0

J'ai essayé de convertir en utilisant "docNav = new XPathDocument (responseText);" mais je reçois un "caractères illégaux dans le chemin" ArgumentException. J'ai essayé de remplacer les guillemets simples par String.Empty d'abord, mais cela n'a pas aidé. Si vous pouviez ramasser quelque chose de grossier pour convertir ce désordre en une exception .Net que je pourrais lancer, ce serait très utile. –

+0

en fait, avant de faire cela, quelle lib avez-vous utilisé pour accéder à odata? Avez-vous utilisé ceux de http://odata.codeplex.com/? – mmix

+0

J'utilise tout ce qui est dans VS 2010/.Net 4. –