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

时间:2015-10-28 14:11:48

标签: xml vb.net validation xsd

我有一个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服务发送时,这会正确验证。

我刚刚更改了两个字段,以便它们包含&#39;字符串&#39;在&#39; Int16&#39;字段然后失败(因为它应该)这些字段是&#39; Indem&#39;字段。

<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相同的错误时,我已经在我的代码中提供了它验证的模式的位置,对于任何希望使用工作示例和数字的人来说在我出错的地方。

由于

2 个答案:

答案 0 :(得分:3)

在我的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视为私有全局变量。所以,你可以说你的解决方案之所以“好像它'缓存'这个问题”,是因为它正在缓存本质上是一个全局变量的问题。

答案 1 :(得分:0)

我最终将代码简化为以下

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设置为“”。