VB.Net - Validating XML using DTD - asp.net

I've got myself a bit of a problem that I can't seem to figure out. I'm trying to programatically validate a generated XML file using a DTD using the following instructions from Microsoft (Validation Using a DTD with XmlReader
Here's my code thus far:
Private Sub BTN_ValidateXMLdoc_Click(sender As Object, e As EventArgs) Handles BTN_ValidateXMLdoc.Click
Dim JobNumber As String = Me.HNF_JobName.Value
Dim XMLPath As String = "N:\" & JobNumber & "\" & JobNumber & ".xml"
' Set the validation settings.
Dim settings As XmlReaderSettings = New XmlReaderSettings()
settings.DtdProcessing = DtdProcessing.Parse
settings.ValidationType = ValidationType.DTD
settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings
settings.ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema
AddHandler settings.ValidationEventHandler, AddressOf ValidationCallBack
' Create the XmlReader object.
Dim reader As XmlReader = XmlReader.Create(XMLPath, settings)
' Parse the file.
While reader.Read()
End While
End Sub
' Display any validation errors.
Private Shared Sub ValidationCallBack(sender As Object, e As ValidationEventArgs)
MsgBox(String.Format("Validation Error: {0}", e.Message), MsgBoxStyle.OkOnly)
End Sub
Now.... Here in lies my problem. For some reason, the ValidationCallBack EventHandler never gets fired. If an error occurs during the reader.Read() executing it throws an exception error.
Correct me if I'm wrong, but shouldn't the ValidationCallBack sub be called?
There are errors in the XML file but instead of it being handled by the event handler it's just throwing an exception....
I'm open to any ideas as to what may be going on here?

Your code implies the DTD is embedded in the XML document itself. While that's possible, it's unlikely to be what you want. I suspect your test is failing because there is no embedded DTD in the actual XML document.
If the DTD is indeed external to the XML document, you need to tell your XmlReaderSettings where to find it.
Remove the line
settings.ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema from your code.
Make sure there's a DOCTYPE in your XML document to specify the DTD. If there isn't, you may need to insert it before validation.
If you want to escape the overhead of downloading the DTD each time, you should create an XmlResolver. See Problem validation a XML file with a local DTD file in C# for an example.
Consider converting your DTD to an XML Schema. Schemas are more natural in XmlReader. DTDs don't understand XML namespaces.

Related

How to get PID (Process ID) of Word instance or Hwnd property?

I'm looking for a better way of coding for proper closing of WINWORD.EXE or word process in my application by getting its PID (Process ID) just like getting the PID in Excel.
This is my sample of getting the PID of an Excel using Hwnd property and GetProcessID class.
Imports System.Diagnostics
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Integer, ByRef lpdwProcessId As IntPtr) As IntPtr
Public Sub CreateNewFromTemplate_Excel()
' Create Excel Application, Workbook, and WorkSheets
Dim xlExcel As Excel.Application = New Excel.Application
'Getting the process ID of excel application
Dim processId As IntPtr = Nothing
GetWindowThreadProcessId(xlExcel.Hwnd, processId)
Dim excelProcess As Process = Process.GetProcessById(processId.ToInt32())
Dim blError As Boolean = False
Try
[Perform Excel generation here.]
' Make sure all objects are disposed
xlBook.Close()
xlExcel.Quit()
Catch ex As Exception
blError = True
If Not excelProcess.HasExited Then excelProcess.Kill() ' End the specific Excel Process ID if not yet closed.
Throw
Finally
If Not blError Then
If Not excelProcess.HasExited Then excelProcess.Kill() ' End the specific Excel Process ID if not yet closed.
End If
End Try
End Sub
This is my code for closing the Word Process/WINWORD.EXE but unfortunately, it's not working on the server side so I'm looking for a way and code to get the Word Process ID to properly close it.
Marshal.ReleaseComObject(rng)
Dim strFileName As String = comm.GenerateFilename(strUser_Id, strVPN) & ".docx"
' Save the document.
Dim filename As Object = Path.GetFullPath(strNewFilePath & strFileName)
newDoc.SaveAs(FileName:=filename)
' Close.
Dim save_changes As Object = False
newDoc.Close(save_changes)
WordApp.Quit(save_changes)
Marshal.ReleaseComObject(newDoc)
Marshal.ReleaseComObject(WordApp)
rng = Nothing
newDoc = Nothing
WordApp = Nothing
' Let GC know about it
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
' save the file to database
SaveFormat(filename, strUser_Id, strFamilyId.Trim, strVPN.Trim, DateTime.Now.ToString(), "application/vnd.ms-word", br_id, "doc")
If File.Exists(filename) Then
File.Delete(filename)
End If
Can anyone suggest what's the best way or the best practice for coding on how to get the PID or Hwnd property of Word instance. Thanks :)
What you are trying to do is probably not going to work as reliably as expected. I would strongly suggest that you switch to OpenXML or some other library if you need to process documents and spreadsheets from Server side.
I tend to use EPPlus which works very well and is almost the same code as VBA/Interop. http://epplus.codeplex.com/
I would read the following warnings and articles from Microsoft before proceeding:
All current versions of Microsoft Office were designed, tested, and configured to run as end-user products on a client workstation. They assume an interactive desktop and user profile. They do not provide the level of reentrancy or security that is necessary to meet the needs of server-side components that are designed to run unattended.
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
https://support.microsoft.com/en-us/help/257757/considerations-for-server-side-automation-of-office

ASP.NET Export - Response not ending?

I'm trying to export some text to a text file, and that part works fine. The trouble is that the text files get a bunch of HTML/.NET output at the bottom of them... In other words, it's like the response isn't ending and the page is trying to write the rest of the page. Here's the code:
Private Sub WriteData(ByRef Context As System.Web.HttpContext, Data As List(of String), fileName as String)
With Context.Response
.Clear()
.ClearHeaders()
.ClearContent()
.AddHeader("content-disposition", String.Format("attachment; filename={0}", fileName))
.ContentType = contentType
End With
For Each curValue in Data
Context.Response.Write(curValue)
Context.Response.Write(Environment.NewLine)
Next
Context.ApplicationInstance.CompleteRequest()
Context.Response.End()
End Sub
To call this, I just pass the HttpContext.Current and a list of data.
Does anybody know why this might happen? I'm not sure how to interpret it, and I've looked all over without much luck. My assumption was that the response wasn't actually ending with "Response.End()"...
Thanks,
Mike
My assumption is that you're using an .aspx to do this.
This would be a perfect scenario for a Generic Handler. Try using .ashx instead.
Here is a pretty simple tutorial if you need more info:
http://www.brainbell.com/tutorials/ASP/Generic_Handlers_%28ASHX_Files%29.html

Output XML as file in ASP.NET

I'm having difficulty sending an XML stream to the client browser. I've researched this considerably and everything looks right - moreover, similar code works in a previous version of this app. Any ideas what I could be doing wrong?
The following code throws no errors, but does not download a file on the client machine.
Public Shared Sub Export(ByVal source As DataTable)
Try
With Current.Response
Dim xml As String = CreateExcelXMLFromDataTable(source.DefaultView)
.Clear()
.Buffer = True
.ContentType = "application/vnd.ms-excel"
.AddHeader("Content-Disposition", String.Concat("attachment;filename=", "export.xlsx", ";"))
.AddHeader("Content-Length", xml.Length.ToString)
.Charset = ""
.Write(xml)
.Flush()
.Close()
End With
Catch ex As Exception
Console.WriteLine(ex.Message.ToString)
End Try
End Sub
Thanks!
If you are calling this function in an Ajax request it will not work. You have to cause a full postback to send the file to the client.
You can send the file without causing a full postback in the current page using an popup window (window.open) or an iframe with the URL of the download asp.net page, which will call the Export function.

Creating a dynamic graphic in asp.net

I am busy creating a control in asp.net. The control consists of some text and an image. The image will be used to display a graph. The control gets the data for the graph by reading it from a database. It seems I have two options to display the graph in the image box. First, I can create a jpg from the data and save the file on the server. I can then load this file into the image box. I think this would cause a problem if various users try to access the site at the same time, so I don't think it is a good option. The other options is to create a file called output, that outputs the graph like this: objBitmap.Save(Response.OutputStream, ImageFormat.Gif)
I can then display the image like this in my control: Image1.ImageUrl = "output.aspx"
The problem that I am facing is how do I get the data from my control to the output page? As far as I know it is too much data to pass as a parameter. If there is another better method of doing it, please let me know
Thanks
You can write the image content to the response of output.aspx. Something like this (taken from one of my existing GetImage pages:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim strFilename As String
strFilename = Request.QueryString("filename")
Dim strPath As String = AppSettings("ProxyImageSavePath") & strFilename
Response.Clear()
Response.ContentType = "image/jpeg"
If Not IO.File.Exists(strPath) Then
'erm
Response.Write("file not found")
Else
Response.WriteFile(strPath)
End If
Response.End()
End Sub
Edit: I've just realised this may not be the solution you're looking for; Your webserver should be able to cache this though.
You need handlers. See in this article, Protecting Your Images, section "Creating the ImageHandler HTTP Handler", you'll find the code how to write the handler, so it outputs an image. You don't need all, it's only an example.
You also need to register the handler in the web.config.
To reference it Image1.ImageUrl = "handler.ashx?graphdata=xxxx". Use QueryString to get the data source to generate the graph.

Having problem opening/writing to a text file in ASP.NET

I want to write some stats to a text file every time a person loads a page. But every once in awhile I am getting at 'Could Not Open File, Already in use' type of error. I can not 100% replicate this error it is very erratic. My code is
Public Sub WriteStats(ByVal ad_id As Integer)
Dim ad_date As String = Now.Year & Now.Month
Dim FILENAME As String = Server.MapPath("text/BoxedAds.txt")
Dim objStreamWriter As StreamWriter
objStreamWriter = File.AppendText(FILENAME)
objStreamWriter.WriteLine(ad_id & ";" & ad_date)
objStreamWriter.Close()
End Sub
My question is, how can I lock and unlock the file so I stop getting the erratic errors?
Thanks
If two or more requests hit your web server at roughly the same time, they will all try to open the same file. You will need to create unique file names for each request.
Public Sub WriteStats(ByVal ad_id As Integer)
Dim ad_date As String = Now.Year & Now.Month
Dim FILENAME As String = Server.MapPath("text/BoxedAds.txt")
Dim index As Integer
Using fs As New IO.FileStream(FILENAME, IO.FileMode.Append, IO.FileAccess.Write, IO.FileShare.ReadWrite), _
tl As New TextWriterTraceListener(fs)
index = Trace.Listeners.Add(tl)
Trace.WriteLine(ad_id & ";" & ad_date)
Trace.Listeners(index).Flush()
Trace.Flush()
End Using
Trace.Listeners.RemoveAt(index)
End Sub
Three important things here:
Use of IO.FileShare.ReadWrite to allow multiple writers on the file at once.
The Using statement to make sure the stream is closed immediately, even if an exception occurs. This will minimize collisions
The TextWriterTraceListener will create a temp file for your if it can't open the file you request, to make sure the message isn't lost.
You will have to handle the exception and build some handling to re-try writing to the file after a short random interval.
If you get too much contention then it might make more sense to log it to a table in a database and create a process to export to a file (if its still needed)
I haven't had any trouble with short info using:
File.AppendAllText(path, info);
Regarding the comment on it causing locks, from reflector it uses the same options explained very well by Joel. It does not use the trace writer, so it won't output to a temp file in the case of high load / large content causing trouble.
If the info is large, you really want separate files. For high load, I would go with Joel's suggestion and create a temp file, which can be alternatively done by catching the exception on File.AppendAllText, and using the same File.AppeandAllText with a unique filename.

Resources