【问题标题】:VB.NET XSD Validation - Repeating Validation Error After Dealing with an Invalid FileVB.NET XSD 验证 - 处理无效文件后重复验证错误
【发布时间】:2015-10-28 14:11:48
【问题描述】:

我有一个 VB.NET 函数,它可以验证我的 XML 与架构,如果失败,则将失败输出到 Web 服务的 XML 响应。

我遇到的问题是,当我说格式正确的 XML 时,它会验证并成功,然后如果我发送不正确的 XML,验证器会正确说明它在验证中失败的位置。

如果我通过 Web 服务发送格式正确的正确 XML,我的验证检查函数将返回与检查前一个 XML 时相同的错误,几乎就像它“缓存”了问题一样。

谁能告诉我为什么会这样,我可以确认通过验证的 XML 是 100% 正确的,因为我查看过它并导出到我在 VB.NET 之外验证 XML 的另一个程序。

我的 ValidateXML 函数

Public Shared Function ValidateXML(xmlFilePath As String) As String

    Dim doc As New XmlDocument()
    doc.LoadXml(xmlFilePath)
    doc.Schemas.Add(Nothing, "http://www.fresh.co.uk/freshit/fresh_lead_schema.xsd")
    Dim errorBuilder As New XmlValidationErrorBuilder()
    doc.Validate(New ValidationEventHandler(AddressOf XmlValidationErrorBuilder.ValidationEventHandler))
    FIGCloud.errorsText = XmlValidationErrorBuilder.GetErrors()
    If FIGCloud.errorsText IsNot Nothing Then
        'Throw New Exception(errorsText)
        Return "Failed"
    Else
        Dim ReturnText As String = doc.InnerXml 'Returns XML Document as a String

        Return ReturnText
    End If

End Function

我从另一个来源获取的 XMLvalidationErrorBuilder 类

Public Class XmlValidationErrorBuilder
Public Shared _errors As New List(Of ValidationEventArgs)()

Public Shared Sub ValidationEventHandler(ByVal sender As Object, ByVal args As ValidationEventArgs)
    If args.Severity = XmlSeverityType.Error Then
        _errors.Add(args)
    End If
End Sub

Public Shared Function GetErrors() As String
    If _errors.Count <> 0 Then
        Dim builder As New StringBuilder()
        builder.Append("The following ")
        builder.Append(_errors.Count.ToString())
        builder.AppendLine(" error(s) were found while validating the XML document against the XSD:")
        For Each i As ValidationEventArgs In _errors
            builder.Append("* ")
            builder.AppendLine(i.Message)
        Next
        Return builder.ToString()
    Else
        Return Nothing
    End If
End Function
End Class

这是正确格式的 XML

<FreshLead>
<ContactDetails>
    <Title>Mr</Title>
    <FirstName>Joe</FirstName>
    <LastName>Bloggs</LastName>
    <EmailAddress>joe.bloggs@davisco.co.uk</EmailAddress>
    <HomeTel>01527 321 850</HomeTel>
    <MobileTel>07771111111</MobileTel>
    <DateOfBirth>21/05/1987</DateOfBirth>
    <Address>Joe Bloggs Road, Here</Address>
    <Postcode>B98 9PA</Postcode>
</ContactDetails>
<TradeDetails>
    <TradingName>Motor Trade Direct</TradingName>
    <TypeOfBus>Sales</TypeOfBus>
    <AgeOfBus>5 Years</AgeOfBus>
    <NoOfEmployees>5</NoOfEmployees>
    <NoOfDrivers>5</NoOfDrivers>
    <FullPartTime>Full-Time</FullPartTime>
    <BusPostcode>B98 9PA</BusPostcode>
    <BusPremises>No</BusPremises>
    <DemoCover>No</DemoCover>
    <PremIndem>10000</PremIndem>
    <RoadRisksIndem>20000</RoadRisksIndem>
    <VolXS>250</VolXS>
    <CoverStart>19/03/2015</CoverStart>
    <CoverReq>Comprehensive</CoverReq>
    <MTExperience>5 Years</MTExperience>
</TradeDetails>
<ProposerDetails>
    <UKResident>5 Years</UKResident>
    <FullUKLic>10 Years+</FullUKLic>
    <MT.NCB>2 Years</MT.NCB>
    <PC.NCB>2 Years</PC.NCB>
    <ClaimsConv5yr>No</ClaimsConv5yr>
</ProposerDetails>
<AddDetails>
    <CurrInsurer>Markerstudy</CurrInsurer>
    <BestQuote>2000.00</BestQuote>
    <ContactTime>Evening</ContactTime>
    <PrefContact>Email</PrefContact>
</AddDetails>

第一次通过 Web 服务发送时验证正确。

我刚刚更改了 2 个字段,以便它们在“Int16”字段中包含“字符串”,然后失败(应该如此)这些字段是“Indem”字段。

<FreshLead>
<ContactDetails>
    <Title>Mr</Title>
    <FirstName>Joe</FirstName>
    <LastName>Bloggs</LastName>
    <EmailAddress>joe.bloggs@davisco.co.uk</EmailAddress>
    <HomeTel>01527 321 850</HomeTel>
    <MobileTel>07771111111</MobileTel>
    <DateOfBirth>21/05/1987</DateOfBirth>
    <Address>Joe Bloggs Road, Here</Address>
    <Postcode>B98 9PA</Postcode>
</ContactDetails>
<TradeDetails>
    <TradingName>Motor Trade Direct</TradingName>
    <TypeOfBus>Sales</TypeOfBus>
    <AgeOfBus>5 Years</AgeOfBus>
    <NoOfEmployees>5</NoOfEmployees>
    <NoOfDrivers>5</NoOfDrivers>
    <FullPartTime>Full-Time</FullPartTime>
    <BusPostcode>B98 9PA</BusPostcode>
    <BusPremises>No</BusPremises>
    <DemoCover>No</DemoCover>
    <PremIndem>Over 10000</PremIndem>
    <RoadRisksIndem>Over 20000</RoadRisksIndem>
    <VolXS>250</VolXS>
    <CoverStart>19/03/2015</CoverStart>
    <CoverReq>Comprehensive</CoverReq>
    <MTExperience>5 Years</MTExperience>
</TradeDetails>
<ProposerDetails>
    <UKResident>5 Years</UKResident>
    <FullUKLic>10 Years+</FullUKLic>
    <MT.NCB>2 Years</MT.NCB>
    <PC.NCB>2 Years</PC.NCB>
    <ClaimsConv5yr>No</ClaimsConv5yr>
</ProposerDetails>
<AddDetails>
    <CurrInsurer>Markerstudy</CurrInsurer>
    <BestQuote>2000.00</BestQuote>
    <ContactTime>Evening</ContactTime>
    <PrefContact>Email</PrefContact>
</AddDetails>

但是当我将第一个工作示例传回时,它失败并出现与上述 XML 相同的错误,我已经在我的代码中提供了它验证的架构的位置,供任何希望使用工作示例和图形的人使用找出我哪里出错了。

谢谢

【问题讨论】:

    标签: xml vb.net validation xsd


    【解决方案1】:

    在我的original example 中,XmlValidationErrorBuilder 类的目的是提供有状态对象,其中每个对象都可用于存储单个操作的错误列表。每次执行验证时,它都会创建XmlValidationErrorBuilder 类的新实例,然后使用该本地对象来存储仅针对该操作的所有错误。验证操作完成后,将从中读取错误并将其丢弃。换句话说,每个验证操作都在其自己的本地 XmlValidationErrorBuilder 对象中保留了一个单独的错误列表。

    您的解决方案中的问题是您已将多个成员从实例成员更改为Shared 成员。例如,在我最初的示例中,XmlValidationErrorBuilder 类看起来像这样:

    Public Class XmlValidationErrorBuilder
        Private _errors As New List(Of ValidationEventArgs)()
    
        Public Sub ValidationEventHandler(ByVal sender As Object, ByVal args As ValidationEventArgs)
            If args.Severity = XmlSeverityType.Error Then
                _errors.Add(args)
            End If
        End Sub
    
        Public Function GetErrors() As String
            If _errors.Count <> 0 Then
                Dim builder As New StringBuilder()
                builder.Append("The following ")
                builder.Append(_errors.Count.ToString())
                builder.AppendLine(" error(s) were found while validating the XML document against the XSD:")
                For Each i As ValidationEventArgs In _errors
                    builder.Append("* ")
                    builder.AppendLine(i.Message)
                Next
                Return builder.ToString()
            Else
                Return Nothing
            End If
        End Sub
    End Class
    

    但在您的解决方案中,您将这两种方法和 _errors 字段更改为 Shared 成员。这意味着对错误生成器的所有调用将始终在同一个错误列表上工作,无论哪个验证操作正在使用它。

    另外,在我的原始示例中,我将委托传递给错误生成器的方法,如下所示:

    Dim errorBuilder As New XmlValidationErrorBuilder()
    doc.Validate(New ValidationEventHandler(AddressOf errorBuilder.ValidationEventHandler))
    

    如您所见,这会创建错误生成器的全新本地实例,并将对其方法的引用传递给Validate 方法。但是,在您的解决方案中,您将委托传递给 Shared 方法,如下所示:

    doc.Validate(New ValidationEventHandler(AddressOf XmlValidationErrorBuilder.ValidationEventHandler))
    

    因此,在您的解决方案中,每次调用 Validate 时,您都会将委托传递给相同的 Shared 方法,然后使用单个 Shared 字段来存储错误。每当您将字段声明为Shared 时,它实际上都会创建全局状态。 GlobalPrivate Shared 字段之间的唯一区别是可访问性级别,但只要它们是可访问的,它们仍然以相同的方式工作并服务于相同的目的。换句话说,将Private Shared 视为一个私有全局变量。因此,您可以说,您的解决方案之所以“好像在‘缓存’问题一样”,是因为它问题缓存在本质上是一个全局变量中。

    【讨论】:

    • 顶级人物,非常感谢您提供了非常丰富的答案,绝对教会了我一两件事! :)
    【解决方案2】:

    我最终将代码简化为以下内容

    Public Shared Function ValidateXMLv2(ByVal strXML As String, ByVal xsdPath As String) As Boolean
        Try
    
            Dim schema As XmlReader = XmlReader.Create(xsdPath)
            Dim document As XmlDocument = New XmlDocument()
            document.LoadXml(strXML)
            document.Schemas.Add("", schema)
    
            Dim eventHandler As ValidationEventHandler = New ValidationEventHandler(AddressOf ValidationEventHandler)
    
            document.Validate(AddressOf ValidationEventHandler)
    
            ' the following call to Validate succeeds.
            If FIGCloud.validationerrors = "" Then
                Return True
            Else
                Return False
            End If
    
        Catch ex As Exception
            MsgBox(ex.Message & Environment.NewLine & ex.StackTrace)
            Console.WriteLine(ex.Message & Environment.NewLine & ex.StackTrace)
            Throw
        End Try
    End Function
    
    Public Shared Sub ValidationEventHandler(ByVal sender As Object, ByVal e As ValidationEventArgs)
        FIGCloud.validationerrors += e.Message & Environment.NewLine
    End Sub
    

    然后在函数之外我将 FIGCloud.validationerrors 设置为 ""。

    【讨论】:

    • 抱歉耽搁了。我正在制定答案,但还没有机会完成并发布它。
    猜你喜欢
    • 1970-01-01
    • 2011-10-29
    • 2013-01-06
    • 2011-09-13
    • 2012-05-13
    • 2013-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多