Retrieve data from browser local storage using c# - c#

Is it possible to retrieve data from chrome/firefox local storage using C#?

Disclaimer: I have tested this on my Windows 7 x64 running Google Chrome 13.0.782.220 at the moment. The information provided here is a result of my own research and is not any official way or API to retrieve this information. Use at your own risk. Also the technique presented here might break with any future release if Chrome changes the way to store this information.
So, Google Chrome uses SQLite to persist local storage data. You could use the System.Data.SQLite managed driver to read it from your .NET application. If you are running on Windows 7 (don't know for others as that's the one I have and can test), you will have the following folder:
c:\Users\SOMEUSERNAME\AppData\Local\Google\Chrome\User Data\Default\Local Storage\
This folder will contain multiple files with the .localstorage extension. Each file is for different site. For example for StackOverflow I have http_stackoverflow.com_0.localstorage but of course this naming is totally arbitrary and you cannot rely upon it. Each file represents a SQLite database.
I have noticed that this database contains a table called ItemTable with 2 string columns called key and value.
So to read the values it's a simple matter of sending a SQL query:
class Program
{
static void Main()
{
using (var conn = new SQLiteConnection("Data Source=http_stackoverflow.com_0.localstorage;Version=3;"))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT key, value FROM ItemTable";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(
"key: {0}, value: {1}",
reader.GetString(reader.GetOrdinal("key")),
reader.GetString(reader.GetOrdinal("value"))
);
}
}
}
}
}

When using Chromium Embedded Framework I found that the above solution has many limitations. It seems like Chromium have moved to using leveldb instead.
I ended up with a solution where I inject JS code that modify local storage in FrameLoadStart. (it should be easy to read values as well - JavascriptResponse.Result can be casted to a IDictionary when using this script: "window.localStorage;" instead)
// writing local storage in FrameLoadStart
foreach (var entry in LocalStorage)
{
script += $"window.localStorage.{entry.Key} = '{entry.Value}';";
}
IFrame frame = chromeBrowser.GetMainFrame();
var result = await frame.EvaluateScriptAsync(script , frame.Url, 0);
if(!result.Success)
{
throw new Exception(result.Message);
}

Related

Reading in a complex text file to input into database

I am working on a program that will read in a text file and then insert areas of the text file into different columns on a database. The text file is generally set up like this:
"Intro information"
"more Intro information"
srvrmgr> "information about system"
srbrmgr> list parameters for component *ADMBatchProc*
"Headers"
*Name of record* *alias of record* *value of record*
The columns create a table containing all of the setting information for this component. One all of the settings are listed, the file moves to another component and returns all the information for that component in a new table. I need to read in the component and the information on the tables without the headers or the other information. I will then need to be able to transfer that data into a database. The columns are fixed width on each table within the file.
Any recommendations about how to approach this are welcome. I have never read in a file this complex so I dont really know how to approach ignoring alot of information while trying to get other information ready for a database. Also the component value I am trying to gather always follows the word component on a line that starts with "srvrmgr".
The '*' represents areas that will be put into datbase.
Siebel Enterprise Applications Siebel Server Manager, Version 8.1.1.11 [23030] LANG_INDEPENDENT
Copyright (c) 1994-2012, Oracle. All rights reserved.
The Programs (which include both the software and documentation) contain
proprietary information; they are provided under a license agreement containing
restrictions on use and disclosure and are also protected by copyright, patent,
and other intellectual and industrial property laws. Reverse engineering,
disassembly, or decompilation of the Programs, except to the extent required to
obtain interoperability with other independently created software or as specified
by law, is prohibited.
Oracle, JD Edwards, PeopleSoft, and Siebel are registered trademarks of
Oracle Corporation and/or its affiliates. Other names may be trademarks
of their respective owners.
If you have received this software in error, please notify Oracle Corporation
immediately at 1.800.ORACLE1.
Type "help" for list of commands, "help <topic>" for detailed help
Connected to 1 server(s) out of a total of 1 server(s) in the enterprise
srvrmgr> configure list parameters show PA_NAME,PA_ALIAS,PA_VALUE
srvrmgr>
srvrmgr> list parameters for component ADMBatchProc
PA_NAME PA_ALIAS PA_VALUE
---------------------------------------------------------------------- ------------------------------------- --------------------------------------------------------------------------------------------------------------------
ADM Data Type Name ADMDataType
ADM EAI Method Name ADMEAIMethod Upsert
ADM Deployment Filter ADMFilter
213 rows returned.
srvrmgr> list parameters for component ADMObjMgr_enu
PA_NAME PA_ALIAS PA_VALUE
---------------------------------------------------------------------- ------------------------------------- --------------------------------------------------------------------------------------------------------------------
AccessibleEnhanced AccessibleEnhanced False
This is the beginning of the text file. It a produced in a system called Siebel to show all of the settings for this environment. I need to pull the component name (there are multiple on the actual file but the ones shown here are 'ADMBatchProc' and 'ADMObjMgr_enu'), and then the data shown on the table below it that was created by Siebel. The rest of the information is irrelevant for the purpose of the task I need.
I would recommend using Test-Driven Development techniques in this case. I'm guessing that your possible variations of input format are near infinite.
Try this:
1) Create an interface that will represent the data operations or parsing logic you expect the application to perform. For example:
public interface IParserBehaviors {
void StartNextComponent();
void SetTableName(string tableName);
void DefineColumns(IEnumerable<string> columnNames);
void LoadNewDataRow(IEnumerable<object> rowValues);
DataTable ProduceTableForCurrentComponent();
// etc.
}
2) Gather as many small examples of discrete inputs that have well-defined behaviors as possible.
3) Inject a behaviors handler into your parser. For example:
public class Parser {
private const string COMPONENT_MARKER = "srvrmgr";
private readonly IParserBehaviors _behaviors;
public Parser(IParserBehaviors behaviors) {
_behaviors = behaviors;
}
public void ReadFile(string filename) {
// bla bla
foreach (string line in linesOfFile) {
// maintain some state
if (line.StartsWith(COMPONENT_MARKER)) {
DataTable table = _behaviors.ProduceTableForCurrentComponent();
// save table to the database
_behaviors.StartNextComponent();
}
else if (/* condition */) {
// parse some text
_behaviors.LoadNewDataRow(values);
}
}
}
}
4) Create tests around the expected behaviors, using your preferred mocking framework. For example:
public void FileWithTwoComponents_StartsTwoNewComponents() {
string filename = "twocomponents.log";
Mock<IParserBehaviors> mockBehaviors = new Mock<IParserBehaviors>();
Parser parser = new Parser(mockBehaviors.Object);
parser.ReadFile(filename);
mockBehaviors.Verify(mock => mock.StartNextComponent(), Times.Exactly(2));
}
This way, you will be able to integrate under controlled tests. When (not if) someone runs into a problem, you can distill what case wasn't covered, and add a test surrounding that behavior, after extracting the case from the log being used. Separating concerns this way also allows your parsing logic to be independent from your data operation logic. The needs of parsing specific behaviors seems to be central to your application, so it seems like a perfect fit for creating some domain-specific interfaces.
You'll want to read the text file using StreamReader:
using (FileStream fileStream = File.OpenRead(path))
{
byte[] data = new byte[fileStream.Length];
for (int index = 0; index < fileStream.Length; index++)
{
data[index] = (byte)fileStream.ReadByte();
}
Console.WriteLine(Encoding.UTF8.GetString(data)); // Displays: your file - now you can decide how to manipulate it.
}
Perhaps then you'll use Regex to capture the date you'd like to insert:
You might insert into the db like this:
using (TransactionScope transactionScope = new TransactionScope())
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command1 = new SqlCommand(
“INSERT INTO People ([FirstName], [LastName], [MiddleInitial])
VALUES(‘John’, ‘Doe’, null)”,
connection);
SqlCommand command2 = new SqlCommand(
“INSERT INTO People ([FirstName], [LastName], [MiddleInitial])
VALUES(‘Jane’, ‘Doe’, null)”,
connection);
command1.ExecuteNonQuery();
command2.ExecuteNonQuery();
}
transactionScope.Complete();
}
Examples adapted from Wouter de Kort's C# 70-483.

The process cannot access the file 'filename' because it is being used by another process

I am new in C# and I have a problem connecting to a Firebird database. I want my program to access a Firebird Database [FDB format file]. I have problem, see the code below:
File.Copy(pathway, new_pathway, true);
FbConnection addDetailsConnection = new FbConnection("User=sysdba;Password=masterkey;Dialect=3;Database= " + new_pathway +
";DataSource=localhost;" );
string SQLCOMMAND = " SELECT UOM FROM ST_ITEM_UOM WHERE CODE = 'ANT'";
addDetailsConnection.Open();
FbCommand readCommand = new FbCommand(SQLCOMMAND, addDetailsConnection);
FbDataReader myreader = readCommand.ExecuteReader();
while (myreader.Read())
{
MessageBox.Show(myreader[0].ToString());
}
myreader.Close();
readCommand.Dispose();
addDetailsConnection.Close();
addDetailsConnection.Dispose();
This code lets me read my FDB file and extract the data. When the code executes for the first time, there is no error or problem, However when when I execute it again, this error is shown:
The process cannot access the file 'C:\Users\ACC-0001.FDB' because it is being used by another process.
You can use Handle to check which program is locking the file. It might be caused by your code or by another process running on your machine.
The tool identifies the process, for example:
C:>handle.exe c:\test.xlsx
Handle v3.46 Copyright (C) 1997-2011 Mark Russinovich Sysinternals -
www.sysinternals.com
EXCEL.EXE pid: 3596 type: File 414: C:\test.xlsx
As found here.
If the problem lies within your code, make sure you dispose and close all connections, preferably by using them within using sections:
using (FbConnection addDetailsConnection = new FbConnection("..."))
{
// do work
}
More details on using using can be found here.
You might have bumped into this Firebird issue: FB server reports that DB file is used by another application on secondary attachment attempt through a symlink
It only happens on Windows and only when two non-embedded connections use different path names of which one or both have a symlink in their path so they effectively point to the same location.
Both handle.exe and Process Explorer will only show the canonical (final) filename that fbserver.exe actually opens.
The only way to find out is to:
compare connection strings.
verify with handle.exe or Process Explorer that the files are indeed opened by fbserver.exe (and not by your process itself using an embedded connection)

EzAPI OLE DB Destination

I've searched all over and I now have to ask SO. I'm trying to construct a simple dataflow using EzAPI. It's been anything but easy, but I'm committed to figuring this out. What I can't figure out is how to get the EzOleDBDestination working. Here's my complete code
var a = new Application();
// using a template since it's impossible to set up an ADO.NET connection to MySQL
// using EzAPI and potentially even with the raw SSIS API...
var pkg = new EzPackage(a.LoadPackage(#"C:\...\Package.dtsx", null));
pkg.Name = "Star";
var df = new EzDataFlow(pkg);
df.Name = "My DataFlow";
var src = new EzAdoNetSource(df);
src.Name = "Source Database";
src.SqlCommand = "SELECT * FROM enum_institution";
src.AccessMode = AccessMode.AM_SQLCOMMAND;
src.Connection = new EzConnectionManager(pkg, pkg.Connections["SourceDB"]);
src.ReinitializeMetaData();
var derived = new EzDerivedColumn(df);
derived.AttachTo(src);
derived.Name = "Prepare Dimension Attributes";
derived.LinkAllInputsToOutputs();
derived.Expression["SourceNumber"] = "id";
derived.Expression["Name"] = "(DT_STR,255,1252)description";
// EDIT: reordered the operation here and I no longer get an error, but
// I'm not getting any mappings or any input columns when I open the package in the designer
var dest = new EzOleDbDestination(df);
dest.AttachTo(derived, 0, 0);
dest.Name = "Target Database";
dest.AccessMode = 0;
dest.Table = "[dbo].[DimInstitution]";
dest.Connection = new EzConnectionManager(pkg, pkg.Connections["TargetDB"]);
// this comes from Yahia's link
var destInput = dest.Meta.InputCollection[0];
var destVirInput = destInput.GetVirtualInput();
var destInputCols = destInput.InputColumnCollection;
var destExtCols = destInput.ExternalMetadataColumnCollection;
var sourceColumns = derived.Meta.OutputCollection[0].OutputColumnCollection;
foreach(IDTSOutputColumn100 outputCol in sourceColumns) {
// Now getting COM Exception here...
var extCol = destExtCols[outputCol.Name];
if(extCol != null) {
// Create an input column from an output col of previous component.
destVirInput.SetUsageType(outputCol.ID, DTSUsageType.UT_READONLY);
var inputCol = destInputCols.GetInputColumnByLineageID(outputCol.ID);
if(inputCol != null) {
// map the input column with an external metadata column
dest.Comp.MapInputColumn(destInput.ID, inputCol.ID, extCol.ID);
}
}
}
Basically, anything that involves calls to ReinitializeMetadata() results in 0xC0090001, because that method is where the error happens. There's no real documentation to help me, so I have to rely on any gurus here.
I should mention that the source DB is MySQL and the target DB is SQL Server. Building packages like this using the SSIS designer works fine, so I know it's possible.
Feel free to tell me if I'm doing anything else wrong.
EDIT: here's a link to the base package I'm using as a template: http://www.filedropper.com/package_1 . I've redacted the connection details, but any MySQL and SQL Server database will do. The package will read from MySQL (using the MySQL ADO.NET Connector) and write to SQL Server.
The database schema is mostly irrelevant. For testing, just make a table in MySQL that has two columns: id (int) and description (varchar), with id being the primary key. Make equivalent columns in SQL Server. The goal here is simply to copy from one to the other. It may end up being more complex at some point, but I have to get past this hurdle first.
I can't test this now BUT I am rather sure that the following will help you get it working:
Calling ReinitializeMetadata() causes the component to fetch the table metadata. This should only be called after setting the AccessMode and related property. You are calling it before setting AccessMode...
Various samples including advice on debugging problems
define the derived column(s) directly in the SQL command instead of using a EzDerivedColumn
try to get it working with 2 SQL Server DBs first, some of the available MySQL ADO.NET provider have some shortcomings under some circumstances
UPDATE - as per comments some more information on debugging this and a link to a complete end-to-end sample with source:
http://blogs.msdn.com/b/mattm/archive/2009/08/03/looking-up-ssis-hresult-comexception-errorcode.aspx
http://blogs.msdn.com/b/mattm/archive/2009/08/03/debugging-a-comexception-during-package-generation.aspx
Complete working sample with source
I've had this exact same issue and been able to resolve it with a lot of experimentation. In short you must set the connection for both the source and destination, and then call the attachTo after both connections are set. You must call attachTo for every component.
I've written a blog about starting with an SSIS package as a template, and then manipulating it programmatically to produce a set of new packages.
The article explains the issue more.

Display a ConnectionString dialog

I'm trying to create a program in C# that should be able to create, backup and restore a SQL Server database.
For this, the user needs to be able to setup a connection string to the desired SQL Server (and database).
I would like to use the same dialog as for example Visual Studio for creating the connection string.
Is this possible?
The data connection dialog component linked to in this answer is no longer available for download.
However, a (apparently somewhat altered) DataConnectionDialog component has since become available on NuGet.
Installation:
Add the component to your Visual Studio project via the NuGet package manager console:
Install-Package DataConnectionDialog
Usage example:
// using Microsoft.Data.ConnectionUI;
// using System.Windows.Forms;
bool TryGetDataConnectionStringFromUser(out string outConnectionString)
{
using (var dialog = new DataConnectionDialog())
{
// If you want the user to select from any of the available data sources, do this:
DataSource.AddStandardDataSources(dialog);
// OR, if you want only certain data sources to be available
// (e.g. only SQL Server), do something like this instead:
dialog.DataSources.Add(DataSource.SqlDataSource);
dialog.DataSources.Add(DataSource.SqlFileDataSource);
…
// The way how you show the dialog is somewhat unorthodox; `dialog.ShowDialog()`
// would throw a `NotSupportedException`. Do it this way instead:
DialogResult userChoice = DataConnectionDialog.Show(dialog);
// Return the resulting connection string if a connection was selected:
if (userChoice == DialogResult.OK)
{
outConnectionString = dialog.ConnectionString;
return true;
}
else
{
outConnectionString = null;
return false;
}
}
}
Note: The dialog component referred to below is no longer available for download. Unless you have retrieved it in the past, you will probably not get this answer's sample code to work.
Alternative: There is now a different DataConnectionDialog available on
NuGet. See this answer for details.
"Data Connection Dialog" on MSDN Archive Gallery (broken as of 1 Sept. 2015)
The data connection dialog is a database tool component released with Visual Studio. It allows users to build connection strings and to connect to specific data sources. try this..
C# Sample:
static void Main(string[] args)
{
DataConnectionDialog dcd = new DataConnectionDialog();
DataConnectionConfiguration dcs = new DataConnectionConfiguration(null);
dcs.LoadConfiguration(dcd);
if (DataConnectionDialog.Show(dcd) == DialogResult.OK)
{
// load tables
using (SqlConnection connection = new SqlConnection(dcd.ConnectionString))
{
connection.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM sys.Tables", connection);
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader.HasRows);
}
}
}
}
dcs.SaveConfiguration(dcd);
}
Here source code also available. we can integrate and redistribute the source code with our application according to license.
Yes and no.
Yes, it is technically possible, but I urge you not to; that dialog is part of Visual Studio and is lot listed in "redist". My interpretation is that you are not free to redistribute this dll.
I think all the other answers here are out-of-date, but I found a current solution at code.msdn.microsoft.com:
Using Microsoft Visual Studio Connection Dialog at runtime
In Visual Studio when a developer wants to create strong typed classes for database tables either for the conventional TableAdapter or Entity Framework there is a place in the process where a dialog is displayed as shown below. I will show you how to do this at runtime and a bit more.
The download is a solution that builds the following dlls:
Microsoft.Data.ConnectionUI.Dialog.dll
Microsoft.Data.ConnectionUI.dll
Microsoft.Data.DataConnectionConfiguration.dll
The solution also contains a sample application showing how to use them.
Worked a treat for me and it is super easy.
You can use UDL file.
Configuring Data Controls to Use Universal Data Link (.udl) Files
You can use SQLConnectionStringUI Nuget package.
I created some code that will do this. The code is in GitHub and you can learn about it here: https://csharpdeveloper.wordpress.com/2020/05/07/a-c-net-dialog-for-connecting-to-sql-server/
Lin
Create your own form similar to Server Explorer Connection Setting window, and implement it. You cannot use that form meant for VS

What is the Fastest way to read event log on remote machine?

I am working on an application which reads eventlogs(Application) from remote machines. I am making use of EventLog class in .net and then iterating on the Log entries but this is very slow. In some cases, some machines have 40000+ log entries and it takes hours to iterate through the entries.
what is the best way to accomplish this task? Are there any other classes in .net which are faster or in any other technology?
Man, I feel your pain. We had the exact same issue in our app.
Your solution has a branch depending on what server version you're running on and what server version your "target" machine is running on.
If you're both on Vista or Windows Server 2008, you're in luck. You should look at System.Diagnostics.Eventing.Reader.EventLogQuery and System.Diagnostics.Eventing.Reader.EventLogReader. These are new in .net 3.5.
Basically, you can build a query in XML and ship it over to run on the remote computer. Maybe you're just searching for events of a specific type, or maybe just new events from a specific point in time. The search runs on the remote machine, and then you just get back the matching events. The new classes are much faster than the old .net 2.0 way, but again, they are only supported on Vista or Windows Server 2008.
For our app when the target is NOT on Vista/Win2008, we downloaded the raw .evt file from the remote system, and then parsed the file using its binary format. There are several sources of data about the event log format for .evt files (pre-Vista), including link text and an article I recall on codeproject.com that had some c# code.
Vista and Windows Server 2008 machines use a new .evtx format that is a new format, so you can't use the same binary parsing approach across all versions. But the new EventLogQuery and EventLogReader classes are so fast that you won't have to. It's now perfectly speedy to just use the built-in classes.
Event Log Reader is horribly slow... too slow. WTF Microsoft?
Use LogParser 2.2 - Search for C# and LogParser on the Internet (or you can use the log parser commands from the command line). I don't want to duplicate the work already contributed by others.
I pull the log from the remote system by having the log exported as an EVTX file. I then copy the file from the remote system. This process is really quick - even with a network that spans the planet (I had issues with having the log exported to a network resource). Once you have it local, you can do your searches and processing.
There are multiple reasons for having the EVTX - I won't get into the reasons why we do this.
The following is a working example of the code to save a copy of the log as an EVTX:
(Notes: "device" is the network host name or IP. "LogName" is the name of the log desired: "System", "Security", or "Application". outputPathOnRemoteSystem is the path on the remote computer, such as "c:\temp\%hostname%.%LogName%.%YYYYMMDD_HH.MM%.evtx".)
static public bool DumpLog(string device, string LogName, string outputPathOnRemoteSystem, out string errMessage)
{
bool wasExported = false;
string errorMessage = "";
try
{
System.Diagnostics.Eventing.Reader.EventLogSession els = new System.Diagnostics.Eventing.Reader.EventLogSession(device);
els.ExportLogAndMessages(LogName, PathType.LogName, "*", outputPathOnRemoteSystem);
wasExported = true;
}
catch (UnauthorizedAccessException e)
{
errorMessage = "Unauthorized - Access Denied: " + e.Message;
}
catch (EventLogNotFoundException e)
{
errorMessage = "Event Log Not Found: " + e.Message;
}
catch (EventLogException e)
{
errorMessage = "Export Failed: " + e.Message + ", Log: " + LogName + ", Device: " + device;
}
errMessage = errorMessage;
return wasExported;
}
A good Explanation/Example can be found on MSDN.
EventLogSession session = new EventLogSession(Environment.MachineName);
// [System/Level=2] filters out the errors
// Where "Log" is the log you want to get data from.
EventLogQuery query = new EventLogQuery("Log", PathType.LogName, "*[System/Level=2]");
EventLogReader reader = new EventLogReader(query);
for (EventRecord eventInstance = reader.ReadEvent();
null != eventInstance;
eventInstance = reader.ReadEvent())
{
// Output or save your event data here.
}
When waiting 5-20 minutes with the old code this one does it in less than 10 seconds.
Maybe WMI can help you:
WMI with C#
Have you tried using the remoting features in powershell 2.0? They allow you to execute cmdlets (like ones to read event logs) on remote machines and return the results (as objects, of course) to the calling session.
You could place a Program at those machines that save the log to file and sends it to your webapplication i think that would be alot faster as you can do the looping local but im not sure how to do it so i cant ive you any code :(
I recently did such thing via WCF callback interface however my clients interacted with the server through WCF and adding a WCF Callback was easy in my project, full code with examples is available here
Just had the same issue and want to share my solution. It makes a search through application, system and security eventlogs from 260 seconds (using EventLog) about a 100 times faster (using EventLogQuery).
And this in a way where it is possible to check if the event message contains a pattern or any other check without the requirement of FormatDescription().
My trick is to use the same mechanism as PowerShells Get-WinEvent does and then pass it through the result check.
Here is my code to find all events within last 4 days where the event message contains a filter pattern.
string[] eventLogSources = {"Application", "System", "Security"};
var messagePattern = "*Your Message Search Pattern*";
var timeStamp = DateTime.Now.AddDays(-4);
var matchingEvents = new List<EventRecord>();
foreach (var eventLogSource in eventLogSources)
{
var i = 0;
var query = string.Format("*[System[TimeCreated[#SystemTime >= '{0}']]]",
timeStamp.ToUniversalTime().ToString("o"));
var elq = new EventLogQuery(eventLogSource, PathType.LogName, query);
var elr = new EventLogReader(elq);
EventRecord entryEventRecord;
while ((entryEventRecord = elr.ReadEvent()) != null)
{
if ((entryEventRecord.Properties)
.FirstOrDefault(x => (x.Value.ToString()).Contains(messagePattern)) != null)
{
matchingEvents.Add(entryEventRecord);
i++;
}
}
}
Maybe that the remote computers could do a little bit of computing. So this way your server would only deal with relevant information. It would be a kind of cluster using the remote computer to do some light filtering and the server would the the analysis part.

Categories

Resources