1

W3C 検証サービスを使用して、TextBox に入力したテキストが有効なマークアップであることを確認しています。

有効

それはほとんど働いています。しかし、特定の条件下では、私の入力はエラーになり、無限のタイムアウト例外が発生します。プログラムを再び機能させるには、プログラムを閉じて再度開く必要があります。

私のコードを一瞥して、この問題を解決するのを手伝ってください。

TextBox と StatusBar を備えた非常に単純な WPF アプリケーションを作成しました。入力すると StatusBar が更新され、入力したマークアップが有効か無効かがわかります。私がサービスを叩いていないように、検証はキーストロークなしで 1 秒以上経過した後にのみ行われます。

無効 http://img9.imageshack.us/img9/3788/invalidr.gif

StatusBar には、"Validating..."、"Valid"、"Invalid"、または (存在する場合) 例外のメッセージが表示される場合があります。

検証中 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 を処理しようとしているときに次の例外が発生します。

名前を「"」文字で始めることはできません。16 進値は 0x22 です。行 86、位置 40。

XML 例外 http://img11.imageshack.us/img11/3066/namecannotbegin.gif

検証がそのように 2 回続けて失敗した場合、段落タグを修正して通常どおり続行することはできないようです。何らかの理由で、後続の各検証は次の例外で失敗します。

操作がタイムアウトしました

タイムアウト http://img21.imageshack.us/img21/7600/timedout.gif

これは非常に奇妙です。

プロジェクト全体を投稿して申し訳ありませんが、問題の原因がわかりません。それは私のスレッド化、Web サービス通信、例外処理かもしれません...私はそれを見つけることができないようです. StreamWriter、HttpWebRequest、および ResponseStreams を正しく閉じていますか?

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>

ビジュアルベーシック

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

助けてくれてありがとう!

4

1 に答える 1

0

一見すると、テキストが変更されるたびに検証を試みないことをお勧めします。それは少し圧倒される可能性があり、実際にそうです。それがここで起こっていることだと私は恐れています。非同期にすることでブロックを防ぐことができますが、問題が隠れているのではないかと思います。

TextChangedイベントにフラグを設定してバリデーターを実行してから、DoWorkメソッドをタイトな(ish)ループで実行してそのフラグをチェックしてみてください。それはそれが完了する時間を与え、混乱することはありません。正しいデータを取得するのに1、2秒かかる場合がありますが、ロックアップしないでください。

幸運を。

于 2009-03-20T23:15:20.247 に答える