Exporter - Http Error Response |
When you are exporting data to a Web URL and you are exporting multiple records using the Upload XML file containing all records or Upload Zipped XML file containing all records HttpPostMode it would be a shame for your remote code to error out midway though a batch update of your database.
Ideally upon a failed insert or update of a particular record you probably want to continue onto the next rather the page error out, you (or your developer) can code the page do this but then you are in a situation where there could have been errors but you don't know which records failed to insert/update, or there could be no error at all but you just don't know and are left wondering.
These are not ideal choices, either have the page error out on the first error meaning all records after the failed one will be skipped, or ignore any errors and continue onto the next but never knowing if or what errors occurred.
This is where the Http Error Response feature comes in, by checking a box in the job editor to let the application know your using this feature the job will always expect the remote page to return XML in a specific format.
The XML will contain any error information about any and all errors that occurred, this XML must be generated within the page and it is your or your web developers responsibility to generate the appropriate XML.
Internally, regardless of where its exporting date to, the application stores error details on any errors in a .NET dataset, the data from this dataset is saved to the file system in XML format so any error information that occurred during the last export is retained even when the application is closed and re-opened.
This is the XML that should be returned from your page, this returned XML becomes the jobs active error list, even when there are no errors you still must return the base XML for the dataset.
When there are no errors
the base XML that must be returned when no errors occurred in the page is:
<?xml version="1.0" standalone="yes"?> <ExportErrors />
When there are errors
when errors do occur in the page you should include the appropriate XML elements to return the error information to the application, an example of this XML would be:
<?xml version="1.0" standalone="yes"?> <ExportErrors> <ErrorLogs> <ErrorID>1</ErrorID> <ErrorTitle>Insert Failed</ErrorTitle> <ErrorMessage>no value provided for required parameter</ErrorMessage> <ExportData>Stockcode=WID1 Description=Widget 1</ExportData> </ErrorLogs> <ErrorLogs> <ErrorID>2</ErrorID> <ErrorTitle>Insert Failed</ErrorTitle> <ErrorMessage>no value provided for required parameter</ErrorMessage> <ExportData>Stockcode=WID2 Description=Widget 2</ExportData> </ErrorLogs> </ExportErrors>
the supported fields that can be returned are:
ASP.NET
If your page is an ASP.NET page generating the XML is very easy to do, simply create an instance of the DataSet class, add the table & columns then use the DataSet's GetXML method to return the XML.
VB.NET Example, code needed for XML error response is highlighted in yellow.
<%@ Page Language="VB" %> <%@ Import Namespace="System.IO" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.OleDb" %>
<script runat="server">
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim ExportErrors As New DataSet("ExportErrors") Dim TblErrors As DataTable = ExportErrors.Tables.Add("ErrorLogs")
Dim Col As DataColumn Col = TblErrors.Columns.Add("ErrorID", GetType(Int32)) Col.AutoIncrement = True Col.AutoIncrementSeed = 1 Col.AutoIncrementStep = 1
Col = TblErrors.Columns.Add("IsHtml", GetType(Boolean)) Col.DefaultValue = False
TblErrors.Columns.Add("ErrorTitle", GetType(String)) TblErrors.Columns.Add("ErrorMessage", GetType(String)) TblErrors.Columns.Add("ExportData", GetType(String)) TblErrors.Columns.Add("StackTrace", GetType(String))
If Request.Files.Count > 0 Then
Dim Ds As New DataSet Ds.ReadXml(Request.Files(0).InputStream)
Dim ConStrBuilder As New OleDbConnectionStringBuilder() ConStrBuilder.Provider = "Microsoft.Jet.OLEDB.4.0" ConStrBuilder.DataSource = Path.Combine(Request.PhysicalApplicationPath, "DemoData.mdb") ConStrBuilder.PersistSecurityInfo = False
Dim Conn As New OleDbConnection(ConStrBuilder.ConnectionString)
Conn.Open()
For Each Row As DataRow In Ds.Tables("STOCK").Rows Dim IsInsert As Boolean
Dim Cmd As New OleDbCommand("SELECT COUNT(ProductCode) FROM Products WHERE ProductCode=?", Conn) Cmd.Parameters.Add(New OleDbParameter("@ProductCode", Row("STOCK_CODE"))).DbType = DbType.String
Dim RecordExists As Boolean = Convert.ToInt32(Cmd.ExecuteScalar()) > 0
If RecordExists Then IsInsert = False Cmd.CommandText = "UPDATE Products SET Description=?, SalesPrice=?, Category=? WHERE ProductCode=?" Else IsInsert = True Cmd.CommandText = "INSERT INTO Products (Description, SalesPrice, Category, ProductCode) VALUES(?, ?, ?, ?)" End If
Cmd.Parameters.Clear()
Try Cmd.Parameters.Add(New OleDbParameter("@Description", Row("DESCRIPTION"))).DbType = DbType.String Cmd.Parameters.Add(New OleDbParameter("@SalesPrice", Row("SALES_PRICE"))).DbType = DbType.Double Cmd.Parameters.Add(New OleDbParameter("@Category", Row("STOCK_CAT"))).DbType = DbType.String Cmd.Parameters.Add(New OleDbParameter("@ProductCode", Row("STOCK_CODE"))).DbType = DbType.String Cmd.ExecuteNonQuery() Catch ex As Exception Dim NewErrorRow As DataRow = TblErrors.NewRow NewErrorRow("ErrorTitle") = IIf(IsInsert, "Insert Record Failed", "Update Record Failed") NewErrorRow("ErrorMessage") = ex.Message NewErrorRow("StackTrace") = ex.StackTrace NewErrorRow("ExportData") = "" For Each Column As DataColumn In Row.Table.Columns NewErrorRow("ExportData") &= Column.ColumnName & "=" & Row(Column.ColumnName) & vbCrLf Next TblErrors.Rows.Add(NewErrorRow) End Try
Next
Conn.Close()
End If
Response.Clear() Response.Write("<?xml version=""1.0"" standalone=""yes""?>" & vbCrLf & ExportErrors.GetXml()) Response.End()
End Sub </script>
C#.NET Example, code needed for XML error response is highlighted in yellow.
<%@ Page Language="C#" %> <%@ Import Namespace="System.IO" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.OleDb" %>
<script runat="server">
protected void Page_Load(object sender, System.EventArgs e) {
DataSet ExportErrors = new DataSet("ExportErrors"); DataTable TblErrors = ExportErrors.Tables.Add("ErrorLogs");
DataColumn Col = default(DataColumn); Col = TblErrors.Columns.Add("ErrorID", typeof(Int32)); Col.AutoIncrement = true; Col.AutoIncrementSeed = 1; Col.AutoIncrementStep = 1;
Col = TblErrors.Columns.Add("IsHtml", typeof(bool)); Col.DefaultValue = false;
TblErrors.Columns.Add("ErrorTitle", typeof(string)); TblErrors.Columns.Add("ErrorMessage", typeof(string)); TblErrors.Columns.Add("ExportData", typeof(string)); TblErrors.Columns.Add("StackTrace", typeof(string));
if (Request.Files.Count > 0) {
DataSet Ds = new DataSet(); Ds.ReadXml(Request.Files[0].InputStream);
OleDbConnectionStringBuilder ConStrBuilder = new OleDbConnectionStringBuilder(); ConStrBuilder.Provider = "Microsoft.Jet.OLEDB.4.0"; ConStrBuilder.DataSource = Path.Combine(Request.PhysicalApplicationPath, "DemoData.mdb"); ConStrBuilder.PersistSecurityInfo = false;
OleDbConnection Conn = new OleDbConnection(ConStrBuilder.ConnectionString);
Conn.Open();
foreach (DataRow Row in Ds.Tables["STOCK"].Rows) { bool IsInsert = false;
OleDbCommand Cmd = new OleDbCommand("SELECT COUNT(ProductCode) FROM Products WHERE ProductCode=?", Conn); Cmd.Parameters.Add(new OleDbParameter("@ProductCode", Row["STOCK_CODE"])).DbType = DbType.String;
bool RecordExists = Convert.ToInt32(Cmd.ExecuteScalar()) > 0;
if (RecordExists) { IsInsert = false; Cmd.CommandText = "UPDATE Products SET Description=?, SalesPrice=?, Category=? WHERE ProductCode=?"; } else { IsInsert = true; Cmd.CommandText = "INSERT INTO Products (Description, SalesPrice, Category, ProductCode) VALUES(?, ?, ?, ?)"; }
Cmd.Parameters.Clear();
try { Cmd.Parameters.Add(new OleDbParameter("@Description", Row["DESCRIPTION"])).DbType = DbType.String; Cmd.Parameters.Add(new OleDbParameter("@SalesPrice", Row["SALES_PRICE"])).DbType = DbType.Double; Cmd.Parameters.Add(new OleDbParameter("@Category", Row["STOCK_CAT"])).DbType = DbType.String; Cmd.Parameters.Add(new OleDbParameter("@ProductCode", Row["STOCK_CODE"])).DbType = DbType.String; Cmd.ExecuteNonQuery(); } catch (Exception ex) { DataRow NewErrorRow = TblErrors.NewRow(); NewErrorRow["ErrorTitle"] = (IsInsert ? "Insert Record Failed" : "Update Record Failed"); NewErrorRow["ErrorMessage"] = ex.Message; NewErrorRow["StackTrace"] = ex.StackTrace; NewErrorRow["ExportData"] = ""; foreach (DataColumn Column in Row.Table.Columns) { NewErrorRow["ExportData"] += Column.ColumnName + "=" + Row[Column.ColumnName] + "\n"; } TblErrors.Rows.Add(NewErrorRow); } }
Conn.Close(); }
Response.Clear(); Response.Write("<?xml version=\"1.0\" standalone=\"yes\"?>" + "\n" + ExportErrors.GetXml()); Response.End();
}
</script>
|