【发布时间】:2009-03-20 22:59:49
【问题描述】:
我正在使用 W3C 验证服务来检查我在 TextBox 中键入的文本是否是有效的标记。
它几乎可以工作了。但是,在特定条件下,我的输入会导致错误,然后是无休止的超时异常。我必须关闭重新打开程序才能让它再次运行。
请查看我的代码并帮助我解决这个问题。
我有一个非常简单的 WPF 应用程序,带有一个 TextBox 和一个 StatusBar。当我输入时,状态栏会更新,让我知道我输入的标记是否有效。因此,我不会对服务进行重击,只有在没有击键的情况下经过一秒或更长时间后才会进行验证。
Invalid http://img9.imageshack.us/img9/3788/invalidr.gif
StatusBar 可能会显示:“Validating...”、“Valid”、“Invalid”,或者——如果有的话——异常消息。
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 和 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>
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
感谢您的帮助!
【问题讨论】:
-
不用担心发布这么多代码。我们喜欢代码。发现代码中的错误比从模糊的描述中猜测更容易。
-
您使用的是本地安装的服务副本 (validator.w3.org/docs/install.html) 还是托管在 w3.org 上的服务?
-
我正在使用托管在 w3.org 的服务。
标签: .net web-services multithreading backgroundworker w3c