VB.NET XSD 验证 - 处理无效文件后重复验证错误

VB.NET XSD Validation - Repeating Validation Error After Dealing with an Invalid File

我有一个 VB.NET 函数来验证我的 XML 与模式的对比,如果它失败,则将失败输出到 Web 服务的 XML 响应。

我遇到的问题是当我说格式正确时 XML 它验证并成功,然后如果我发送不正确 XML 验证器正确指出验证失败的地方。

如果我然后通过 Web 服务发送正确的 XML,我的验证检查函数 returns 将出现与检查前一个 XML 时遇到的相同错误,几乎就像是 'caching' 问题。

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

我的验证XML 函数

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 Class 我从另一个来源获取

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' 字段中包含 'Strings',然后失败(应该如此)这些字段是 '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,我已经在我的代码中提供了它所验证的架构的位置,供任何希望这样做的人使用使用一个工作示例并找出我哪里出错了。

谢谢

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

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 设置为 "".

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

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

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 视为私有全局变量。因此,您可以说您的解决方案之所以起作用 "as if its 'caching' the issue," 是因为它 正在缓存 本质上是全局变量的问题。