请帮我解决我的W3C验证API超时问题

时间:2009-03-20 22:59:49

标签: .net web-services multithreading backgroundworker w3c

我正在使用W3C验证服务来检查我在TextBox中输入的文本是否为有效标记。

Valid

它几乎正常工作。但是,在特定条件下,我的输入会导致错误,然后导致无限超时异常。我必须关闭重新打开程序才能让它再次运行。

请浏览我的代码并帮助我解决此问题。

我有一个非常简单的WPF应用程序,带有TextBox和StatusBar。 StatusBar会在我输入时更新,以便告诉我输入的标记是否有效。因此,我没有敲定服务,只有在经过一秒钟或更长时间后才会进行验证,而且没有按键。

Invalid http://img9.imageshack.us/img9/3788/invalidr.gif

StatusBar可能会显示:“验证...”,“有效”,“无效”,或者 - 如果有的话 - 是一个例外的消息。

Validating http://img7.imageshack.us/img7/5842/validating.gif

以下验证成功:

XHTML输入

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml:lang="en">
    <head>
        <title>Test</title>
    </head>
    <body>
        <h1>Test</h1>
        <p>This is a test</p>
    </body>
</html>

如果我像<p>This is a test</那样破坏了我的段落,那么在尝试处理响应XML时会出现此异常:

  

名称不能以“”开头   字符,十六进制值0x22。   第86行,第40位。

XML Exception http://img11.imageshack.us/img11/3066/namecannotbegin.gif

如果验证连续两次失败,那么我似乎无法修复我的段落标记并继续正常运行。由于某种原因,每个后续验证都会失败并出现此异常:

  

操作已超时

Timed Out http://img21.imageshack.us/img21/7600/timedout.gif

这很奇怪。

我很抱歉发布我的整个项目,但我不知道我的问题来自哪里。它可能是我的线程,Web服务通信,异常处理......我似乎无法找到它。我是否正确关闭了StreamWriter,HttpWebRequest和ResponseStream?

XAML

<Window x:Class="Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="W3C Validation"
        Height="300"
        Width="300"
        Name="Window1">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0"
                 TextWrapping="Wrap"
                 AcceptsReturn="True"
                 VerticalScrollBarVisibility="Visible"
                 FontFamily="Consolas"
                 TextChanged="TextBox_TextChanged" />
        <StatusBar Grid.Row="1">
            <StatusBarItem>
                <TextBlock x:Name="TextBlockResult" />
            </StatusBarItem>
        </StatusBar>
    </Grid>
</Window>

Visual Basic

Imports System.ComponentModel
Imports <xmlns:env="http://www.w3.org/2003/05/soap-envelope">
Imports <xmlns:m="http://www.w3.org/2005/10/markup-validator">

Class Window1

    Private WithEvents Worker As BackgroundWorker
    Private _WorkerArgument As String

    Private Sub Window1_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
        InitializeWorker()
    End Sub

    Private Sub InitializeWorker()
        Worker = New BackgroundWorker
        Worker.WorkerSupportsCancellation = True
        AddHandler Worker.DoWork, AddressOf Worker_DoWork
        AddHandler Worker.RunWorkerCompleted, AddressOf Worker_RunWorkerCompleted
    End Sub

    Private Sub TextBox_TextChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.TextChangedEventArgs)
        TryToWork(DirectCast(sender, TextBox).Text)
    End Sub

    Sub TryToWork(ByVal Argument As String)

        If _WorkerArgument IsNot Nothing Then
            _WorkerArgument = Argument
            Exit Sub
        End If

        If Not Worker.IsBusy Then
            TextBlockResult.Text = "Validating..."
            Worker.RunWorkerAsync(Argument)
            Exit Sub
        End If

        _WorkerArgument = Argument
        Worker.CancelAsync()
        Dim RetryTimer As New Windows.Threading.DispatcherTimer
        AddHandler RetryTimer.Tick, AddressOf RetryTicker
        RetryTimer.Interval = New TimeSpan(1) '1 tick'
        RetryTimer.Start()

    End Sub

    Sub RetryTicker(ByVal sender As Object, ByVal e As System.EventArgs)
        If Not Worker.IsBusy Then
            DirectCast(sender, Windows.Threading.DispatcherTimer).Stop()
            TextBlockResult.Text = "Validating..."
            Worker.RunWorkerAsync(_WorkerArgument)
            _WorkerArgument = Nothing
        End If
    End Sub

    Private Sub Worker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        'wait for one second'
        Dim StartTime As DateTime = DateTime.Now()
        While Now.Subtract(StartTime) < New TimeSpan(0, 0, 1)
            If DirectCast(sender, BackgroundWorker).CancellationPending Then
                e.Cancel = True
                Exit Sub
            End If
            System.Threading.Thread.Sleep(New TimeSpan(0, 0, 0, 0, 100)) 'tenth of a second'
        End While
        'then validate'
        e.Result = Validate(DirectCast(e.Argument, String))
    End Sub

    Private Function Validate(ByVal Text As String) As String
        Try
            Dim Url As String = "http://validator.w3.org/check"
            Dim Post As String = "&fragment=" + Web.HttpUtility.UrlEncode(Text) + "&output=soap12"
            Dim ResponseDocument As XDocument = XDocument.Load(New Xml.XmlTextReader(Communicate(Url, Post)))
            If ResponseDocument.Root.<env:Body>.<m:markupvalidationresponse>.<m:validity>.Value = "true" Then
                Return "Valid"
            Else
                Return "Invalid"
            End If
        Catch ex As Exception
            Return ex.Message
        End Try
    End Function

    Private Function Communicate(ByVal Url As String, ByVal Post As String) As System.IO.Stream
        Dim Writer As System.IO.StreamWriter = Nothing
        Dim Request As System.Net.HttpWebRequest = System.Net.WebRequest.Create(Url)
        Request.Method = "POST"
        Request.ContentLength = Post.Length
        Request.ContentType = "application/x-www-form-urlencoded"
        Request.Timeout = 2000 '2 seconds'
        Try
            Writer = New System.IO.StreamWriter(Request.GetRequestStream())
            Writer.Write(Post)
        Catch
        Finally
            If Not Writer Is Nothing Then
                Writer.Close()
            End If
        End Try
        Return Request.GetResponse.GetResponseStream()
    End Function

    Private Sub Worker_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
        If Not e.Cancelled Then
            TextBlockResult.Text = DirectCast(e.Result, String)
        End If
    End Sub

End Class

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

乍一看,我建议每次更改文本时都不要尝试验证。这可能,而且确实有点压倒性的。我担心这就是发生的事情。使其成为异步的好工作将阻止它阻止,但我也怀疑它隐藏了你的问题。

尝试让TextChanged事件设置一个标志来执行验证器,然后让DoWork方法在紧密(ish)循环中运行,检查该标志。这将使它有时间完成而不会混淆。可能需要一两秒才能获得正确的数据,但不应该锁定。

祝你好运。