OFX File parser in C# - c#

I am looking for an OFX file parser library in C#. I have search the web but there seems to be none. Does anyone know of any good quality C# OFX file parser. I need to process some bank statements files which are in OFX format.
Update
I have managed to find a C# library for parsing OFX parser.
Here is the link ofx sharp. This codebase seems to be the best case to startup my solution.

I tried to use the ofx sharp library, but realised it doesn't work is the file is not valid XML ... it seems to parse but has empty values ...
I made a change in the OFXDocumentParser.cs where I first fix the file to become valid XML and then let the parser continue. Not sure if you experienced the same issue?
Inside of the method:
private string SGMLToXML(string file)
I added a few lines first to take file to newfile and then let the SqmlReader process that after the following code:
string newfile = ParseHeader(file);
newfile = SGMLToXMLFixer.Fix_SONRS(newfile);
newfile = SGMLToXMLFixer.Fix_STMTTRNRS(newfile);
newfile = SGMLToXMLFixer.Fix_CCSTMTTRNRS(newfile);
//reader.InputStream = new StringReader(ParseHeader(file));
reader.InputStream = new StringReader(newfile);
SGMLToXMLFixer is new class I added into the OFXSharp library. It basically scans all the tags that open and verifies it has a closing tag too.
namespace OFXSharp
{
public static class SGMLToXMLFixer
{
public static string Fix_SONRS(string original)
{ .... }
public static string Fix_STMTTRNRS(string original)
{ .... }
public static string Fix_CCSTMTTRNRS(string original)
{ .... }
private static string Fix_Transactions(string file, string transactionTag, int lastIdx, out int lastIdx_new)
{ .... }
private static string Fix_Transactions_Recursive(string file_modified, int lastIdx, out int lastIdx_new)
{ .... }
}
}

Try http://www.codeproject.com/KB/aspnet/Ofx_to_DataSet.aspx. The code uses Framework 3.5 and transforms an ofx into a dataset, this may help with what you're trying to do.

Related

Read value from excel

I have a problem that I can't solve. I need to pass a value from one Selenium test to another. And the writing part works just fine. I saves the value to an excel file. The problem appears when I try to read it. I have a class which should be able to read the cell, but it won't.
Excel.cs
using System.IO;
using OfficeOpenXml;
using excel = Microsoft.Office.Interop.Excel;
namespace Core
{
public sealed class Excel
{
#region Private Properties
private static string InputPath { get; } = ConfigSettingProvider.InputSourcePath;
private static string OutputPath { get; } = ConfigSettingProvider.OutputSourcePath;
#endregion Private Properties
public static string ReadCell (int sheet, int x, int y) // (sheet, row, column)
{
FileInfo existingFile = new FileInfo("..\\..\\..\\Property\\Input\\data1.xlsx");
using (ExcelPackage package = new ExcelPackage(existingFile))
{
return package.Workbook.Worksheets[sheet].Cells[x, y].Value.ToString();
}
}
}
}
And then in Test Fixture class I am trying to call ReadCell method:
var cellPolicyNo = Excel.ReadCell(1, 1, 1);
But it simply won't even enter to read it. Immediately the exception is thrown: "The type initializer for 'Core.Excel' threw an exception". at Core.Excel.ReadCell(Int32 sheet, Int32 x, Int32 y)
What am I doing wrong? What should I change?
Thank you
You might want to take a look at this thread to see if it helps with answering your question.
How to read single Excel cell value
This is the more common way of reading from an excel file that is more reliable. There are also ways of doing it through OLEDB but that is for reading the entire excel file. Hopefully this helps as it is similar to code I have used in the past to read data from excel files.
It appears to be a static constructor problem, see here:
https://stackoverflow.com/questions/4398334/the-type-initializer-for-myclass-threw-an-exception#:~:text=The%20type%20initializer%20for%20%27CSMessageUtility.,-CSDetails%27%20threw%20an&text=means%20that%20the%20static%20constructor,static%20members%20of%20that%20class.
Btw, it might perhaps help to try a different toolkit, namely EPPlus (the last free version is 4.5.3.3). I've tried to read cells also with Excel Interop but it didn't work out so well. With EPPlus you can use LINQ on the range objects of Excel.

Can I use OpenXmlPowerTools in a Flask App

Is it possible to use a C#/.Net based library like OpenXmlPowerTools in a Flask/Python 3 web-app?
My research tells me that I might be able to via a wrapper? or creating a microservice?
Would like to know your thoughts.
You can do this with pythonnet. I've created a sample class in C# that references the OpenXmlPowerTools and DocumentFormat.OpenXml assemblies and provides two methods:
using OpenXmlPowerTools;
using DocumentFormat.OpenXml.Packaging;
namespace CodeSnippets.OpenXmlWrapper
{
public class OpenXmlPowerToolsWrapper
{
public static string GetMainDocumentPart(string path)
{
using WordprocessingDocument wordDocument = WordprocessingDocument.Open(path, true);
return wordDocument.MainDocumentPart.GetXElement().ToString();
}
public static string FinishReview(string path)
{
using WordprocessingDocument wordDocument = WordprocessingDocument.Open(path, true);
var settings = new SimplifyMarkupSettings
{
AcceptRevisions = true,
RemoveComments = true
};
MarkupSimplifier.SimplifyMarkup(wordDocument, settings);
return wordDocument.MainDocumentPart.GetXElement().ToString();
}
}
}
The corresponding sample Python client looks like this, noting that clr is a module provided by pythonnet:
import clr
import shutil
clr.AddReference(
r"..\CodeSnippets.OpenXmlWrapper\bin\x64\Debug\net471\CodeSnippets.OpenXmlWrapper")
from CodeSnippets.OpenXmlWrapper import OpenXmlPowerToolsWrapper
wrapper = OpenXmlPowerToolsWrapper()
# Display contents before finishing review, showing that the document contains revision markup.
xml_with_revision_markup = wrapper.GetMainDocumentPart("DocumentWithRevisionMarkup.docx")
print("Document before finishing review:\n")
print(xml_with_revision_markup)
# Finish review, removing all revision markup.
print("\nFinishing review ...")
shutil.copyfile("DocumentWithRevisionMarkup.docx", "Result.docx")
xml_without_revision_markup = wrapper.FinishReview("Result.docx")
# Display contents after finishing review, showing that the revision markup was removed.
print("\nDocument after finishing review:\n")
print(xml_without_revision_markup)
You'll find the full source code in my CodeSnippets GitHub repo. Look at the CodeSnippets.OpenXmlWrapper and CodeSnippets.OpenXmlWrapper.PythonClient projects.
Depending on your use case, you will also be able to use the OpenXmlPowerTools directly. I just implemented a wrapper to provide a simplified interface.

What is the replacement for TestContext.DataRow["MyColumnName"]

Using MSTest in a .Net Core Unit test project. I am attempting to use a csv datasource to provide the data for a test method.
Previously, I would use something like below in a .Net Framework test project:
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", #"data.csv", "data#csv", DataAccessMethod.Sequential),
DeploymentItem("data.csv"),
TestMethod]
public void ValuesController_Post()
{
_controller.Post(TestContext.DataRow["body"]);
_valuesRepository.Verify(_ => _.Post(It.IsAny<string>()), Times.Once);
}
The key here being the DataRow property found in TestContext. This doesn't appear to exist in the .Net Core version of the TestContext.
How would I go about doing this in .Net Core?
Since moving to aspnet core, I've never been able to use the same [Datasource(...)] attribute to iterate through test data, my data-driven tests are always skipped.
Have you considered switching to another approach with [DataTestMethod] and [DynamicData] with a custom source that reads you file ?
Here's a good article on this :
https://www.meziantou.net/2018/02/05/mstest-v2-data-tests
Maybe another way would be to read the whole file at the begining of the test and then iterate through the dataset as One single unit test?
Hope this helps.
It took me an afternoon to fiddle with things, but I finally found a solution. Since you don't specify your test or CSV file, here is a quick example I could get working.
Long story short, I installed the CsvHelper NuGet package, because parsing CSV is dead easy right up to the point it is not. As Carl Verret pointed out, you need to use the [DynamicData(...)] attribute above your test method, and then parse the CSV using CsvHelper.
The CSV File (Example.csv)
A,B,IsLessThanZero
1,2,FALSE
3,-5,TRUE
Important: Make sure this CSV file is included in your test project and "Copy To Output Directory" is set to "Always" in the properties for the CSV file in Solution Explorer.
Data Transfer Object Used By CsvHelper
public class AdditionData
{
public int A { get; set; }
public int B { get; set; }
public bool IsLessThanZero { get; set; }
}
The Test Class
[TestClass]
public class ExampleTests
{
// HINT: Look in {Your Test Project Folder}\bin\{Configuration}\netcore3.1\FolderYourCsvFileIsIn for the CSV file.
// Change this path to work with your test project folder structure.
private static readonly string DataFilePath = Path.GetDirectoryName(typeof(ExampleTests).Assembly.Location) + #"\FolderYourCsvFileIsIn\Example.csv";
[TestMethod]
[DynamicData(nameof(GetData), DynamicDataSourceType.Method)]
public void AddingTwoNumbers(AdditionData data)
{
bool isLessThanZero = data.A + data.B < 0;
Assert.AreEqual(data.IsLessThanZero, isLessThanZero);
}
private static IEnumerable<object[]> GetData()
{
using var stream = new StreamReader(DataFilePath);
using var reader = new CsvReader(stream, new CsvConfiguration(CultureInfo.CurrentCulture));
var rows = reader.GetRecords<AdditionData>();
foreach (var row in rows)
{
yield return new object[] { row };
}
}
}
After building your solution, you will see a single test in Test Explorer. Running this single test runs all variants defined in your CSV file:

FileVersionInfo.GetVersionInfo() incorrect in Console Application

I'm getting some serious weirdness using FileVersionInfo.GetVersionInfo() and was hoping somebody might be able to help.
The basics of the issue is that I am iterating through all the files in a folder calling GetVersionInfo() on each. There are about 300 files. This works ok for all but 2 of the files. For these DLLs I am getting comepletely incorrect info back from GetVersionInfo().
In order to eliminate all other variables, I extracted this call into a simple test app and it still got the same problem. However, if I built the test app as a Windows Application (it was a Console Application initially) then the data came back correct.
Just to clarify, the incorrect data coming back when running as a Console App is not simply null info like you would get if the file didn't contain version data. It contained reasonable data, but just the wrong data. It's as if it's reading it from a different file. I've looked for a file that contains matching version data, but can't find one.
Why is this simple call functioning differently if built as a Console Application rather than a Windows Application?
If anyone can help with this I would be very grateful.
Rgds,
Andy
-- Code Added
using System;
using System.Diagnostics;
namespace test
{
class Program
{
static void Main(string[] args)
{
string file = "C:\\ProblemFile.dll";
FileVersionInfo version = FileVersionInfo.GetVersionInfo(file);
string fileName = version.FileName;
string fileVersion = version.FileVersion;
Console.WriteLine(string.Format("{0} : {1}", fileName, fileVersion));
}
}
}
This behaviour seems weird indeed. Could it be that the Console application does not load the DLL from the same place as the WinForms application does? This would mean that GetVersionInfo uses some other API than just Win32 CreateFile (maybe going through some DLL resolver mechanism, side-by-side or whatever); remember that under the covers, version.dll will be executing your request, not the CLR itself.
Looking at FileVersionInfo through Reflector points in another direction yet:
public static unsafe FileVersionInfo GetVersionInfo(string fileName)
{
// ...
int fileVersionInfoSize = UnsafeNativeMethods.GetFileVersionInfoSize(fileName, out num);
FileVersionInfo info = new FileVersionInfo(fileName);
if (fileVersionInfoSize != 0)
{
byte[] buffer = new byte[fileVersionInfoSize];
fixed (byte* numRef = buffer)
{
IntPtr handle = new IntPtr((void*) numRef);
if (!UnsafeNativeMethods.GetFileVersionInfo(fileName, 0, fileVersionInfoSize, new HandleRef(null, handle)))
{
return info;
}
int varEntry = GetVarEntry(handle);
if (!info.GetVersionInfoForCodePage(handle, ConvertTo8DigitHex(varEntry)))
{
int[] numArray = new int[] { 0x40904b0, 0x40904e4, 0x4090000 };
foreach (int num4 in numArray)
{
if ((num4 != varEntry) && info.GetVersionInfoForCodePage(handle, ConvertTo8DigitHex(num4)))
{
return info;
}
}
}
}
}
return info;
}
As you can see there, some interesting dance is going on with code pages. What if the DLLs you inspected had several version information resources attached to them? Depending on the culture of the program calling into GetVersionInfo, I guess that the code page related calls could return other results?
Take the time to check the resources of the DLLs and make sure that there is only one language/code page for the version information. It might point you at the solution, I hope.
Sure the "files" you're seeing aren't . and .. ? If you iterate through all files, you'll always see entries for . (current dir) and .. (up dir). GetVersion Info might well return anything for these. You'd have to filter these entries out manually by name.
File and Assembly versions are 2 different things.
Are you sure you are not expecting the other?
Update: Tried this. Didn't work.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace test
{
class Program
{
[DllImport("COMCTL32")]
private static extern int InitCommonControls(int nExitCode);
static void Main(string[] args)
{
InitCommonControls(0);
string file = "C:\\ProblemFile.dll";
FileVersionInfo version = FileVersionInfo.GetVersionInfo(file);
string fileName = version.FileName;
string fileVersion = version.FileVersion;
Console.WriteLine(string.Format("{0} : {1}", fileName, fileVersion));
}
}
}

Writing Logs to an XML File with .NET

I am storing logs in an xml file...
In a traditional straight text format approach, you would typically just have a openFile... then writeLine method...
How is it possible to add a new entry into the xml document structure, like you would just with the text file approach?
use an XmlWriter.
example code:
public class Quote
{
public string symbol;
public double price;
public double change;
public int volume;
}
public void Run()
{
Quote q = new Quote
{
symbol = "fff",
price = 19.86,
change = 1.23,
volume = 190393,
};
WriteDocument(q);
}
public void WriteDocument(Quote q)
{
var settings = new System.Xml.XmlWriterSettings
{
OmitXmlDeclaration = true,
Indent= true
};
using (XmlWriter writer = XmlWriter.Create(Console.Out, settings))
{
writer.WriteStartElement("Stock");
writer.WriteAttributeString("Symbol", q.symbol);
writer.WriteElementString("Price", XmlConvert.ToString(q.price));
writer.WriteElementString("Change", XmlConvert.ToString(q.change));
writer.WriteElementString("Volume", XmlConvert.ToString(q.volume));
writer.WriteEndElement();
}
}
example output:
<Stock Symbol="fff">
<Price>19.86</Price>
<Change>1.23</Change>
<Volume>190393</Volume>
</Stock>
see
Writing with an XmlWriter
for more info.
One of the problems with writing a log file in XML format is that you can't just append lines to the end of the file, because the last line has to have a closing root element (for the XML to be valid)
This blog post by Filip De Vos demonstrates quite a good solution to this:
High Performance writing to XML Log files (edit: link now dead so removed)
Basically, you have two XML files linked together using an XML-include thing:
Header file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log [
<!ENTITY loglines SYSTEM "loglines.xml">
]>
<log>
&loglines;
</log>
Lines file (in this example, named loglines.xml):
<logline date="2007-07-01 13:56:04.313" text="start process" />
<logline date="2007-07-01 13:56:25.837" text="do something" />
<logline date="2007-07-01 13:56:25.853" text="the end" />
You can then append new lines to the 'lines file', but (most) XML parsers will be able to open the header file and read the lines correctly.
Filip notes that: This XML will not be parsed correctly by every XML parser on the planet. But all the parsers I have used do it correctly.
The big difference is the way you are thinking about your log data. In plain text files you are indeed just adding new lines. XML is a tree structure however, and you need to think about like such. What you are adding is probably another NODE, i.e.:
<log>
<time>12:30:03 PST</time>
<user>joe</user>
<action>login</action>
<log>
Because it is a tree what you need to ask is what parent are you adding this new node to. This is usually all defined in your DTD (Aka, how you are defining the structure of your data). Hopefully this is more helpful then just what library to use as once you understand this principle the interface of the library should make more sense.
Why reinvent the wheel? Use TraceSource Class (System.Diagnostics) with the XmlWriterTraceListener.
Sorry to post a answer for old thread. i developed the same long time ago. here i like to share my full code for logger saved log data in xml file date wise.
logger class code
using System.IO;
using System.Xml;
using System.Threading;
public class BBALogger
{
public enum MsgType
{
Error ,
Info
}
public static BBALogger Instance
{
get
{
if (_Instance == null)
{
lock (_SyncRoot)
{
if (_Instance == null)
_Instance = new BBALogger();
}
}
return _Instance;
}
}
private static BBALogger _Instance;
private static object _SyncRoot = new Object();
private static ReaderWriterLockSlim _readWriteLock = new ReaderWriterLockSlim();
private BBALogger()
{
LogFileName = DateTime.Now.ToString("dd-MM-yyyy");
LogFileExtension = ".xml";
LogPath= Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Log";
}
public StreamWriter Writer { get; set; }
public string LogPath { get; set; }
public string LogFileName { get; set; }
public string LogFileExtension { get; set; }
public string LogFile { get { return LogFileName + LogFileExtension; } }
public string LogFullPath { get { return Path.Combine(LogPath, LogFile); } }
public bool LogExists { get { return File.Exists(LogFullPath); } }
public void WriteToLog(String inLogMessage, MsgType msgtype)
{
_readWriteLock.EnterWriteLock();
try
{
LogFileName = DateTime.Now.ToString("dd-MM-yyyy");
if (!Directory.Exists(LogPath))
{
Directory.CreateDirectory(LogPath);
}
var settings = new System.Xml.XmlWriterSettings
{
OmitXmlDeclaration = true,
Indent = true
};
StringBuilder sbuilder = new StringBuilder();
using (StringWriter sw = new StringWriter(sbuilder))
{
using (XmlWriter w = XmlWriter.Create(sw, settings))
{
w.WriteStartElement("LogInfo");
w.WriteElementString("Time", DateTime.Now.ToString());
if (msgtype == MsgType.Error)
w.WriteElementString("Error", inLogMessage);
else if (msgtype == MsgType.Info)
w.WriteElementString("Info", inLogMessage);
w.WriteEndElement();
}
}
using (StreamWriter Writer = new StreamWriter(LogFullPath, true, Encoding.UTF8))
{
Writer.WriteLine(sbuilder.ToString());
}
}
catch (Exception ex)
{
}
finally
{
_readWriteLock.ExitWriteLock();
}
}
public static void Write(String inLogMessage, MsgType msgtype)
{
Instance.WriteToLog(inLogMessage, msgtype);
}
}
Calling or using this way
BBALogger.Write("pp1", BBALogger.MsgType.Error);
BBALogger.Write("pp2", BBALogger.MsgType.Error);
BBALogger.Write("pp3", BBALogger.MsgType.Info);
MessageBox.Show("done");
may my code help you and other :)
Without more information on what you are doing I can only offer some basic advice to try.
There is a method on most of the XML objects called "AppendChild". You can use this method to add the new node you create with the log comment in it. This node will appear at the end of the item list. You would use the parent element of where all the log nodes are as the object to call on.
Hope that helps.
XML needs a document element (Basically top level tag starting and ending the document).
This means a well formed XML document need have a beginning and end, which does not sound very suitable for logs, where the current "end" of the log is continously extended.
Unless you are writing batches of self contained logs where you write everything to be logged to one file in a short period of time, I'd consider something else than XML.
If you are writing a log of a work-unit done, or a log that doesn't need to be inspected until the whole thing has finished, you could use your approach though - simply openfile, write the log lines, close the file when the work unit is done.
For editing an xml file, you could also use LINQ. You can take a look on how here:
http://www.linqhelp.com/linq-tutorials/adding-to-xml-file-using-linq-and-c/

Categories