How to read in an XML file asynchronously? - c#

I am writing a Windows Form Application for data post-processing. I have a panel where I allow for files to be dragged and dropped. The XML files will be quite large (enough to slow the UI down). Therefore I would like to read the file in asynchronously. So far for this part of the app I have two methods:
namespace myApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void DragDropPanel_DragEnter(object sender, DragEventArgs e)
{
// Trigger the Drag Drop Event
e.Effect = DragDropEffects.Copy;
}
private async void DragDropPanel_DragDrop(object sender, DarEventArgs e)
{
// Identifiers used are:
string[] filePaths = (string[])e.Data.GetData(DataFormats.FileDrop);
string filePath = filePaths[0],
fileName = System.IO.Path.GetFileName(filePath);
// Read in the file asynchronously
XmlReader reader = XmlReader.Create(filePath);
//reader.Settings.Async = true; // ** (SECOND ERROR) ** \\
while (await reader.ReadAsync()) // ** (FIRST ERROR) ** \\
{
Console.WriteLine("testing...");
}
// Do other things...
}
}
}
Now when I drag and drop the XML file I get the following error:
System.InvalidOperationException:
Set XmlReaderSettings.Async to true if you want to use Async Methods.
this error occurs because of the line I labeled with FIRST ERROR. I attempt to fix this by uncommenting the line above it which I have labeled with SECOND ERROR. Now when I drag and drop I get the error:
System.Xml.Xml.XmlException:
The XmlReaderSettings.Async property is read only and cannot be set
So I go to the MS Docs for the XmlReaderSettings.Async property and it says:
You must set this value to true when you create a new XmlReader instance if you want to use asynchronous XmlReader methods on that instance.
Which then gives the reason why the SECOND ERROR occurs. However, I cannot get this to work. Any tips?

You need to Create the XmlReader with the proper settings.
XmlReaderSettings settings = new XmlReaderSettings
{
Async = true
};
XmlReader reader = XmlReader.Create(filePath, settings);
References:
https://msdn.microsoft.com/en-us/library/ms162474(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.xml.xmlreadersettings(v=vs.110).aspx

Related

C# Invalid FORMATETC structure when using GetTextAsync

I'm trying to make a progam which automatically searches for the word I copied in a file and then replaces that word in the clipboard with the line on which it was found in my file. I successfully setup an Eventhandler to see when the clipboard changes. I'm now trying to implement a way of reading my file.
After trying to use the StringReader the Exception is thrown:
Invalid FORMATETC structure occurred.
This is my code right now:
public partial class MainWindow : System.Windows.Window
{
string line;
string currentClipboardContent;
string expectedClipboardContent;
string vocabularygerman = Properties.Resources.vocabularygerman;
string vocabularyfrench = Properties.Resources.vocabularyfrench;
int lineNumber;
public MainWindow()
{
InitializeComponent();
Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += new EventHandler<object>(this.TrackClipboardChanges_EventHandler);
}
private async void TrackClipboardChanges_EventHandler(object sender, object e)
{
DataPackageView dataPackageView = Windows.ApplicationModel.DataTransfer.Clipboard.GetContent();
if (dataPackageView.Contains(StandardDataFormats.Text))
{
currentClipboardContent = await dataPackageView.GetTextAsync();
if (expectedClipboardContent != currentClipboardContent)
{
Thread.Sleep(500);
using (var reader = new StringReader(vocabularygerman))
{
lineNumber = 0;
while ((line = reader.ReadLine()) != null)
{
lineNumber++;
if (line.Contains(currentClipboardContent))
{
System.Windows.Forms.Clipboard.SetDataObject(lineNumber);
break;
}
}
}
expectedClipboardContent = System.Windows.Forms.Clipboard.GetText();
}
}
}
Everything worked fine until I tried to use the StringReader. I'm thinking of ditching the stringreader altogether and using a streamreader, but I am not able to use my vocabularygerman.txt file in my resources.
StringReader does not implement the IDataObject interface so SetDataObject method wont like that as it depends on that interface being present.
Try
Clipboard.SetText(lineNumber.ToString())
instead if you need the StringReader.
PS: use await for async calls

CefSharp Search Engine Implamentation

I am working on a cefsharp based browser and i am trying to implement a search engine into the browser, but the code I have tried docent work, it doesn't really have any errors but when i star the project and type something i the text field nothing happens and it dosent load the search engine i entered into the code, the only time the textbox loads anything is when a url is typed.
This is the code used in the browser that docent work
private void LoadUrl(string url)
{
if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
{
WebUI.Load(url);
}
else
{
var searchUrl = "https://www.google.com/search?q=" + WebUtility.HtmlEncode(url);
WebUI.Load(searchUrl);
}
}
i have also tried
void LoadURl(String url)
{
if (url.StartsWith("http"))
{
WebUI.Load(url);
}
else
{
WebUI.Load(url);
}
}
i was also suggested to try
private void LoadUrl(string url)
{
if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
{
WebUI.LoadUrl(url);
}
else
{
var searchUrl = "https://www.google.com/search?q=" + Uri.EscapeDataString(url);
WebUI.LoadUrl(searchUrl);
}
}
We have here really few Information on how your code works. But what I notice is that you use WebUtility.HtmlEncode for the search query. WebUtility has also a WebUtility.UrlEncode Method, that how I understand your question makes more sense it the context. This is the documentation for the method: https://learn.microsoft.com/de-de/dotnet/api/system.net.webutility.urlencode
The Url you are generating is invalid. You need to use Uri.EscapeDataString to convert the url param into a string that can be appended to a url.
// For this example we check if a well formed absolute Uri was provided
// and load that Url, all others will be loaded using the search engine
// e.g. https://github.com will load directly, attempting to load
// github.com will load the search engine with github.com as the query.
//
if (Uri.IsWellFormedUriString(url, UriKind.Absolute))
{
chromiumWebBrowser.LoadUrl(url);
}
else
{
var searchUrl = "https://www.google.com/search?q=" + Uri.EscapeDataString(url);
chromiumWebBrowser.LoadUrl(searchUrl);
}
nothing happens and it dosent load the search engine
You need to subscribe to the LoadError event to get actual error messages. It's up to you to display errors to the user. The following is a basic example:
chromiumWebBrowser.LoadError += OnChromiumWebBrowserLoadError;
private void OnChromiumWebBrowserLoadError(object sender, LoadErrorEventArgs e)
{
//Actions that trigger a download will raise an aborted error.
//Aborted is generally safe to ignore
if (e.ErrorCode == CefErrorCode.Aborted)
{
return;
}
var errorHtml = string.Format("<html><body><h2>Failed to load URL {0} with error {1} ({2}).</h2></body></html>",
e.FailedUrl, e.ErrorText, e.ErrorCode);
_ = e.Browser.SetMainFrameDocumentContentAsync(errorHtml);
}
For testing purposes you can also copy and paste the searchUrl string you've generated and try loading it in Chrome to see what happens, you should also get an error.

gsapi_init_with_args is made: -100

I'm trying to build a PostScript to PDF Converter using Ghostscript.Net.
The Args that GetArgs return, are the ones I usually use to call gswin32c.exe and they work fine.
But every time i call Process, i get an error Saying "An error occured when call to 'gsapi_init_with_args' is made: -100". Googling that error didn't bring anything up so I thought I might ask here.
Are there differnet arguments to consider when calling the .dll directly with Ghostscript.net? Or did I made a mistake somewhere else?
Here's my class:
public class PdfConverter
{
#region Private Fields
private List<GhostscriptVersionInfo> _Versions = GhostscriptVersionInfo.GetInstalledVersions(GhostscriptLicense.GPL | GhostscriptLicense.AFPL | GhostscriptLicense.Artifex);
#endregion
#region Private Properties
private GhostscriptVersionInfo Version { get; set; }
#endregion
#region Construction
public PdfConverter()
{
Version = GhostscriptVersionInfo.GetLastInstalledVersion();
}
#endregion
#region Public Members
public bool ConvertToPdf(DirectoryInfo dir)
{
var d = dir;
if(!d.Exists)
return false;
var postScriptFiles = d.GetFiles("*.ps");
var pdfFiles = postScriptFiles.Select(psf => new FileInfo(Path.ChangeExtension(psf.FullName, ".pdf")));
foreach(var file in postScriptFiles) {
//ThreadPool.QueueUserWorkItem(new WaitCallback((o) => {
Process(file, new FileInfo(Path.ChangeExtension(file.FullName, ".pdf")));
//}));
}
pdfFiles.ForEach(pdf => pdf?.Refresh());
return pdfFiles.All(pdf => pdf.Exists);
}
#endregion
#region Private Helpers
private void Process(FileInfo inputFile, FileInfo outputFile)
{
Console.WriteLine($"Converting {inputFile} to {outputFile}");
var proc = new GhostscriptProcessor(Version, true);
proc.Process(GetArgs(inputFile, outputFile).ToArray(), new ConsoleStdIO(true, true, true));
}
private IEnumerable<string> GetArgs(FileInfo inputFile, FileInfo outputFile)
{
return new [] {
$"-q ",
$"-sDEVICE=pdfwrite",
$"-dSAFER",
$"-dNOPAUSE",
$"-dBATCH",
$"-sPAPERSIZE=a4",
$"-dEmbedAllFonts=true",
$"-dAutoRotatePages=/None",
$"-sOutputFile=\"{outputFile.FullName}\"",
$"-dCompatibilityLevel#1.4",
$"-c .setpdfwrite",
$"-f \"{inputFile.FullName}\""
};
}
#endregion
}
Edit:
I forgot to mention: To implement it i had to make my own GhostsdcriptStdIO class. I admit that I'm not entirely sure if I did this right. Although it does get instanciated without exceptions, and override StdOut(...) get's called, and the output is written to the console as expected. override void StdError(...) get's called as well. And also written to the console as expeted.
The Output of the error btw is:
"**** Could not open the file "c:\temp\test.pdf""
"**** Unable to open the initial device, quitting."
Here's my ConsoleStdIO class:
public class ConsoleStdIO : Ghostscript.NET.GhostscriptStdIO
{
#region Construction
public ConsoleStdIO(bool handleStdIn, bool handleStdOut, bool handleStdError) : base(handleStdIn, handleStdOut, handleStdError) { }
#endregion
#region Overrides
public override void StdError(string error)
{
var foo = Encoding.Default.GetBytes(error);
var lenght = foo.Length;
using (var err = Console.OpenStandardError()) {
if(err.CanWrite)
err.Write(foo, 0, lenght);
}
}
public override void StdIn(out string input, int count)
{
byte[] bytes = new byte[0];
using(var stdInput = Console.OpenStandardInput()) {
stdInput.Read(bytes, 0, count);
}
input = Encoding.Default.GetString(bytes);
}
public override void StdOut(string output)
{
var foo = Encoding.Default.GetBytes(output);
var lenght = foo.Length;
using (var err = Console.OpenStandardError()) {
if(err.CanWrite)
err.Write(foo, 0, lenght);
}
}
#endregion
}
Again: doing the same operation with the exact same files and arguments using gswin32c.exe works fine.
Happy Hacking
Error -100 is gs_error_Fatal, which means 'something catastrophic went wrong'. Its an indication that the program failed to start up properly and we can't tell why. The back channel may contain more information.
And indeed, the back channel tells you what's wrong:
**** Could not open the file "c:\temp\test.pdf
**** Unable to open the initial device, quitting.
Ghostscript is unable to open the output file, which means it can't open the pdfwrite device (because that requires an output file) so it aborts the operation.
There could be a number of reasons why Ghostscript can't open the output file. The first thing I'd do is trim down the number of arguments;
You don't want -q (quiet) when you are trying to debug a problem, you want all the information you can get.
I'd remove -dSAFER at least to start with, because that prevents Ghostscript accessing directories outside the current working directory and certain 'special' ones. It may well prevent you accessing the temp directory.
You don't need to set EmbedAllFonts when its the same value as the default.
You could drop the CompatibilityLevel (and note that you've used a # there instead of an =) switch, and the AutoRotatePages while getting this to work.
The "-c .setpdfwrite -f" string has been pointless for years but people still keep using it. All that does these days is slow down the start of processing, ditch it.
Finally you can try changing the backslash ('\') characters to forward slash ('/') in case your string handling is messing that up, or use double backslashes (I'd use the forward slash myself).
You should also check that c:\test\temp.pdf doesn't exist, or if it does exist is not read-only or already open in a different application.
So I solved the problem...
After taking KenS' advice I could run the application without Ghostscript (not Ghostscript.NET) giving me any errors. But it did not produce an actual PDF File.
So KenS's answer did not quite solve the problem, but since 'less is more' and since he took the time to talk to me on IRC to verify that my args in itself were correct, I'll give the answer points nonetheless.
What actually solved my was the following:
Here my original GetArgs(...)
private IEnumerable<string> GetArgs(FileInfo inputFile, FileInfo outputFile)
{
return new [] {
$"-sDEVICE=pdfwrite",
$"-dNOPAUSE",
$"-dBATCH",
$"-sPAPERSIZE=a4",
#"-sFONTPATH=" + System.Environment.GetFolderPath(System.Environment.SpecialFolder.Fonts),
$"-sOutputFile={outputFile.FullName}",
$"{inputFile.FullName}",
};
}
Someone in #csharp pointed out to me, that in c, the first argument is always the name of the command. So he suggested to just put "gs" as the first argument (as a dummy) and try... And that's what actually solved my problem.
So this is how the working GetArgs(...) looks:
private IEnumerable<string> GetArgs(FileInfo inputFile, FileInfo outputFile)
{
return new [] {
$"gs",
$"-sDEVICE=pdfwrite",
$"-dNOPAUSE",
$"-dBATCH",
$"-sPAPERSIZE=a4",
#"-sFONTPATH=" + System.Environment.GetFolderPath(System.Environment.SpecialFolder.Fonts),
$"-sOutputFile={outputFile.FullName}",
$"{inputFile.FullName}",
};
}

Deserializing SSIS data from DTSX file

I am trying to deserialize XML from SSIS DTSX files. I have found the XSD files which I think are needed, found here: https://msdn.microsoft.com/en-us/library/gg587628%28v=sql.105%29.aspx. I have used xsd2code plugin for VS to create objects from the XSDs.
The problem: I am able to deserialize into these objects, but almost no actual data gets pulled in from the DTSX files.
In the code below, I have placed a break point at the WriteLine() command in Parse_XML() and looked at the contents of the two ExecutableTypePackage objects (executables and exec). Both have the same contents:
The property ExecutableType gets set to "SSIS.Package.3"
The Property collection (List<ExecutableTypePackageProperty>) has one element; its Name property is set to "PackageFormatVersion" and Value property is set to "6".
That's all. While those values are correct, there's a lot more data in the file that's not getting pulled in. But I get no warnings nor exceptions.
Admittedly, I don't have much experience with XML, and using the serialization methods is very new to me, but I have used them for validating the XML structure of report files (RDL), and never ran across any such issues. I have been beating my head against the wall for 2 full days on this now, and I am not making any progress. I have searched every which way I can think of for answers on this, but I don't find anyone else having this problem.
string file = null;
public Form1()
{
InitializeComponent();
}
private void Run_btn_Click(object sender, EventArgs e)
{
Parse_XML();
MessageBox.Show("Done!");
}
private void Parse_XML()
{
TextReader tr = new StreamReader(file);
XmlSerializer serializer = new XmlSerializer(typeof(DTSX.ExecutableTypePackage));
DTSX.ExecutableTypePackage executables = (DTSX.ExecutableTypePackage)serializer.Deserialize(tr);
DTSX.ExecutableTypePackage exec = DTSX.ExecutableTypePackage.Deserialize(File.ReadAllText(file));
MessageBox.Show(String.Format("Found {0} executables in package.", exec.Executable.Count));
Console.WriteLine("Done loading root object.");
}
private void File_btn_Click(object sender, EventArgs e)
{
int text_size = -1;
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
file = openFileDialog1.FileName;
try
{
string text = File.ReadAllText(file);
text_size = text.Length;
File_txtbx.Text = file;
}
catch (IOException)
{
}
}
Console.WriteLine(file);
Console.WriteLine(text_size);
Console.WriteLine(result);
}

Unity XmlDocument function not always working

Is there anything to consider when using XmlDocument function in unity3d?
I'm having this weird problem: When the function which uses XmlDocument is called from Awake() or OnGUI() the document is edited successfully. But when it's called from inside a button event, event tough I get a well edited string before saving the document, it's not able to modify the document itself.
Function that edits the file (sometimes):
public static void addTestProfile () {
string path = Application.dataPath + "/Documents/Profiles.xml";
Hashtable tempTable = new Hashtable();
tempTable.Add("user", "chuck II");
tempTable.Add("url", "funny");
tempTable.Add("passwrod", "1234asdf");
General.StoreProfile(tempTable, path);
}
public static void StoreProfile(Hashtable profile, string path) {
Debug.Log("profile to store name: " + profile["password"]);
XmlDocument doc = new XmlDocument();
doc.Load(profilesPath);
XmlElement element = doc.CreateElement("Profile");
XmlElement innerElement1 = doc.CreateElement("user");
innerElement1.InnerText = profile["user"] as string;
element.AppendChild(innerElement1);
XmlElement innerElement2 = doc.CreateElement("url");
innerElement2.InnerText = profile["url"] as string;
element.AppendChild(innerElement2);
XmlElement innerElement3 = doc.CreateElement("password");
innerElement3.InnerText = profile["password"] as string;
element.AppendChild(innerElement3);
doc.DocumentElement.AppendChild(element);
doc.Save(profilesPath);
Debug.Log(doc.InnerXml);
}
I created a new project just to test this problem, the file is not edited when called just before calling Application.loadLevel();
Here it works well and the file itself is edited:
void OnGUI () {
General.addTestProfile(); // General is the singleton class that contains the function implementation
}
But some how this is not working:
// GUI Save btn
if (GUI.Button(new Rect(255, 20, 60, 35), "Add")) {
General.addTestProfile(); // General is the singleton class that contains the function implementation
Application.LoadLevel(0);
}
When I print the resultant string right before the save() xmlDocument function, it shows the new item but somehow the xml file remains the same.
Am I missing something important maybe related to the execution order? Something like timeout?
this is just a wild guess, but could this work?
// PSEUDOCODE
bool pressed
function OnGUI()
if GUI.Button then
pressed = true
end if
if pressed then
addTestProfile();
end if
end function
I took help from this link: http://answers.unity3d.com/questions/9538/new-to-unity-3d-gui-button-help-needed-please
When it jumped back to scene 1, it was re-writing the original file.
"Debug.Log" sucks! , this instruction never printed the second call to createProfilesFile() function. So just one line was missing:
if (System.IO.File.Exists(profilesPath)) return;
Here the createProfilesFile() function:
public static void CreateProfilesFile (string path) {
Debug.Log("create init"); // This line wasn't called the second time ...
if (System.IO.File.Exists(path)) return;
// Create a new file specified path
XmlTextWriter textWriter = new XmlTextWriter(path,null);
// Opens the document
textWriter.WriteStartDocument();
// Write comments
textWriter.WriteComment("This document contains the profiles that have been created.");
textWriter.WriteStartElement("Profiles");
textWriter.WriteStartElement("Profile");
textWriter.WriteStartElement("user");
textWriter.WriteString("foo user");
textWriter.WriteEndElement();
textWriter.WriteStartElement("url");
textWriter.WriteString("foo url");
textWriter.WriteEndElement();
textWriter.WriteStartElement("password");
textWriter.WriteString("foo password");
textWriter.WriteEndElement();
textWriter.WriteEndElement();
textWriter.WriteEndElement();
// Ends the document.
textWriter.WriteEndDocument();
// close writer
textWriter.Close();
}

Categories

Resources