Programmatically reading VS .coveragexml file in C# - c#

So I have some code that can read the methods out of a .coverage file...
using (CoverageInfo info = CoverageInfo.CreateFromFile(this.myCoverageFile))
{
CoverageDS ds = info.BuildDataSet();
foreach (ICoverageModule coverageModule in info.Modules)
{
CodeModule currentModule = new CodeModule(coverageModule.Name);
byte[] coverageBuffer = coverageModule.GetCoverageBuffer(null);
using (ISymbolReader reader = coverageModule.Symbols.CreateReader())
{
Method currentMethod;
while (reader.GetNextMethod(out currentMethod, coverageBuffer))
{
if (currentMethod != null)
{
currentModule.Methods.Add(currentMethod);
}
}
}
returnModules.Add(currentModule);
}
}
... but I want to be able to read .coverage files that have been exported to xml too. The reason for this is that .coverage files require the source dlls be in the exact location they were when code coverage was measured, which doesn't work for me.
When I try to load a coveragexml file using CreateFromFile(string) I get the following exception.
Microsoft.VisualStudio.Coverage.Analysis.InvalidCoverageFileException
was unhandled Message=Coverage file
"unittestcoverage.coveragexml" is
invalid or corrupt.
The coveragexml file opens in Visual Studio just fine, so I don't believe there's any issue with the file's format.
I know that CoverageDS can import an xml file, but the API is less than intuitive and the only example I can find of its use is...
using(CoverageInfo info = CoverageInfo.CreateFromFile(fileString))
{
CoverageDS data = info.BuildDataSet();
data.ExportXml(xmlFile);
}
...which tells me nothing about how to actually read the coverage data from that file.
Does someone know how to process code coverage data from a .coveragexml file?

Probably the best introduction to manipulating code coverage information programmatically is available here and also in the linked ms_joc blog.
I'm pretty sure you can use 'CreateInfoFromFile' with either the .coverage file or the XML file you exported in the sample above.
UPDATE:
CreateInfoFromFile throws an exception if the coveragexml is passed as the argument. Here is an alternative:
CoverageDS dataSet = new CoverageDS();
dataSet.ImportXml(#"c:\temp\test.coveragexml");
foreach (CoverageDSPriv.ModuleRow module in dataSet.Module)
{
Console.WriteLine(String.Format("{0} Covered: {1} Not Covered: {2}", module.ModuleName, module.LinesCovered, module.LinesNotCovered));
}

Have you tried the CoverageDS.ReadXml(fileName_string) method?

Related

EPPlus edited XLSM files show Error in Excel

I use the EPPlus library to batch edit some existing XLSM files. Inside the files I replace a line of VBA code and that's it. Everything works nice, if I edit the same line in the Excel code editor by hand.
When I open some of the files with Excel 2013 (15.0.4989.1000), the following error message is shown.
We found a problem with some content in 'test.xlsm'. Do you want us to
recover as much as we can? If you trust the source of this workbook,
click Yes.
If I click yes, the repair report shows the following entry. But the message is somewhat too generic to help me further.
Removed Records: Named range from /xl/workbook.xml-Part (Arbeitsmappe)
This is my C# code, which edits the XLSM file. Can I update my code or do I have to update the XLSM-file before editing it?
static void PatchVba(string filePath, string oldCode, string newCode)
{
var wbFileInfo = new FileInfo(filePath);
using (var package = new ExcelPackage(wbFileInfo, false))
{
foreach (var m in package.Workbook.VbaProject.Modules)
{
if (m.Code.Contains(oldCode))
{
m.Code = m.Code.Replace(oldCode, newCode);
Console.WriteLine("VBA Patched in \"{0}\"", filePath);
}
}
try
{
package.SaveAs(wbFileInfo);
}
catch
{
Console.WriteLine("Could not save patched file \"{0}\".", filePath);
}
}
}
I found out what the problem is. In the edited XLSM-file, a range name is used multiple times with overlapping scope. I was too focused on my C# code to find the root cause.
So removing the named ranges solves the issue. But it would still be interesting to know, why I can edit it without problems using Excel, but not by using EPPlus.

Receiving message of issue with content in Excel File

I am currently building an Excel file by hand using OpenXml. I'm in the process of adding the sheets, however, I have come across an issue. I have a loop that adds the names of each sheet in but once it runs and I try to open the file, I get the following message:
"We found a problem with some content in 'FileName.xlsx'. Do you want us to try to recover as much as we can? If you trust the source of this workbook, Click Yes."
I think the issue might be due that I am adding in the name of each sheet using a string variable. When I take it out and add something else, it works. Below is my code where I am looping through and adding my sheets.
//Technology Areas
foreach (DataRow dr in techAreaDS.Rows)
{
var data = dr["TechAreaName"].ToString().Split('-');
var techArea = data[2].TrimStart();
var techAreaSheet = new Sheet { Id = workbookPart.GetIdOfPart(worksheetPart),
SheetId = sheetId, Name = techArea };
sheets.Append(techAreaSheet);
sheetId++;
}
I've seen people mention it is an issue with cells having strings that can be converted into strings, but in this case, the string will always be a string. Any help would be appreciated.
EDIT: I've figured out the problem. The issue is the Name property has a Max Length of 31. One of my items has a 42 length, hence the error. I did find a cool set of code to validate my OpenXml. Link.
UPDATE:
Oddly enough, someone thinks this question was about finding some code to help validate what I was doing. It was not... The question is clear: why was I receiving an error when trying to name sheets. I was not asking for validation code, though I found some.
I do ask that if you wish to help, please read the question versus assume what I was asking, and if you don't know what I wish to have answered, ask...
In order to find out the issue(s) causing this error, you need to validate the generated document.
Besides using the built in validation method as described here, which doesn't show you all issues as I found out, I suggest that you download and install Microsoft's Open XML SDK 2.5 for Microsoft Office.
It contains Microsoft's Open XML SDK 2.5 Productivity Tool, which is very helpful here:
Create a copy of the damaged XLSX file, and apply the fixes as Microsoft Excel is suggesting (suppose you have the files FileName_corrupt.xlsx and FileName_fixed.xlsx
Then, run Microsoft's Open XML SDK 2.5 Productivity Tool, open FileName_corrupt.xlsx, select "Compare Files" and specify the 2nd file FileName_fixed.xlsx. This allows you to compare the XML structure of both files.
Let Microsoft's Open XML SDK 2.5 Productivity Tool generate C# code from both files: Open them first, then right-click on the root level and select "Reflect Code". This will create C# code which allows you to generate the same file. Save both C# code versions (i.e. FileName_corrupt.cs and FileName_fixed.cs)
Now you can compare the differences via Visual Studio: Either use
devenv.exe /diff FileName_corrupt.cs FileName_fixed.cs
to compare them, or use the batch file I've created to launch the VS compare - this is a hidden feature in Visual Studio, it allows to compare 2 local files being not part of TFS.
This way you should be able to work out the differences and allow you to fix your code.
NOTE: For a first validation, I do suggest to use the validation code. Only if it still fails, use the steps above. For validation you can use
public static string ValidateOpenXmlDocument(OpenXmlPackage pXmlDoc, bool throwExceptionOnValidationFail=false)
{
using (var docToValidate = pXmlDoc)
{
var validator = new DocumentFormat.OpenXml.Validation.OpenXmlValidator();
var validationErrors = validator.Validate(docToValidate).ToList();
var errors = new System.Text.StringBuilder();
if (validationErrors.Any())
{
var errorMessage = string.Format("ValidateOpenXmlDocument: {0} validation error(s) with document", validationErrors.Count);
errors.AppendLine(errorMessage);
errors.AppendLine();
}
foreach (var error in validationErrors)
{
errors.AppendLine("Description: " + error.Description);
errors.AppendLine("ErrorType: " + error.ErrorType);
errors.AppendLine("Node: " + error.Node);
errors.AppendLine("Path: " + error.Path.XPath);
errors.AppendLine("Part: " + error.Part.Uri);
if (error.RelatedNode != null)
{
errors.AppendLine("Related Node: " + error.RelatedNode);
errors.AppendLine("Related Node Inner Text: " + error.RelatedNode.InnerText);
}
errors.AppendLine();
errors.AppendLine("==============================");
errors.AppendLine();
}
if (validationErrors.Any() && throwExceptionOnValidationFail)
{
throw new Exception(errors.ToString());
}
if (errors.Length > 0)
{
System.Diagnostics.Debug.WriteLine(errors.ToString());
}
return errors.ToString();
}
along with
public static void ValidateExcelDocument(string fileName)
{
using (var xlsx = SpreadsheetDocument.Open(fileName, true))
{
ValidateOpenXmlDocument(xlsx);
}
}
With a slight modification, you can easily use the code above for Microsoft Word validation too:
public static void ValidateWordDocument(string fileName)
{
using (var docx = WordprocessingDocument.Open(fileName, true))
{
ValidateOpenXmlDocument(docx);
}
}
I've figured out the problem. The issue is the Name property has a Max Length of 31 characters. The text I'm trying to use sometimes exceeds that limit (one has 42 characters). I also found a pretty cool set of code to validate my Open Xml to find out what the specific issue is. Link

C# CsvHelper - Missing CsvReader.cs

I am using CsvHelper to read a .CSV file into an html table. I am using .NET MVC 4 and CsvReader 2.13.2.0. I have tried different versions of CsvHelper and am still getting the same error on this line:
var csv = new CsvReader(new StreamReader(path));
Error:
I've looked in the CsvHelper folder and there is just a .dll, debug database, and an XML document. Does anybody know why this file does not exist or if I am using a depreciated CsvHelper method or something. Thanks!
I know this doesn't directly answer your question but I would look into LinqToCSV (you can find it on Nuget). With it you can use it to serialize a csv file into an object and use linq to iterate over it. It's very easy to use and since it's a package you won't need to worry about the dll management or the code being deprecated. I've used it in the past, I dont remember the exact syntax but loading the file is something like this:
var cc = new CsvContext();
cc.Read<YourModel>(filePath);
That will read the csv file into your C# object. Then you can just use it like any other object.
I had the same problem. But I forgot surrounding it with a try-/catch to see the root exception :-). Simple!
try
{
var csv = new CsvReader(new StreamReader(path));
}
catch (UnauthorizedAccessException e)
{
//handle it
}
catch (System.Exception e)
{
//handle it
}

Deploy an application's xml file with installer or create it on the fly if it does not exist

I am having an xml file like:
<CurrentProject>
// Elements like
// last opened project file to reopen it when app starts
// and more global project independend settings
</CurrentProject>
Now I asked myself wether I should deliver this xml file with above empty elements with the installer for my app or should I create this file on the fly on application start if it does not exist else read the values from it.
Consider also that the user could delete this file and that should my application not prevent from working anymore.
What is better and why?
UPDATE:
What I did felt ok for me so I post my code here :) It just creates the xml + structure on the fly with some security checks...
public ProjectService(IProjectDataProvider provider)
{
_provider = provider;
string applicationPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
_projectPath = Path.Combine(applicationPath,#"TBM\Settings.XML");
if (!File.Exists(_projectPath))
{
string dirPath = Path.Combine(applicationPath, #"TBM");
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
using (var stream = File.Create(_projectPath))
{
XElement projectElement = new XElement("Project");
projectElement.Add(new XElement("DatabasePath"));
projectElement.Save(stream, SaveOptions.DisableFormatting);
}
}
}
In a similar scenario, I recently went for creating the initial file on the fly. The main reason I chose this was the fact that I wasn't depending on this file being there and being valid. As this was a file that's often read from/written to, there's a chance that it could get corrupted (e.g. if the power is lost while the file is being written).
In my code I attempted to open this file for reading and then read the data. If anywhere during these steps I encountered an error, I simply recreated the file with default values and displayed a corresponding message to the user.

How To Write To An Embedded Resource?

I keep getting the error "Stream was not writable" whenever I try to execute the following code. I understand that there's still a reference to the stream in memory, but I don't know how to solve the problem. The two blocks of code are called in sequential order. I think the second one might be a function call or two deeper in the call stack, but I don't think this should matter, since I have "using" statements in the first block that should clean up the streams automatically. I'm sure this is a common task in C#, I just have no idea how to do it...
string s = "";
using (Stream manifestResourceStream =
Assembly.GetExecutingAssembly().GetManifestResourceStream("Datafile.txt"))
{
using (StreamReader sr = new StreamReader(manifestResourceStream))
{
s = sr.ReadToEnd();
}
}
...
string s2 = "some text";
using (Stream manifestResourceStream =
Assembly.GetExecutingAssembly().GetManifestResourceStream("Datafile.txt"))
{
using (StreamWriter sw = new StreamWriter(manifestResourceStream))
{
sw.Write(s2);
}
}
Any help will be very much appreciated. Thanks!
Andrew
Embedded resources are compiled into your assembly, you can't edit them.
As stated above, embedded resources are read only. My recommendation, should this be applicable, (say for example your embedded resource was a database file, XML, CSV etc.) would be to extract a blank resource to the same location as the program, and read/write to the extracted resource.
Example Pseudo Code:
if(!Exists(new PhysicalResource())) //Check to see if a physical resource exists.
{
PhysicalResource.Create(); //Extract embedded resource to disk.
}
PhysicalResource pr = new PhysicalResource(); //Create physical resource instance.
pr.Read(); //Read from physical resource.
pr.Write(); //Write to physical resource.
Hope this helps.
Additional:
Your embedded resource may be entirely blank, contain data structure and / or default values.
A bit late, but for descendants=)
About embedded .txt:
Yep, on runtime you couldnt edit embedded because its embedded. You could play a bit with disassembler, but only with outter assemblies, which you gonna load in current context.
There is a hack if you wanna to write to a resource some actual information, before programm starts, and to not keep the data in a separate file.
I used to worked a bit with winCE and compact .Net, where you couldnt allow to store strings at runtime with ResourceManager. I needed some dynamic information, in order to catch dllNotFoundException before it actually throws on start.
So I made embedded txt file, which I filled at the pre-build event.
like this:
cd $(ProjectDir)
dir ..\bin\Debug /a-d /b> assemblylist.txt
here i get files in debug folder
and the reading:
using (var f = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("Market_invent.assemblylist.txt")))
{
str = f.ReadToEnd();
}
So you could proceed all your actions in pre-build event run some exes.
Enjoy! Its very usefull to store some important information and helps avoid redundant actions.

Categories