Помогите мне решить проблему с тайм-аутом API проверки W3C - PullRequest
1 голос
/ 21 марта 2009

Я использую сервис проверки W3C, чтобы проверить, что текст, который я ввожу в TextBox, является допустимой разметкой.

Valid

Это почти работает. Но при определенных условиях мой ввод приводит к ошибке, а затем к бесконечным исключениям тайм-аута. Я должен закрыть заново открыть программу, чтобы она снова заработала.

Пожалуйста, просмотрите мой код и помогите мне решить эту проблему.

У меня довольно простое приложение WPF с TextBox и StatusBar. StatusBar обновляется по мере ввода, чтобы сообщить мне, является ли моя напечатанная разметка действительной или нет. Чтобы служба не работала, проверки выполняются только через одну секунду или более без нажатия клавиш.

Неверно http://img9.imageshack.us/img9/3788/invalidr.gif

В нем StatusBar может отображать: «Validating ...», «Valid», «Invalid» или - если оно было - сообщение об исключении.

Проверка http://img7.imageshack.us/img7/5842/validating.gif

Следующее успешно подтверждено:

XHTML Input

<?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 http://img11.imageshack.us/img11/3066/namecannotbegin.gif

Если проверка два раза подряд не проходит, то кажется, что я не могу просто исправить свои теги абзаца и продолжить как обычно. По какой-то причине каждая последующая проверка завершается неудачей с этим исключением:

Время ожидания истекло

Тайм-аут http://img21.imageshack.us/img21/7600/timedout.gif

Это очень странно.

Извините, что опубликовал весь мой проект, но я не знаю, откуда возникла моя проблема. Это может быть мои потоки, связь с веб-сервисом, обработка исключений ... Я просто не могу найти это. Правильно ли я закрываю свои StreamWriter, HttpWebRequest и ResponseStreams?

* * Тысяча сорок-девять * 1050 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 голосов
/ 21 марта 2009

На первый взгляд, я бы рекомендовал не пытаться проверять каждый раз, когда текст изменяется. Это может и будет немного подавляющим. Я боюсь, что это то, что здесь происходит. Хорошая работа по созданию Async, так как это предотвратит его блокировку, но я также подозреваю, что она скрывает вашу проблему.

Попробуйте, чтобы событие TextChanged установило флаг для выполнения валидатора, а затем просто запустите метод DoWork в тесном цикле (ish), проверяющем этот флаг. Это позволит ему завершить время и не запутаться. Чтобы получить правильные данные, может потребоваться секунда или две, но не должны блокироваться.

Удачи.

...